mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-26 15:55:02 +03:00
feat(hosts): add drag-and-drop and global subscription ordering (#6895)
Hosts already had one saved order on the Hosts page, but subscriptions honoured it only inside each inbound, so a host of a later inbound could never come before one of an earlier inbound (#6894). A new opt-in setting makes raw/base64, Clash/Mihomo and JSON subscriptions follow the Hosts page order across inbounds; the default keeps today's inbound-first output unchanged. The Hosts table gains drag-and-drop reordering next to the Up/Down buttons, on a pointer-reorder hook the Routing Rules table now shares.
This commit is contained in:
+34
-3
@@ -77,6 +77,9 @@ type SubService struct {
|
||||
// with the clients array left out; generators read only inbound-level
|
||||
// fields (encryption, method, version, …) from it.
|
||||
settingsByInbound map[int]map[string]any
|
||||
hostsByInbound map[int][]*model.Host
|
||||
hostGroupOrders map[string]hostEntryOrder
|
||||
hostsFirst bool
|
||||
}
|
||||
|
||||
// NewSubService creates a new subscription service with the given configuration.
|
||||
@@ -112,6 +115,10 @@ func (s *SubService) PrepareForRequest(host string) {
|
||||
s.clientsByInbound = map[int]map[string]model.Client{}
|
||||
s.fullyPrimedInbounds = map[int]bool{}
|
||||
s.settingsByInbound = map[int]map[string]any{}
|
||||
s.hostsByInbound = nil
|
||||
s.hostGroupOrders = nil
|
||||
mode, _ := s.settingService.GetSubHostSortMode()
|
||||
s.hostsFirst = mode == "hosts-first"
|
||||
s.loadNodes()
|
||||
s.loadRemarkSettings()
|
||||
s.subCalendarExpireInclusive, _ = s.settingService.GetSubCalendarExpireInclusive()
|
||||
@@ -464,6 +471,7 @@ func (s *SubService) resolveInfoNodeRemark(subId string, uniqueEmails []string,
|
||||
|
||||
func (s *SubService) getSubs(subId string) ([]string, []string, int64, xray.ClientTraffic, error) {
|
||||
var result []string
|
||||
var ordered []orderedSubEntry[func() string]
|
||||
var emails []string
|
||||
var traffic xray.ClientTraffic
|
||||
var hasEnabledClient bool
|
||||
@@ -495,22 +503,42 @@ func (s *SubService) getSubs(subId string) ([]string, []string, int64, xray.Clie
|
||||
s.projectThroughFallbackMaster(inbound)
|
||||
// Host overrides apply AFTER fallback projection so a host's
|
||||
// address/TLS wins over the projected master stream.
|
||||
hostEps := s.hostEndpoints(inbound, "raw")
|
||||
var hostEps []map[string]any
|
||||
if !s.hostsFirst {
|
||||
hostEps = s.hostEndpoints(inbound, "raw")
|
||||
}
|
||||
for _, client := range clients {
|
||||
if client.Enable {
|
||||
hasEnabledClient = true
|
||||
}
|
||||
var link string
|
||||
if len(hostEps) > 0 {
|
||||
if s.hostsFirst {
|
||||
for _, variant := range s.subscriptionHostVariants(inbound, "raw") {
|
||||
render := func() string {
|
||||
if variant.host != nil {
|
||||
return s.linkFromHosts(inbound, client, variant.endpoint(s, inbound))
|
||||
}
|
||||
return s.GetLink(inbound, client.Email)
|
||||
}
|
||||
ordered = append(ordered, orderedSubEntry[func() string]{variant.order, render})
|
||||
}
|
||||
} else if len(hostEps) > 0 {
|
||||
link = s.linkFromHosts(inbound, client, hostEps)
|
||||
} else {
|
||||
link = s.GetLink(inbound, client.Email)
|
||||
}
|
||||
result = append(result, link)
|
||||
if !s.hostsFirst {
|
||||
result = append(result, link)
|
||||
}
|
||||
emails = append(emails, client.Email)
|
||||
seenEmails[client.Email] = struct{}{}
|
||||
}
|
||||
}
|
||||
if s.hostsFirst {
|
||||
for _, render := range orderedSubValues(ordered) {
|
||||
result = append(result, render())
|
||||
}
|
||||
}
|
||||
for _, ext := range externalLinks {
|
||||
if ext.Enable {
|
||||
hasEnabledClient = true
|
||||
@@ -693,6 +721,9 @@ func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error)
|
||||
return nil, err
|
||||
}
|
||||
s.indexStatsBySubId(subId)
|
||||
if err := s.loadSubscriptionHosts(inbounds); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return inbounds, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user