054222d154
- 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
95 lines
3.6 KiB
Go
95 lines
3.6 KiB
Go
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))
|
|
})
|
|
}
|