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) }() }