mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-28 00:24:19 +00:00
f1a4286e2f
Add a subSortIndex field to inbounds that controls the order of links in subscription output only: the raw sub body, the HTML sub page, and the JSON/Clash formats (all served from the same query). Lower values come first; ties keep id order. The panel inbound list is unaffected. The value is editable in the inbound form next to the share-address fields, propagates to nodes via wireInbound, and follows the usual node-sync rules (copied on import, mirrored while not dirty, never a structural change). Rescoped from #5214 by @Ponywka.
85 lines
2.3 KiB
Go
85 lines
2.3 KiB
Go
package service
|
|
|
|
// sqliteMaxVars is a safe ceiling for the number of bind parameters in a
|
|
// single SQL statement. SQLite's SQLITE_MAX_VARIABLE_NUMBER is 999 on builds
|
|
// before 3.32 and 32766 after; staying under 999 keeps queries portable
|
|
// across forks/old binaries and also bounds per-query memory on truly large
|
|
// installs (>32k clients) where even modern SQLite would refuse a single IN.
|
|
const sqliteMaxVars = 900
|
|
|
|
// normalizeSubSortIndex clamps the 1-based subscription sort order. Values
|
|
// below 1 arrive from clients that predate the field (omitted form key binds
|
|
// to 0) and must not sort ahead of explicitly ranked inbounds.
|
|
func normalizeSubSortIndex(v int) int {
|
|
if v < 1 {
|
|
return 1
|
|
}
|
|
return v
|
|
}
|
|
|
|
// uniqueNonEmptyStrings returns a deduplicated copy of in with empty strings
|
|
// removed, preserving the order of first occurrence.
|
|
func uniqueNonEmptyStrings(in []string) []string {
|
|
if len(in) == 0 {
|
|
return nil
|
|
}
|
|
seen := make(map[string]struct{}, len(in))
|
|
out := make([]string, 0, len(in))
|
|
for _, v := range in {
|
|
if v == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[v]; ok {
|
|
continue
|
|
}
|
|
seen[v] = struct{}{}
|
|
out = append(out, v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// uniqueInts returns a deduplicated copy of in, preserving order of first occurrence.
|
|
func uniqueInts(in []int) []int {
|
|
if len(in) == 0 {
|
|
return nil
|
|
}
|
|
seen := make(map[int]struct{}, len(in))
|
|
out := make([]int, 0, len(in))
|
|
for _, v := range in {
|
|
if _, ok := seen[v]; ok {
|
|
continue
|
|
}
|
|
seen[v] = struct{}{}
|
|
out = append(out, v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// chunkStrings splits s into consecutive sub-slices of at most size elements.
|
|
// Returns nil for an empty input or non-positive size.
|
|
func chunkStrings(s []string, size int) [][]string {
|
|
if size <= 0 || len(s) == 0 {
|
|
return nil
|
|
}
|
|
out := make([][]string, 0, (len(s)+size-1)/size)
|
|
for i := 0; i < len(s); i += size {
|
|
end := min(i+size, len(s))
|
|
out = append(out, s[i:end])
|
|
}
|
|
return out
|
|
}
|
|
|
|
// chunkInts splits s into consecutive sub-slices of at most size elements.
|
|
// Returns nil for an empty input or non-positive size.
|
|
func chunkInts(s []int, size int) [][]int {
|
|
if size <= 0 || len(s) == 0 {
|
|
return nil
|
|
}
|
|
out := make([][]int, 0, (len(s)+size-1)/size)
|
|
for i := 0; i < len(s); i += size {
|
|
end := min(i+size, len(s))
|
|
out = append(out, s[i:end])
|
|
}
|
|
return out
|
|
}
|