2edc83e614
Также: версия файла, совпадающего с выпуском, записывается (нет ложного «новее»); признак неудачной проверки отдельно от результатов установки; окно обновления само перезагружает страницу. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
88 lines
3.6 KiB
Go
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)
|
|
}()
|
|
}
|