Files
Bridge-and-Join-s/internal/lkgateway/moduleslicense.go
T
zuevav 2edc83e614 Модуль, снятый с лицензии, отключается один раз: служба остановлена (bj-keymedia unit-disable), одно оповещение, в списках не показывается; вернули в лицензию — служба включается
Также: версия файла, совпадающего с выпуском, записывается (нет ложного «новее»); признак неудачной проверки отдельно от результатов установки; окно обновления само перезагружает страницу.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
2026-09-24 22:43:34 +03:00

88 lines
3.6 KiB
Go

package lkgateway
// Модули, снятые с лицензии: служба модуля останавливается и отключается один раз, с одним
// оповещением; дальше модуль не показывается и не предлагается к обновлению. Вернули в лицензию —
// служба включается обратно. Работает только при действующей лицензии: истёкший или непроверенный
// ключ модули не трогает (временная ошибка не должна гасить работающие службы).
import (
"context"
"log"
"os"
"sync"
"time"
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/release"
)
var moduleEnforceMu sync.Mutex
// moduleOff — модуль отключён как снятый с лицензии (по записи в настройках).
func moduleOff(rc *RuntimeConfig, name string) bool {
_, ok := rc.Snapshot().Update.DisabledModules[name]
return ok
}
func enforceModuleLicense(ctx context.Context, rc *RuntimeConfig) {
moduleEnforceMu.Lock()
defer moduleEnforceMu.Unlock()
if _, err := os.Stat(keymediaReqDir); err != nil {
return // нет root-службы (разработка, тесты)
}
st := licenseStatus(rc)
if !st.Valid {
return
}
cfg := rc.Snapshot().Update
changed := false
for _, c := range release.Components {
if c.Core || c.Feature == "" || c.Feature == "updates" || c.Unit == "" {
continue
}
if _, err := os.Stat(c.Path); err != nil {
continue // модуль не установлен
}
allowed := moduleAllowed(rc, c.Feature)
_, off := cfg.DisabledModules[c.Name]
switch {
case !allowed && !off:
if _, err := runKeymediaOp(ctx, "unit-disable", map[string]string{"extra": c.Unit}); err != nil {
log.Printf("modules: отключение %s: %v", c.Unit, err)
continue
}
if cfg.DisabledModules == nil {
cfg.DisabledModules = map[string]string{}
}
cfg.DisabledModules[c.Name] = time.Now().Format("02.01.2006 15:04")
changed = true
log.Printf("modules: %s снят с лицензии — служба %s остановлена и отключена", c.Name, c.Unit)
raiseSystemAlert(rc, "Модуль «"+c.Title+"» отключён: не входит в лицензию",
"Служба "+c.Unit+" остановлена, раздел скрыт, обновления для модуля не выдаются. Чтобы подключить модуль, свяжитесь с ZETIT — после добавления в лицензию он включится сам.")
case allowed && off:
if _, err := runKeymediaOp(ctx, "unit-enable", map[string]string{"extra": c.Unit}); err != nil {
log.Printf("modules: включение %s: %v", c.Unit, err)
continue
}
delete(cfg.DisabledModules, c.Name)
changed = true
log.Printf("modules: %s снова в лицензии — служба %s включена", c.Name, c.Unit)
raiseSystemAlert(rc, "Модуль «"+c.Title+"» снова включён", "Модуль добавлен в лицензию, служба "+c.Unit+" запущена.")
}
}
if changed {
cur := rc.Snapshot().Update
cur.DisabledModules = cfg.DisabledModules
if err := rc.SaveUpdateSettings(cur); err != nil {
log.Printf("modules: сохранение: %v", err)
}
}
}
func enforceModuleLicenseAsync(rc *RuntimeConfig) {
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
enforceModuleLicense(ctx, rc)
}()
}