Версии систем: общий список в «Обзоре» и строка в разделе каждого модуля
bj собирает версии своих компонентов и внешних систем (в фоне, кэш 10 минут, прогрев при старте): ядро и модули bj (components.json или «-version»), экспортёр ARQA (служба bj-quikexport, /version), криптосервис (Health), «Валидата CSP» (zpki1utl), Java, ИШ НРД (deps.json + сайт НРД), МНП QUIK (VersionInfo), DEPO (OD_DATA_VERSION), PostgreSQL, ОС. «Настройка → Обзор» — таблица «Версии систем» с кнопкой «Обновить сведения»; в разделах БД, Fancy, QUIK МНП, Экспорт QUIK, Криптография, НРД, ЛК, НПР и Обновления — строка с версией. В таблице обновлений у компонентов, выложенных вручную, вместо «неизвестна» — версия самого компонента. bj-component-install: -version. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package quikexport
|
||||
|
||||
// Версия экспортёра ARQA: строка вида 12.1.5.2 внутри программы export. Кандидат сверяется с версией
|
||||
// установщика из .actions.log (install_quikexport-12.1.5.run), чтобы не принять чужую версию библиотеки.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
exporterVerRe = regexp.MustCompile(`^\d{1,3}\.\d+\.\d+\.\d+$`)
|
||||
exporterInstallerRe = regexp.MustCompile(`install_quikexport-(\d+\.\d+\.\d+)\.run`)
|
||||
)
|
||||
|
||||
var exporterVerCache struct {
|
||||
sync.Mutex
|
||||
path string
|
||||
mod time.Time
|
||||
ver string
|
||||
}
|
||||
|
||||
// exporterVersion — версия ARQA quikexport в каталоге dir ("" — не определена).
|
||||
func exporterVersion(dir string) string {
|
||||
bin := filepath.Join(dir, "export")
|
||||
fi, err := os.Stat(bin)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
exporterVerCache.Lock()
|
||||
defer exporterVerCache.Unlock()
|
||||
if exporterVerCache.path == bin && exporterVerCache.mod.Equal(fi.ModTime()) {
|
||||
return exporterVerCache.ver
|
||||
}
|
||||
installer := ""
|
||||
if log, err := os.ReadFile(filepath.Join(dir, ".actions.log")); err == nil {
|
||||
if m := exporterInstallerRe.FindAllSubmatch(log, -1); len(m) > 0 {
|
||||
installer = string(m[len(m)-1][1])
|
||||
}
|
||||
}
|
||||
ver := ""
|
||||
if b, err := os.ReadFile(bin); err == nil {
|
||||
for _, tok := range bytes.Split(b, []byte{0}) {
|
||||
if len(tok) > 20 || !exporterVerRe.Match(tok) {
|
||||
continue
|
||||
}
|
||||
if installer == "" || bytes.HasPrefix(tok, []byte(installer+".")) {
|
||||
ver = string(tok)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if ver == "" {
|
||||
ver = installer
|
||||
}
|
||||
exporterVerCache.path, exporterVerCache.mod, exporterVerCache.ver = bin, fi.ModTime(), ver
|
||||
return ver
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package quikexport
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExporterVersion(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
// В программе встречаются и чужие версии библиотек — берётся та, что совпадает с установщиком.
|
||||
bin := []byte("\x00ELF\x008.0.4.2\x00codecvt\x0012.1.5.2\x000123456789\x00")
|
||||
if err := os.WriteFile(filepath.Join(dir, "export"), bin, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, ".actions.log"), []byte("[14/09/26][./install_quikexport-12.1.5.run][root] Done\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v := exporterVersion(dir); v != "12.1.5.2" {
|
||||
t.Fatalf("версия экспортёра = %q", v)
|
||||
}
|
||||
if v := exporterVersion(t.TempDir()); v != "" {
|
||||
t.Fatalf("без экспортёра версия должна быть пустой, получено %q", v)
|
||||
}
|
||||
}
|
||||
@@ -856,6 +856,9 @@ type QuikExportView struct {
|
||||
ShowRO bool
|
||||
ServerIP string
|
||||
Warnings []string
|
||||
|
||||
ModuleVersion string // bj-quikexport
|
||||
ExporterVersion string // ARQA quikexport (\"\" — не определена)
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -7,7 +7,8 @@ package quikexport
|
||||
// в заголовке X-BJ-Indicator — цвет индикатора меню (ok | warn | err | пусто);
|
||||
// - POST /admin/setup/quikexport[/keys|apply|import|service|dbinit] — действие; итог — 204
|
||||
// с сообщением в X-BJ-Flash, bj-server показывает его как обычное сообщение страницы настроек;
|
||||
// - GET /admin/setup/quikexport/sql и /preview — файлы как есть.
|
||||
// - GET /admin/setup/quikexport/sql и /preview — файлы как есть;
|
||||
// - GET /version — версии модуля и экспортёра ARQA (JSON) для общего списка версий bj.
|
||||
//
|
||||
// Лицензию проверяет bj-server и передаёт в X-BJ-Licensed: 1.
|
||||
|
||||
@@ -38,6 +39,7 @@ type Config struct {
|
||||
StorePath string // собственные настройки модуля
|
||||
SetupPath string // setup.json bj: отсюда настройки переносятся при первом запуске (раздел quik_export)
|
||||
KeyPath string // служебный ключ модулей
|
||||
Version string // версия модуля bj-quikexport
|
||||
}
|
||||
|
||||
// Server — служба модуля.
|
||||
@@ -77,6 +79,7 @@ func (srv *Server) Handler() http.Handler {
|
||||
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("ok")) })
|
||||
mux.HandleFunc("/section", func(w http.ResponseWriter, r *http.Request) {
|
||||
v := quikExportView(srv.store, licensed(r), r.URL.Query().Get("reveal_ro") == "1")
|
||||
v.ModuleVersion, v.ExporterVersion = srv.cfg.Version, exporterVersion(v.S.Dir)
|
||||
var buf bytes.Buffer
|
||||
if err := srv.section.ExecuteTemplate(&buf, "section", v); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@@ -87,6 +90,10 @@ func (srv *Server) Handler() http.Handler {
|
||||
w.Header().Set("X-BJ-Indicator", indicator(v))
|
||||
_, _ = w.Write(buf.Bytes())
|
||||
})
|
||||
mux.HandleFunc("/version", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(map[string]string{"module": srv.cfg.Version, "exporter": exporterVersion(srv.store.Get().Dir)})
|
||||
})
|
||||
mux.HandleFunc("/admin/setup/quikexport", srv.saveQuikExport)
|
||||
mux.HandleFunc("/admin/setup/quikexport/keys", srv.uploadQuikExportKeys)
|
||||
mux.HandleFunc("/admin/setup/quikexport/apply", srv.applyQuikExport)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
{{$X := .}}{{$S := $X.S}}
|
||||
<h1>QUIK — Экспорт биржевой информации</h1>
|
||||
<p class="muted">Модуль ARQA «Экспорт биржевой информации» выгружает данные сервера QUIK (портфели клиентов, позиции, сделки, справочники) в базу PostgreSQL. bj управляет им отсюда: ключи и логин QUIK, где держим базу, какой объём данных выгружаем, состояние службы и место на диске. На этих данных работают модуль «НПР / УДС» и дополнительные проверки M2M. Лицензионный признак <code>quik-export</code>.</p>
|
||||
<p class="muted" style="font-size:12.5px;margin:-6px 0 12px">Экспортёр QUIK (ARQA quikexport): {{if $X.ExporterVersion}}<strong>{{$X.ExporterVersion}}</strong>{{else}}не определена{{end}} · модуль bj-quikexport{{with $X.ModuleVersion}} <strong>{{.}}</strong>{{end}}</p>
|
||||
{{range $X.Warnings}}<div class="card" style="padding:8px 14px;margin-bottom:8px;background:color-mix(in srgb,var(--warn) 10%,var(--card));display:flex;gap:8px;align-items:center"><span class="dot warn"></span>{{.}}</div>{{end}}
|
||||
|
||||
<div class="card">
|
||||
|
||||
Reference in New Issue
Block a user