From eea2a639682f6ea23b671c3c416a2b4d9f26fb6d Mon Sep 17 00:00:00 2001 From: zuevav Date: Fri, 25 Sep 2026 00:14:30 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9B=D0=B8=D1=86=D0=B5=D0=BD=D0=B7=D0=B8?= =?UTF-8?q?=D1=8F:=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=B0=20=C2=AB=D1=81=D0=B5=D1=80=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=20=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87=D1=91=D0=BD=20?= =?UTF-8?q?=D0=BE=D1=82=20=D0=BB=D0=B8=D1=86=D0=B5=D0=BD=D0=B7=D0=B8=D0=B8?= =?UTF-8?q?=C2=BB=20/=20=C2=AB=D0=BB=D0=B8=D1=86=D0=B5=D0=BD=D0=B7=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BE=D1=82=D0=BE=D0=B7=D0=B2=D0=B0=D0=BD=D0=B0=C2=BB?= =?UTF-8?q?=20=E2=80=94=20=D0=BA=D0=BB=D1=8E=D1=87=20=D1=83=D0=B4=D0=B0?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D1=81=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=D1=83,=20=D0=BE=D0=BF=D0=BE=D0=B2=D0=B5=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi --- internal/lkgateway/licenseclient.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/internal/lkgateway/licenseclient.go b/internal/lkgateway/licenseclient.go index dee3424..90567eb 100644 --- a/internal/lkgateway/licenseclient.go +++ b/internal/lkgateway/licenseclient.go @@ -106,6 +106,25 @@ func licenseCall(ctx context.Context, path string, body map[string]string) (*lic return &r, nil } +// licenseDeactivate — сервер отключён от лицензии в портале клиента (или лицензия отозвана): ключ +// удаляется сразу, не дожидаясь его срока, — модули и обновления отключаются. Вернуть: ввести ключ +// продукта заново (если в лицензии есть свободное место). +func licenseDeactivate(rc *RuntimeConfig, reason string) { + s := rc.Snapshot().License + if s.Key == "" { + return + } + s.Key = "" + s.LastAttempt, s.LastOK, s.LastMsg = time.Now(), false, "лицензия отключена: "+reason + if err := rc.SaveLicense(s); err != nil { + log.Printf("lk-gateway: отключение лицензии: %v", err) + return + } + log.Printf("lk-gateway: лицензия на этом сервере отключена: %s", reason) + raiseSystemAlert(rc, "Лицензия на этом сервере отключена", + "Причина: "+reason+". Модули по лицензии и обновления отключены. Если это ошибка — введите ключ продукта заново в «Настройка → Лицензия» (нужно свободное место в лицензии) или обратитесь в ZETIT.") +} + // licenseRecord — итог обращения к серверу лицензий (для карточки); token != "" — новый ключ. func licenseRecord(rc *RuntimeConfig, token, msg string, ok bool) error { s := rc.Snapshot().License @@ -161,6 +180,10 @@ func LicenseRenew(ctx context.Context, rc *RuntimeConfig) error { if err != nil { _ = licenseRecord(rc, "", "продление не удалось: "+err.Error(), false) var ae *licenseAPIError + if errors.As(err, &ae) && (ae.Code == "install_released" || ae.Code == "revoked") { + licenseDeactivate(rc, ae.Message) + return err + } if errors.As(err, &ae) && time.Since(licenseAlertAt) > 12*time.Hour { licenseAlertAt = time.Now() raiseSystemAlert(rc, "Лицензия: сервер лицензий отказал в продлении",