Модуль, снятый с лицензии, отключается один раз: служба остановлена (bj-keymedia unit-disable), одно оповещение, в списках не показывается; вернули в лицензию — служба включается
Также: версия файла, совпадающего с выпуском, записывается (нет ложного «новее»); признак неудачной проверки отдельно от результатов установки; окно обновления само перезагружает страницу. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
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)
|
||||
}()
|
||||
}
|
||||
Reference in New Issue
Block a user