Files
3x-ui/tools/openapigen/schema.go
MHSanaei d843014461 refactor(backend): retire hysteria2 as a top-level protocol
Hysteria v2 is not a separate xray protocol — it is plain "hysteria"
with streamSettings.version = 2. The frontend already dropped hysteria2
from the protocol enum in 5a90f7e3; the backend was still carrying the
literal as a compat alias.

Removed:
- model.Hysteria2 constant
- model.IsHysteria helper (only callers were buildProxy + genHysteriaLink)
- TestIsHysteria
- "hysteria2" from the Inbound.Protocol validate oneof enum
- All `case model.Hysteria, model.Hysteria2:` and `case "hysteria",
  "hysteria2":` branches across client.go, inbound.go, outbound.go,
  xray.go, port_conflict.go, xray/api.go, subService.go,
  subJsonService.go, subClashService.go
- Stale #4081 comments

Kept (correctly — these are client-side URI/config schemes that are
independent of the xray protocol type):
- hysteria2:// share-link URI in subService.genHysteriaLink
- "hysteria2" Clash proxy type in subClashService.buildHysteriaProxy
- Comments referring to Hysteria v2 as a transport version

Note: this change does not include a DB migration. Existing rows with
protocol = 'hysteria2' will fall through to the default switch arms
after upgrade. A separate `UPDATE inbounds SET protocol = 'hysteria'
WHERE protocol = 'hysteria2'` is required for installs that still hold
legacy data.
2026-05-27 00:58:37 +02:00

173 lines
3.3 KiB
Go

package main
import (
"reflect"
"sort"
"strings"
)
type Schema struct {
Name string
Package string
Fields []Field
Doc string
}
type Alias struct {
Name string
Package string
Underlying TypeRef
}
type Field struct {
JSONName string
GoName string
Type TypeRef
Optional bool
Skip bool
Validate []ValidateRule
Doc string
}
type TypeRef struct {
Kind TypeKind
Name string
Element *TypeRef
Key *TypeRef
Value *TypeRef
Inner *TypeRef
}
type TypeKind string
const (
KindString TypeKind = "string"
KindNumber TypeKind = "number"
KindInt TypeKind = "int"
KindBool TypeKind = "boolean"
KindArray TypeKind = "array"
KindMap TypeKind = "map"
KindObject TypeKind = "object"
KindRef TypeKind = "ref"
KindUnknown TypeKind = "unknown"
KindAny TypeKind = "any"
KindRaw TypeKind = "raw"
)
type ValidateRule struct {
Name string
Param string
}
func parseStructTag(raw string) (json string, validate string, gormHasDash bool) {
tag := reflect.StructTag(strings.Trim(raw, "`"))
json = tag.Get("json")
validate = tag.Get("validate")
if g := tag.Get("gorm"); g != "" {
for part := range strings.SplitSeq(g, ";") {
if strings.TrimSpace(part) == "-" {
gormHasDash = true
}
}
}
return
}
func parseJSONTag(tag string) (name string, omit bool, omitempty bool) {
if tag == "" {
return "", false, false
}
parts := strings.Split(tag, ",")
name = parts[0]
if name == "-" {
return "", true, false
}
for _, p := range parts[1:] {
if p == "omitempty" {
omitempty = true
}
}
return
}
func parseValidateTag(tag string) []ValidateRule {
if tag == "" {
return nil
}
var rules []ValidateRule
for part := range strings.SplitSeq(tag, ",") {
part = strings.TrimSpace(part)
if part == "" {
continue
}
before, after, ok := strings.Cut(part, "=")
if !ok {
rules = append(rules, ValidateRule{Name: part})
continue
}
rules = append(rules, ValidateRule{Name: before, Param: after})
}
return rules
}
func (s Schema) HasValidationOn(field string) bool {
for _, f := range s.Fields {
if f.JSONName == field {
return len(f.Validate) > 0
}
}
return false
}
func sortSchemas(in []Schema) []Schema {
out := make([]Schema, len(in))
copy(out, in)
sort.Slice(out, func(i, j int) bool {
return out[i].Name < out[j].Name
})
return out
}
func sortAliases(in []Alias) []Alias {
out := make([]Alias, len(in))
copy(out, in)
sort.Slice(out, func(i, j int) bool {
return out[i].Name < out[j].Name
})
return out
}
func flattenEmbedded(schemas []Schema) []Schema {
byName := make(map[string]Schema, len(schemas))
for _, s := range schemas {
byName[s.Name] = s
}
out := make([]Schema, 0, len(schemas))
for _, s := range schemas {
var resolved []Field
seen := make(map[string]bool, len(s.Fields))
for _, f := range s.Fields {
if f.Type.Kind == KindRef && f.Type.Name != "nullable" {
if embedded, ok := byName[f.Type.Name]; ok && f.GoName == f.Type.Name {
for _, ef := range embedded.Fields {
if seen[ef.JSONName] {
continue
}
seen[ef.JSONName] = true
resolved = append(resolved, ef)
}
continue
}
}
if seen[f.JSONName] {
continue
}
seen[f.JSONName] = true
resolved = append(resolved, f)
}
s.Fields = resolved
out = append(out, s)
}
return out
}