mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-28 08:34:22 +00:00
94b8196e84
* fix(db): additional cross-DB and node traffic edge cases
- ExternalProxy migration: change StreamSettings scan from []byte
to string (text column on both SQLite and Postgres). Use []byte()
for json.Unmarshal. Avoids potential scan/encoding differences
in migration of old multi-domain data on PG.
- Node mirror inbound creation and updates in SetRemoteTraffic:
now copy LastTrafficResetTime from the node's reported snapshot.
Previously, resets done on the node (or via API that affects
node-owned inbounds) would not update the grace period tracking
on the central mirror. This improves traffic reset + node traffic
combining accuracy when using the public API to manage node
inbounds or when nodes perform resets.
These are independent additional issues around node traffic
combining, creating mirrored node inbounds from snapshots,
and migration code that can affect Postgres (or mixed) setups
after API changes or node operations. They do not depend on the
previous enable-merge or tag/sub fixes.
Base: upstream/main (separate PR).
* fix(db): even more node/SQLite edge cases (chunked IN for node stats, tag cleanup)
- In NodeService.GetAll (used for node list/stats): the load of client_traffics
for node inbound IDs used a direct "IN ?" with all IDs. On SQLite this
can hit the bind var limit ("too many SQL variables") when there are
many nodes/inbounds. Chunked using the existing chunkInts + sqliteMaxVars
(same pattern as other large IN queries in the package). This is a
specific scale issue for "node" setups on SQLite (PG is fine with large IN).
- Tag cleanup raw in MigrationRequirements (always runs at startup):
was using SQLite-only INSTR. Fixed to use position() on PG (same as
the previous tag fix on the main branch). Prevents startup crash on PG
after node/inbound API changes that leave old tags.
These are additional specific cases around node traffic/stats combining,
node inbound counts, and startup migrations that can affect Postgres
users or large SQLite node deployments. They are independent of the
enable/traffic core fixes and the prior additional ones.
Added to the clean additional-issues branch for the separate PR.
* fix(db): even more for node traffic merge on 5045 (dialect enable expr + chunk gone deletes)
- Full dialect-safe client enable merge in setRemoteTrafficLocked:
- Added ClientTrafficEnableMergeExpr() helper (PG CASE with ::boolean
casts to avoid type errors; SQLite numeric for affinity).
- Updated GreatestExpr with ::bigint casts on PG.
- Switched the merge UPDATE from "enable AND ?" to the helper.
This completes the node traffic sync safety for the "only node can
disable" logic across DBs (core of the original symptom after API
inbound updates on nodes).
- Chunked the NodeClientTraffic delete for "goneEmails" (when a node's
snapshot no longer includes clients previously attached to a mirrored
inbound). The "email IN ?" could exceed SQLite bind limit for nodes
with many clients (after API deletes, bulk ops, or structural changes).
Uses chunkStrings + sqliteMaxVars (consistent with the node stats chunk
we added earlier).
These are direct extensions of node traffic combining, mirrored inbound
lifecycle, and API-driven changes that affect client_traffics / NodeClientTraffic
for nodes. Stayed on the clean 5045 branch as requested.
Pushed to update https://github.com/MHSanaei/3x-ui/pull/5045
---------
Co-authored-by: Rqzbeh <rqzbeh@users.noreply.github.com>
33 lines
833 B
Go
33 lines
833 B
Go
package database
|
|
|
|
import "fmt"
|
|
|
|
func JSONClientsFromInbound() string {
|
|
if IsPostgres() {
|
|
return "FROM inbounds, jsonb_array_elements(inbounds.settings::jsonb -> 'clients') AS client(value)"
|
|
}
|
|
return "FROM inbounds, JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client"
|
|
}
|
|
|
|
func JSONFieldText(expr, key string) string {
|
|
if IsPostgres() {
|
|
return fmt.Sprintf("(%s ->> '%s')", expr, key)
|
|
}
|
|
|
|
return fmt.Sprintf("TRIM(JSON_EXTRACT(%s, '$.%s'), '\"')", expr, key)
|
|
}
|
|
|
|
func GreatestExpr(a, b string) string {
|
|
if IsPostgres() {
|
|
return fmt.Sprintf("GREATEST(%s::bigint, %s::bigint)", a, b)
|
|
}
|
|
return fmt.Sprintf("MAX(%s, %s)", a, b)
|
|
}
|
|
|
|
func ClientTrafficEnableMergeExpr() string {
|
|
if IsPostgres() {
|
|
return "CASE WHEN ?::boolean THEN enable::boolean ELSE false END"
|
|
}
|
|
return "CASE WHEN ? THEN enable ELSE 0 END"
|
|
}
|