Кабинет: страницы собирает ядро, на хостинге — ретранслятор (Go и PHP)
- modules/lk: конверт запроса/ответа (PageRequest/PageResponse), ServeEnvelope — тот же обработчик страниц внутри ядра; клиент к API внутри процесса (Config.Local/LocalKey); режим ретранслятора (Config.Relay, BJ_RENDER=core, выбор в установщике и lk.json) - ядро: встроенный кабинет (lkcabinet.go), POST /api/lk/render для прямого режима, цикл режима ожидания выполняет конверты страниц; API через ретранслятор недостижимо - PHP-ретранслятор для обычного хостинга (modules/lk/relay-php: index.php, .htaccess, README): установщик в браузере, прямой режим через curl, режим ожидания через очередь в SQLite (BEGIN IMMEDIATE, busy_timeout), конфиг в bj-lk-data рядом с сайтом или в data под .htaccess; архив со страницы настроек (/admin/setup/lk/relay-php.zip) - настройки: карточка НПР/УДС перенесена из раздела «Лицензия» в «Экспорт QUIK»; кнопка «Обновить с сервера лицензий» видна при любом ключе - инструкция /admin/help/lk: два варианта размещения, шаги для PHP-хостинга - тесты: TestLKRelayRendersInCore (оба режима), TestLKPHPRelayAgentMode (настоящий PHP против цикла ядра, PHP_BIN), проверка безопасности через PHP-ретранслятор 34/34 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package lkgateway
|
||||
|
||||
// lkcabinet.go — кабинет клиента, собранный внутрь ядра.
|
||||
//
|
||||
// Страницы кабинета рисует ядро: у него все данные и шаблоны (пакет modules/lk — тот же,
|
||||
// что собирается в самостоятельный bj-lk). На хостинге остаётся ретранслятор, который
|
||||
// передаёт запросы браузера конвертами: в прямом режиме — POST /api/lk/render, в режиме
|
||||
// ожидания — ядро само забирает конверты из очереди ретранслятора (lkagent.go).
|
||||
//
|
||||
// Данные встроенный кабинет берёт через тот же API /api/lk/*, вызывая обработчик внутри
|
||||
// процесса: граница проверок одна и та же, где бы кабинет ни работал.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.zetit.ru/zuevav/Bridge-and-Join-s/modules/lk"
|
||||
)
|
||||
|
||||
// globalLKCabinet — встроенный кабинет; им пользуется и цикл режима ожидания.
|
||||
var globalLKCabinet *lkCabinet
|
||||
|
||||
// lkCabinet — встроенный кабинет; пересобирается, если сменился заголовок.
|
||||
type lkCabinet struct {
|
||||
mu sync.Mutex
|
||||
api http.Handler
|
||||
rc *RuntimeConfig
|
||||
srv *lk.Server
|
||||
title string
|
||||
}
|
||||
|
||||
func newLKCabinet(api http.Handler, rc *RuntimeConfig) *lkCabinet {
|
||||
return &lkCabinet{api: api, rc: rc}
|
||||
}
|
||||
|
||||
// server — кабинет с актуальным заголовком организации.
|
||||
func (c *lkCabinet) server() (*lk.Server, error) {
|
||||
s := c.rc.Snapshot()
|
||||
title := strings.TrimSpace(orgName(s))
|
||||
if title == "" {
|
||||
title = "Личный кабинет"
|
||||
} else {
|
||||
title += " · личный кабинет"
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.srv != nil && c.title == title {
|
||||
return c.srv, nil
|
||||
}
|
||||
srv, err := lk.New(lk.Config{Title: title, Local: c.api, LocalKey: func() string { return c.rc.Snapshot().LK.APIKey }})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.srv, c.title = srv, title
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
// serve — выполнить конверт страницы.
|
||||
func (c *lkCabinet) serve(r *http.Request, env lk.PageRequest) lk.PageResponse {
|
||||
srv, err := c.server()
|
||||
if err != nil {
|
||||
log.Printf("кабинет: не собран: %v", err)
|
||||
return lk.PageResponse{ID: env.ID, Status: http.StatusInternalServerError, Body: []byte("кабинет не собран")}
|
||||
}
|
||||
return srv.ServeEnvelope(r.Context(), env)
|
||||
}
|
||||
|
||||
// registerRender — POST /api/lk/render: ретранслятор в прямом режиме присылает конверт
|
||||
// запроса браузера, получает конверт ответа. Только по ключу модуля.
|
||||
func (c *lkCabinet) registerRender(mux *http.ServeMux, auth func(http.ResponseWriter, *http.Request) bool) {
|
||||
mux.HandleFunc("/api/lk/render", func(w http.ResponseWriter, r *http.Request) {
|
||||
if !auth(w, r) {
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
lkJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "нужен POST"})
|
||||
return
|
||||
}
|
||||
var env lk.PageRequest
|
||||
if err := json.NewDecoder(io.LimitReader(r.Body, 2<<20)).Decode(&env); err != nil {
|
||||
lkJSON(w, http.StatusBadRequest, map[string]string{"error": "конверт не разобран"})
|
||||
return
|
||||
}
|
||||
if env.Kind != "page" {
|
||||
lkJSON(w, http.StatusBadRequest, map[string]string{"error": "через render идут только страницы"})
|
||||
return
|
||||
}
|
||||
lkJSON(w, http.StatusOK, c.serve(r, env))
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user