From b65ec83c397d366157631f257b2c93a543cf9d63 Mon Sep 17 00:00:00 2001 From: konstpic <156318483+konstpic@users.noreply.github.com> Date: Mon, 29 Sep 2025 19:16:46 +0300 Subject: [PATCH] fix: fix delete method (#3569) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Пичугин Константин --- web/job/ldap_sync_job.go | 60 +++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/web/job/ldap_sync_job.go b/web/job/ldap_sync_job.go index 326123a6..cb954932 100644 --- a/web/job/ldap_sync_job.go +++ b/web/job/ldap_sync_job.go @@ -214,7 +214,7 @@ func (j *LdapSyncJob) batchSetEnable(ib *model.Inbound, emails []string, enable return } - // Подготовка JSON для массового обновления + // Prepare JSON for mass update clients := make([]model.Client, 0, len(emails)) for _, email := range emails { clients = append(clients, model.Client{ @@ -238,7 +238,7 @@ func (j *LdapSyncJob) batchSetEnable(ib *model.Inbound, emails []string, enable j.xrayService.SetToNeedRestart() } -// deleteClientsNotInLDAP performs batch deletion of clients not in LDAP +// deleteClientsNotInLDAP deletes clients not in LDAP using batches and a single restart func (j *LdapSyncJob) deleteClientsNotInLDAP(inboundTag string, ldapEmails map[string]struct{}) { inbounds, err := j.inboundService.GetAllInbounds() if err != nil { @@ -246,22 +246,24 @@ func (j *LdapSyncJob) deleteClientsNotInLDAP(inboundTag string, ldapEmails map[s return } + batchSize := 50 // clients in 1 batch + restartNeeded := false + for _, ib := range inbounds { if ib.Tag != inboundTag { continue } clients, err := j.inboundService.GetClients(ib) if err != nil { + logger.Warningf("Failed to get clients for inbound %s: %v", ib.Tag, err) continue } - // Сбор клиентов для удаления + // Collect clients for deletion toDelete := []model.Client{} for _, c := range clients { if _, ok := ldapEmails[c.Email]; !ok { - // Use appropriate field depending on protocol - client := model.Client{Email: c.Email, ID: c.ID, Password: c.Password} - toDelete = append(toDelete, client) + toDelete = append(toDelete, c) } } @@ -269,21 +271,47 @@ func (j *LdapSyncJob) deleteClientsNotInLDAP(inboundTag string, ldapEmails map[s continue } - payload := &model.Inbound{ - Id: ib.Id, - Settings: j.clientsToJSON(toDelete), - } + // Delete in batches + for i := 0; i < len(toDelete); i += batchSize { + end := i + batchSize + if end > len(toDelete) { + end = len(toDelete) + } + batch := toDelete[i:end] - if _, err := j.inboundService.DelInboundClient(payload.Id, payload.Settings); err != nil { - logger.Warningf("Batch delete failed for inbound %s: %v", ib.Tag, err) - } else { - logger.Infof("Batch deleted %d clients from inbound %s", len(toDelete), ib.Tag) - j.xrayService.SetToNeedRestart() + for _, c := range batch { + var clientKey string + switch ib.Protocol { + case model.Trojan: + clientKey = c.Password + case model.Shadowsocks: + clientKey = c.Email + default: // vless/vmess + clientKey = c.ID + } + + if _, err := j.inboundService.DelInboundClient(ib.Id, clientKey); err != nil { + logger.Warningf("Failed to delete client %s from inbound id=%d(tag=%s): %v", + c.Email, ib.Id, ib.Tag, err) + } else { + logger.Infof("Deleted client %s from inbound id=%d(tag=%s)", + c.Email, ib.Id, ib.Tag) + // do not restart here + restartNeeded = true + } + } } } + + // One time after all batches + if restartNeeded { + j.xrayService.SetToNeedRestart() + logger.Info("Xray restart scheduled after batch deletion") + } } -// clientsToJSON сериализует массив клиентов в JSON + +// clientsToJSON serializes an array of clients to JSON func (j *LdapSyncJob) clientsToJSON(clients []model.Client) string { b := strings.Builder{} b.WriteString("{\"clients\":[")