mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-09 06:35:03 +03:00
feat(clients): bind host rules to individual clients in subscriptions (#6620)
Host rules applied per inbound only, so every client of an inbound got the same subscription endpoints (#6618). A client can now be bound to one or more host rules, and its raw, JSON and Clash subscriptions render only those hosts, in either subscription order; an unbound client is unchanged. A binding whose hosts are deleted, disabled or excluded from the format fails closed: the client gets no links there but stays in traffic accounting. Host edits keep row ids, so bindings survive them; nil leaves a stored binding alone and an empty list clears it.
This commit is contained in:
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@@ -42,6 +43,10 @@ func applyClientRecordMerge(row *model.ClientRecord, incoming *model.ClientRecor
|
||||
if incoming.Security != "" {
|
||||
row.Security = incoming.Security
|
||||
}
|
||||
// nil preserves the stored binding, empty clears it via Update's write.
|
||||
if ids := model.NormalizeClientHostRuleIds(incoming.ClientHostRuleIds); ids != nil {
|
||||
row.ClientHostRuleIds = ids
|
||||
}
|
||||
if incoming.Reverse != "" {
|
||||
row.Reverse = incoming.Reverse
|
||||
}
|
||||
@@ -169,6 +174,7 @@ func (s *ClientService) syncInboundClients(tx *gorm.DB, inboundId int, clients [
|
||||
// ToRecord copies the raw email; store the trimmed key this function
|
||||
// looks up by, or a padded email is inserted and never found again.
|
||||
incoming.Email = email
|
||||
incoming.ClientHostRuleIds = model.NormalizeClientHostRuleIds(incoming.ClientHostRuleIds)
|
||||
row, ok := existing[email]
|
||||
if !ok {
|
||||
if _, dup := pending[email]; !dup {
|
||||
@@ -187,7 +193,9 @@ func (s *ClientService) syncInboundClients(tx *gorm.DB, inboundId int, clients [
|
||||
|
||||
idByEmail[email] = row.Id
|
||||
|
||||
if *row == before {
|
||||
// DeepEqual: ClientRecord now carries a slice (ClientHostRuleIds)
|
||||
// and is no longer ==-comparable.
|
||||
if reflect.DeepEqual(*row, before) {
|
||||
continue
|
||||
}
|
||||
if err := tx.Save(row).Error; err != nil {
|
||||
|
||||
Reference in New Issue
Block a user