package lkgateway // handbook_import.go — ручная загрузка справочника участников M2M со страницы // /admin/handbook файлом в ПОДЛИННОМ формате НРД (hk:M2MTransferHandbook, // windows-1251 — тот же, что НРД присылает пакетом #M2MTH и который отдаёт // кнопка «XML»). Нужна для закрытого контура и когда шлюз к НРД недоступен. // // Обрабатываем ровно тем же путём, что и поллер при ответе НРД (nsdpoller.go): // writeHandbookRawXML → saveHandbookEx(push=false) → перезапись FTV_M2M_HANDBOOK // в DEPO → синхронизация получателей в МНП. // На сервер лицензий файл НЕ рассылаем: ручная загрузка одного стенда не должна // становиться облачным справочником для всех клиентов (push=false). Отметку живой // связи с НРД тоже не ставим — это действие человека, а не ответ шлюза. import ( "fmt" "io" "log" "net/http" "net/url" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2m" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdxml" ) // handbookUploadMaxBytes — предел размера загружаемого файла. Справочник НРД — // сотни КБ; с запасом. const handbookUploadMaxBytes = 16 << 20 // importHandbook — POST /admin/handbook/import: принять файл справочника в формате НРД. func (a *admin) importHandbook(w http.ResponseWriter, r *http.Request) { back := func(msg string) { http.Redirect(w, r, "/admin/handbook?flash="+url.QueryEscape(msg), http.StatusSeeOther) } if r.Method != http.MethodPost { http.Error(w, "method", http.StatusMethodNotAllowed) return } r.Body = http.MaxBytesReader(w, r.Body, handbookUploadMaxBytes) f, hdr, err := r.FormFile("handbook") if err != nil { back("Загрузка справочника: файл не получен (" + err.Error() + ")") return } defer f.Close() raw, err := io.ReadAll(f) if err != nil { back("Загрузка справочника: не удалось прочитать файл: " + err.Error()) return } if len(raw) == 0 { back("Загрузка справочника: файл пустой") return } // Разбираем тем же парсером НРД, что и ответ шлюза (поддерживает windows-1251 по прологу). var hb m2m.M2MTransferHandbook if err := nsdxml.Unmarshal(raw, &hb); err != nil { back("Загрузка справочника: это не справочник НРД (hk:M2MTransferHandbook) или файл повреждён: " + err.Error()) return } nP, nPl := len(hb.Participants.Participants), len(hb.SettlementPlaces.Places) if nP == 0 { back("Загрузка справочника: в файле нет ни одного участника — проверьте, тот ли это файл") return } writeHandbookRawXML(raw) // подлинный XML — для выгрузки кнопкой «XML» байт в байт changed := saveHandbookEx(&hb, false) // плоский JSON; на сервер лицензий НЕ рассылаем if globalRC != nil { go func(rc *RuntimeConfig) { if err := depoWriteHandbook(rc); err != nil { log.Printf("depo-events: справочник после ручной загрузки: %v", err) } }(globalRC) quikRecipientsSyncAsync(globalRC) // депозитарии-получатели в МНП } note := "" if !changed { note = " (состав не изменился)" } log.Printf("lk-gateway: справочник M2M загружен ВРУЧНУЮ из файла %q: участников %d, мест расчётов %d, изменился=%v", hdr.Filename, nP, nPl, changed) back(fmt.Sprintf("Справочник загружен из файла %s: участников %d, мест расчётов %d%s.", hdr.Filename, nP, nPl, note)) }