Экспорт 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:
@@ -0,0 +1,58 @@
|
||||
package lkgateway
|
||||
|
||||
// Службы модулей (bj-npr, bj-quikexport, …) — отдельные программы на локальных портах, которые
|
||||
// обновляются независимо от ядра. bj-server проверяет вход, права и лицензию, передаёт службе
|
||||
// служебный ключ (X-BJ-Module-Key) и встраивает её страницы в свой макет. Сами службы — modules/.
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const moduleKeyFile = "/var/lib/bj/.bj/module.key"
|
||||
|
||||
var moduleKeyMu sync.Mutex
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// noRedirect — ответы служб (в т. ч. редиректы) передаются браузеру как есть.
|
||||
func noRedirect(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }
|
||||
|
||||
// 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>`)
|
||||
}
|
||||
|
||||
func pickStr(v, def string) string {
|
||||
if strings.TrimSpace(v) == "" {
|
||||
return def
|
||||
}
|
||||
return v
|
||||
}
|
||||
Reference in New Issue
Block a user