package lkgateway // nsd_reply_capture.go — «отлов» ответов НРД, которые bj пока не разбирает // (фаза 1). После отправки анкеты участника (#M2MPF) и других новых документов // НРД присылает ответ; его тип/схему фиксируем на боевом контуре: сохраняем // подлинный XML в файл и явно логируем, чтобы потом встроить разбор в систему // для всех клиентов. import ( "fmt" "log" "os" "path/filepath" "regexp" "sort" "time" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdadapter/igw" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdxml" ) const nsdRepliesDir = "/var/lib/bj/.bj/nsd-replies" var nsdReplyTypeRe = regexp.MustCompile(`[^A-Za-z0-9_.-]+`) var nsdReplyRootRe = regexp.MustCompile(`<(?:[A-Za-z0-9_]+:)?([A-Za-z0-9_]+)[\s>]`) // captureNSDReply сохраняет подлинный XML входящего пакета НРД, который bj пока не // разбирает, и возвращает путь к файлу и имя корневого элемента. Храним последние // 100 файлов, чтобы каталог не рос без предела. func captureNSDReply(p igw.Package, docXML []byte, tag string) (path, root string) { root = nsdReplyRoot(docXML) if err := os.MkdirAll(nsdRepliesDir, 0o750); err != nil { log.Printf("lk-gateway: nsd-replies: mkdir: %v", err) return "", root } name := fmt.Sprintf("%s-%s-id%d-%s.xml", time.Now().Format("20060102-150405"), tag, p.ID, nsdReplySanitize(p.Type)) path = filepath.Join(nsdRepliesDir, name) if err := os.WriteFile(path, docXML, 0o640); err != nil { log.Printf("lk-gateway: nsd-replies: запись %s: %v", name, err) return "", root } nsdRepliesTrim(100) return path, root } // nsdReplyRoot — имя корневого элемента XML (без префикса), для лога. func nsdReplyRoot(docXML []byte) string { utf := string(nsdxml.DecodeWindows1251(docXML)) if m := nsdReplyRootRe.FindStringSubmatch(utf); m != nil { return m[1] } return "?" } func nsdReplySanitize(t string) string { t = nsdReplyTypeRe.ReplaceAllString(t, "_") if t == "" { return "notype" } return t } // nsdRepliesTrim оставляет keep самых свежих файлов (имена начинаются с метки времени). func nsdRepliesTrim(keep int) { ents, err := os.ReadDir(nsdRepliesDir) if err != nil { return } var names []string for _, e := range ents { if !e.IsDir() { names = append(names, e.Name()) } } if len(names) <= keep { return } sort.Strings(names) // по возрастанию метки времени — старые первыми for _, n := range names[:len(names)-keep] { _ = os.Remove(filepath.Join(nsdRepliesDir, n)) } }