diff --git a/internal/lkgateway/incoming_order.go b/internal/lkgateway/incoming_order.go index 0eaa776..9022b2e 100644 --- a/internal/lkgateway/incoming_order.go +++ b/internal/lkgateway/incoming_order.go @@ -20,6 +20,7 @@ import ( "regexp" "sort" "strings" + "sync" "time" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdadapter/igw" @@ -310,10 +311,46 @@ func collectOrderResponseRaw(contrDID string) []respFile { // readPkgText собирает текст всех документов пакета: распакованные xml/htm/rpt и // содержимое вложенных zip (декодирует windows-1251). Возвращает текст и время. +// pkgTextCache — разобранный текст пакетов ИШ по каталогу: пакет после получения не меняется, +// поэтому перечитывать его файлы при каждом обходе журнала незачем. Ключ проверки — время +// изменения каталога пакета и число файлов в нём. +var pkgTextCache = struct { + mu sync.Mutex + m map[string]pkgTextEntry +}{m: map[string]pkgTextEntry{}} + +type pkgTextEntry struct { + dirMod time.Time + n int + body string + mt time.Time +} + func readPkgText(dir string) (string, time.Time) { + var dirMod time.Time + if st, err := os.Stat(dir); err == nil { + dirMod = st.ModTime() + } + files, _ := os.ReadDir(dir) + pkgTextCache.mu.Lock() + if e, ok := pkgTextCache.m[dir]; ok && e.dirMod.Equal(dirMod) && e.n == len(files) { + pkgTextCache.mu.Unlock() + return e.body, e.mt + } + pkgTextCache.mu.Unlock() + body, mt := readPkgTextUncached(dir, files) + pkgTextCache.mu.Lock() + if len(pkgTextCache.m) > 20000 { // защита от бесконечного роста при чистке каталога + pkgTextCache.m = map[string]pkgTextEntry{} + } + pkgTextCache.m[dir] = pkgTextEntry{dirMod: dirMod, n: len(files), body: body, mt: mt} + pkgTextCache.mu.Unlock() + return body, mt +} + +func readPkgTextUncached(dir string, files []os.DirEntry) (string, time.Time) { var sb strings.Builder var mt time.Time - files, _ := os.ReadDir(dir) for _, f := range files { if f.IsDir() { continue diff --git a/internal/lkgateway/outgoing_order.go b/internal/lkgateway/outgoing_order.go index 9405810..37304d2 100644 --- a/internal/lkgateway/outgoing_order.go +++ b/internal/lkgateway/outgoing_order.go @@ -153,6 +153,40 @@ type OutgoingDeal struct { // scanForm16Drafts живьём читает INBOX и собирает исходящие сделки: все черновики // с 16, сгруппированные по based_on (GUID). Объединяет с // состоянием подачи из стора. store может быть nil (тогда без состояния подачи). +// mf010Cache — текст черновиков MF010 по пути и времени изменения: файл после получения не +// меняется, а обход журнала читал их все при каждом показе. +var mf010Cache = struct { + mu sync.Mutex + m map[string]mf010Entry +}{m: map[string]mf010Entry{}} + +type mf010Entry struct { + mod time.Time + size int64 + body string +} + +func mf010Text(p string, info os.FileInfo) (string, bool) { + mf010Cache.mu.Lock() + if e, ok := mf010Cache.m[p]; ok && e.mod.Equal(info.ModTime()) && e.size == info.Size() { + mf010Cache.mu.Unlock() + return e.body, true + } + mf010Cache.mu.Unlock() + b, err := os.ReadFile(p) + if err != nil { + return "", false + } + body := string(decodeCP1251(b)) + mf010Cache.mu.Lock() + if len(mf010Cache.m) > 20000 { + mf010Cache.m = map[string]mf010Entry{} + } + mf010Cache.m[p] = mf010Entry{mod: info.ModTime(), size: info.Size(), body: body} + mf010Cache.mu.Unlock() + return body, true +} + func scanForm16Drafts(store *OutgoingStore) []*OutgoingDeal { byGUID := map[string]*OutgoingDeal{} _ = filepath.Walk(igwInboxDir, func(p string, info os.FileInfo, err error) error { @@ -162,11 +196,10 @@ func scanForm16Drafts(store *OutgoingStore) []*OutgoingDeal { if !strings.HasSuffix(strings.ToUpper(p), "_MF010.XML") { return nil } - b, e := os.ReadFile(p) - if e != nil { + body, ok := mf010Text(p, info) + if !ok { return nil } - body := string(decodeCP1251(b)) if of16(body, "order_t_id") != "16" { // только списание (16), не 16/1 return nil }