diff --git a/internal/sub/host_sub_test.go b/internal/sub/host_sub_test.go index 3f8b75a4d..cb3dacc91 100644 --- a/internal/sub/host_sub_test.go +++ b/internal/sub/host_sub_test.go @@ -2048,8 +2048,10 @@ func TestSub_LegacyFallbackMasterLookedUpOncePerRequest(t *testing.T) { scans := 0 count := func(tx *gorm.DB) { - if strings.Contains(tx.Statement.SQL.String(), "$.fallbacks") { - scans++ + for _, v := range tx.Statement.Vars { + if v == "%fallbacks%" { + scans++ + } } } _ = db.Callback().Query().After("gorm:query").Register("test:count_front_scans", count) diff --git a/internal/sub/service.go b/internal/sub/service.go index 2c4c005f7..4b0b23ad1 100644 --- a/internal/sub/service.go +++ b/internal/sub/service.go @@ -3607,20 +3607,22 @@ func (s *SubService) socketFront(key socketFrontKey) *model.Inbound { Listen string Port int StreamSettings string - Fallbacks string + Settings string } - // json_valid keeps one inbound with unreadable settings from failing the - // whole statement and hiding every front. + // Parsed here, not with SQL JSON functions, so the lookup works on PostgreSQL too and one + // inbound with unreadable settings cannot hide every front. if err := database.GetDB().Model(model.Inbound{}). - Select("node_id, listen, port, stream_settings, json_extract(settings, '$.fallbacks') AS fallbacks"). - Where("CASE WHEN json_valid(settings) THEN JSON_TYPE(settings, '$.fallbacks') END = 'array'"). + Select("node_id, listen, port, stream_settings, settings"). + Where("settings LIKE ?", "%fallbacks%"). Order("id ASC").Scan(&fronts).Error; err != nil { return nil } for _, front := range fronts { - var fallbacks []any - _ = json.Unmarshal([]byte(front.Fallbacks), &fallbacks) - for _, fallback := range fallbacks { + var parsed struct { + Fallbacks []any `json:"fallbacks"` + } + _ = json.Unmarshal([]byte(front.Settings), &parsed) + for _, fallback := range parsed.Fallbacks { rule, _ := fallback.(map[string]any) dest, _ := rule["dest"].(string) k := socketFrontKey{node: nodeKeyOf(front.NodeID), dest: dest}