Экспорт QUIK — отдельная служба bj-quikexport; модули, выделенные из ядра, ставятся с обновлением

bj-quikexport (modules/quikexport + cmd/bj-quikexport, 127.0.0.1:8084): управление ARQA
quikexport перенесено из bj-server. Настройки у службы в /var/lib/bj/.bj/quik-export/settings.json
(при первом запуске переносятся из setup.json), раздел отдаётся фрагментом с индикатором меню,
действия отвечают X-BJ-Flash. bj-server встраивает раздел в «Настройку», проксирует формы
/admin/setup/quikexport/… и передаёт лицензию (X-BJ-Licensed). Общая проверка служебного
ключа — modules/modkit (им пользуется и bj-npr), общее для прокси — lkgateway/modules.go.

Выделенные из ядра модули (bj-npr, bj-quikexport: Component.FromCore) при обновлении ставятся и
там, где их ещё нет, если входят в лицензию: release.MarkSplitModules, request.json "new",
root-установщик ставит и включает unit-файл из комплекта. Если в обновлении меняется сам
установщик, модули ставятся после перезапуска bj-server (ensureSplitModules).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
zuevav
2026-09-16 01:15:27 +03:00
parent 5527a464ca
commit 97e99b72c7
26 changed files with 1095 additions and 303 deletions
+1 -44
View File
@@ -8,8 +8,6 @@ package lkgateway
import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"html/template"
"io"
@@ -48,30 +46,7 @@ func nprAvailable(rc *RuntimeConfig) bool {
// ---- служба модуля ----
const moduleKeyFile = "/var/lib/bj/.bj/module.key"
var (
moduleKeyMu sync.Mutex
nprHTTP = &http.Client{Timeout: 60 * time.Second, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
)
// moduleKey — служебный ключ для служб модулей (создаётся один раз, читается службами от того же пользователя).
func moduleKey() (string, error) {
moduleKeyMu.Lock()
defer moduleKeyMu.Unlock()
if b, err := os.ReadFile(moduleKeyFile); err == nil && len(strings.TrimSpace(string(b))) >= 32 {
return strings.TrimSpace(string(b)), nil
}
buf := make([]byte, 32)
if _, err := rand.Read(buf); err != nil {
return "", err
}
key := hex.EncodeToString(buf)
if err := os.WriteFile(moduleKeyFile, []byte(key+"\n"), 0o600); err != nil {
return "", err
}
return key, nil
}
var nprHTTP = &http.Client{Timeout: 60 * time.Second, CheckRedirect: noRedirect}
func nprURL() string {
if u := strings.TrimSpace(os.Getenv("BJ_NPR_URL")); u != "" {
@@ -80,17 +55,6 @@ func nprURL() string {
return "http://127.0.0.1:8083"
}
// modulePageData — страница модуля в макете bj.
type modulePageData struct {
page
Content template.HTML
}
func moduleMessage(title, text, hint string) template.HTML {
return template.HTML(`<div class="card"><h2>` + template.HTMLEscapeString(title) + `</h2><p>` + template.HTMLEscapeString(text) + `</p>` +
`<p class="muted">` + template.HTMLEscapeString(hint) + `</p></div>`)
}
// registerNPR — прокси раздела /admin/npr к службе bj-npr.
func registerNPR(mux *http.ServeMux, a *admin, rc *RuntimeConfig) {
unavailable := func(w http.ResponseWriter, r *http.Request, status int, title, text, hint string) {
@@ -156,13 +120,6 @@ func registerNPR(mux *http.ServeMux, a *admin, rc *RuntimeConfig) {
mux.HandleFunc("/admin/npr/", proxy)
}
func pickStr(v, def string) string {
if strings.TrimSpace(v) == "" {
return def
}
return v
}
// ---- настройки: проверка подключения ----
var (