package lkgateway // Модуль «Экспорт биржевой информации» (ARQA quikexport) работает отдельной службой bj-quikexport // (modules/quikexport, обновляется независимо). Раздел остаётся на странице «Настройка»: bj-server // получает от службы готовый HTML раздела и цвет индикатора меню, а формы раздела // (/admin/setup/quikexport/…) проксирует службе и превращает её ответ X-BJ-Flash в обычное // сообщение страницы настроек. Лицензию проверяет bj-server и передаёт в X-BJ-Licensed. import ( "bytes" "context" "fmt" "html/template" "io" "net/http" "net/url" "os" "strings" "time" ) // quikExportFeature — лицензионный признак модуля. const quikExportFeature = "quik-export" // Применение настроек ждёт root-воркер до 3 минут. var quikExportHTTP = &http.Client{Timeout: 4 * time.Minute, CheckRedirect: noRedirect} func quikExportURL() string { if u := strings.TrimSpace(os.Getenv("BJ_QUIKEXPORT_URL")); u != "" { return strings.TrimRight(u, "/") } return "http://127.0.0.1:8084" } // QuikExportView — раздел «Экспорт QUIK» на странице настроек. type QuikExportView struct { HTML template.HTML Ind string // индикатор в меню: ok | warn | err | пусто } func quikExportDo(ctx context.Context, rc *RuntimeConfig, method, uri string, body io.Reader, contentType string) (*http.Response, error) { key, err := moduleKey() if err != nil { return nil, fmt.Errorf("служебный ключ модулей: %w", err) } req, err := http.NewRequestWithContext(ctx, method, quikExportURL()+uri, body) if err != nil { return nil, err } if contentType != "" { req.Header.Set("Content-Type", contentType) } req.Header.Set("X-BJ-Module-Key", key) lic := "0" if moduleAllowed(rc, quikExportFeature) { lic = "1" } req.Header.Set("X-BJ-Licensed", lic) return quikExportHTTP.Do(req) } func quikExportView(rc *RuntimeConfig, showRO bool) QuikExportView { uri := "/section" if showRO { uri += "?reveal_ro=1" } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() resp, err := quikExportDo(ctx, rc, http.MethodGet, uri, nil, "") if err == nil { b, rerr := io.ReadAll(io.LimitReader(resp.Body, 4<<20)) resp.Body.Close() switch { case rerr != nil: err = rerr case resp.StatusCode != http.StatusOK: err = fmt.Errorf("служба ответила %d: %s", resp.StatusCode, strings.TrimSpace(string(b))) default: return QuikExportView{HTML: template.HTML(b), Ind: resp.Header.Get("X-BJ-Indicator")} } } return QuikExportView{Ind: "err", HTML: template.HTML(`