diff --git a/model/outbound.go b/model/outbound.go index 62a2f9d..15b907c 100644 --- a/model/outbound.go +++ b/model/outbound.go @@ -4,8 +4,8 @@ import ( "encoding/json" "errors" "reflect" + "strings" C "sub2sing-box/constant" - "sub2sing-box/util" ) type _Outbound struct { @@ -83,17 +83,41 @@ func (h *Outbound) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - result, err := util.MergeAndMarshal(struct { - Type string `json:"type"` - Tag string `json:"tag,omitempty"` - }{ - Type: h.Type, - Tag: h.Tag, - }, rawOptions) - if err != nil { - return nil, err + result := make(map[string]any) + result["type"] = h.Type + result["tag"] = h.Tag + optsValue := reflect.ValueOf(rawOptions).Elem() + optsType := optsValue.Type() + for i := 0; i < optsType.NumField(); i++ { + field := optsValue.Field(i) + fieldType := optsType.Field(i) + if fieldType.Anonymous { + embeddedFields := reflect.ValueOf(field.Interface()) + if field.Kind() == reflect.Struct { + for j := 0; j < embeddedFields.NumField(); j++ { + embeddedField := embeddedFields.Field(j) + embeddedFieldType := embeddedFields.Type().Field(j) + processField(embeddedField, embeddedFieldType, result) + } + } + } else { + processField(field, fieldType, result) + } } - return []byte(result), nil + return json.Marshal(result) +} + +func processField(field reflect.Value, fieldType reflect.StructField, result map[string]any) { + jsonTag := fieldType.Tag.Get("json") + if jsonTag == "-" { + return + } + tagParts := strings.Split(jsonTag, ",") + tagName := tagParts[0] + if len(tagParts) > 1 && tagParts[1] == "omitempty" && field.IsZero() { + return + } + result[tagName] = field.Interface() } func (h *Outbound) UnmarshalJSON(bytes []byte) error { diff --git a/parser/error.go b/parser/error.go index af95f0b..c16da49 100644 --- a/parser/error.go +++ b/parser/error.go @@ -9,11 +9,9 @@ type ParseError struct { type ParseErrorType string const ( - ErrInvalidPrefix ParseErrorType = "invalid url prefix" - ErrInvalidStruct ParseErrorType = "invalid struct" - ErrInvalidPort ParseErrorType = "invalid port number" - ErrCannotParseParams ParseErrorType = "cannot parse query parameters" - ErrInvalidBase64 ParseErrorType = "invalid base64" + ErrInvalidPrefix ParseErrorType = "invalid url prefix" + ErrInvalidStruct ParseErrorType = "invalid struct" + ErrInvalidPort ParseErrorType = "invalid port number" ) func (e *ParseError) Error() string { diff --git a/parser/shadowsocks.go b/parser/shadowsocks.go index 156f354..ca75561 100644 --- a/parser/shadowsocks.go +++ b/parser/shadowsocks.go @@ -72,6 +72,8 @@ func ParseShadowsocks(proxy string) (model.Outbound, error) { Raw: proxy, } } + method := methodAndPass[0] + password := methodAndPass[1] query := link.Query() pluginStr := query.Get("plugin") @@ -99,8 +101,8 @@ func ParseShadowsocks(proxy string) (model.Outbound, error) { Server: server, ServerPort: port, }, - Method: methodAndPass[0], - Password: methodAndPass[1], + Method: method, + Password: password, Plugin: plugin, PluginOptions: options, }, diff --git a/parser/vless.go b/parser/vless.go index 039e79a..6690cb9 100644 --- a/parser/vless.go +++ b/parser/vless.go @@ -78,10 +78,6 @@ func ParseVless(proxy string) (model.Outbound, error) { ALPN: alpn, ServerName: sni, Insecure: insecureBool, - UTLS: &model.OutboundUTLSOptions{ - Enabled: enableUTLS, - Fingerprint: fp, - }, }, } } @@ -93,10 +89,6 @@ func ParseVless(proxy string) (model.Outbound, error) { ALPN: alpn, ServerName: sni, Insecure: insecureBool, - UTLS: &model.OutboundUTLSOptions{ - Enabled: enableUTLS, - Fingerprint: fp, - }, Reality: &model.OutboundRealityOptions{ Enabled: true, PublicKey: pbk, @@ -141,7 +133,7 @@ func ParseVless(proxy string) (model.Outbound, error) { hosts, err := url.QueryUnescape(host) if err != nil { return model.Outbound{}, &ParseError{ - Type: ErrCannotParseParams, + Type: ErrInvalidStruct, Raw: proxy, Message: err.Error(), } @@ -153,5 +145,13 @@ func ParseVless(proxy string) (model.Outbound, error) { }, } } + + if enableUTLS { + result.VLESSOptions.OutboundTLSOptionsContainer.TLS.UTLS = &model.OutboundUTLSOptions{ + Enabled: enableUTLS, + Fingerprint: fp, + } + } + return result, nil } diff --git a/parser/vmess.go b/parser/vmess.go index c6b26f1..10bf6fc 100644 --- a/parser/vmess.go +++ b/parser/vmess.go @@ -18,7 +18,7 @@ func ParseVmess(proxy string) (model.Outbound, error) { proxy = strings.TrimPrefix(proxy, constant.VMessPrefix) base64, err := util.DecodeBase64(proxy) if err != nil { - return model.Outbound{}, &ParseError{Type: ErrInvalidBase64, Raw: proxy, Message: err.Error()} + return model.Outbound{}, &ParseError{Type: ErrInvalidStruct, Raw: proxy, Message: err.Error()} } var vmess model.VmessJson diff --git a/util/merge.go b/util/merge.go deleted file mode 100644 index 562a5b7..0000000 --- a/util/merge.go +++ /dev/null @@ -1,78 +0,0 @@ -package util - -import ( - "encoding/json" - "fmt" - "reflect" -) - -func MergeAndMarshal(s1, s2 any) (string, error) { - merged, err := mergeStructs(s1, s2) - if err != nil { - return "", err - } - jsonBytes, err := json.Marshal(merged) - if err != nil { - return "", err - } - return string(jsonBytes), nil -} - -func mergeStructs(s1, s2 any) (any, error) { - v1 := reflect.ValueOf(s1) - v2 := reflect.ValueOf(s2) - - if v1.Kind() == reflect.Pointer { - v1 = v1.Elem() - } - if v2.Kind() == reflect.Pointer { - v2 = v2.Elem() - } - - if v1.Kind() != reflect.Struct || v2.Kind() != reflect.Struct { - return nil, fmt.Errorf("both arguments must be structs") - } - - t1 := v1.Type() - t2 := v2.Type() - - var fields []reflect.StructField - var fieldsSet = make(map[string]reflect.Type) - for i := 0; i < t1.NumField(); i++ { - field := t1.Field(i) - fields = append(fields, field) - fieldsSet[field.Name] = field.Type - } - - for i := 0; i < t2.NumField(); i++ { - field := t2.Field(i) - if existingType, ok := fieldsSet[field.Name]; ok { - if existingType != field.Type { - return nil, fmt.Errorf("field %s has conflicting types: %s and %s", field.Name, existingType, field.Type) - } - } else { - fields = append(fields, field) - fieldsSet[field.Name] = field.Type - } - } - - newType := reflect.StructOf(fields) - - newValue := reflect.New(newType).Elem() - - for i := 0; i < t1.NumField(); i++ { - valueField := newValue.FieldByName(t1.Field(i).Name) - if valueField.IsValid() { - valueField.Set(v1.Field(i)) - } - } - - for i := 0; i < t2.NumField(); i++ { - valueField := newValue.FieldByName(t2.Field(i).Name) - if valueField.IsValid() { - valueField.Set(v2.Field(i)) - } - } - - return newValue.Interface(), nil -}