From 1c2ba3285ae2b1aaec52125d1cae620622034286 Mon Sep 17 00:00:00 2001 From: zuevav Date: Fri, 18 Sep 2026 14:21:05 +0300 Subject: [PATCH] =?UTF-8?q?=D0=96=D1=83=D1=80=D0=BD=D0=B0=D0=BB:=20=D0=BA?= =?UTF-8?q?=D1=8D=D1=88=20=D1=80=D0=B0=D0=B7=D0=B1=D0=BE=D1=80=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=BE=D0=B2=20=D0=98=D0=A8=20?= =?UTF-8?q?=D0=B8=20=D1=87=D0=B5=D1=80=D0=BD=D0=BE=D0=B2=D0=B8=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=20MF010=20=D0=BF=D0=BE=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=E2=80=94=20=D0=BE=D0=B1=D1=85=D0=BE=D0=B4=20=D0=BA?= =?UTF-8?q?=D0=B0=D1=82=D0=B0=D0=BB=D0=BE=D0=B3=D0=B0=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D1=87=D0=B8=D1=82=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL --- internal/lkgateway/incoming_order.go | 39 +++++++++++++++++++++++++++- internal/lkgateway/outgoing_order.go | 39 +++++++++++++++++++++++++--- 2 files changed, 74 insertions(+), 4 deletions(-) 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 }