mirror of
https://github.com/bestnite/sub2clash.git
synced 2025-06-17 20:53:18 +08:00
refactor
This commit is contained in:
@ -17,6 +17,7 @@ func GetSupportProxyTypes(clashType ClashType) map[string]bool {
|
||||
"socks5": true,
|
||||
}
|
||||
}
|
||||
|
||||
if clashType == ClashMeta {
|
||||
return map[string]bool{
|
||||
"ss": true,
|
||||
@ -30,5 +31,6 @@ func GetSupportProxyTypes(clashType ClashType) map[string]bool {
|
||||
"anytls": true,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
package model
|
||||
|
||||
type Tags []struct {
|
||||
Name string `json:"name"`
|
||||
ZipballUrl string `json:"zipball_url"`
|
||||
TarballUrl string `json:"tarball_url"`
|
||||
Commit struct {
|
||||
Sha string `json:"sha"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
NodeId string `json:"node_id"`
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type Anytls struct {
|
||||
Type string `yaml:"type"`
|
||||
@ -35,3 +35,17 @@ func ProxyToAnytls(p Proxy) Anytls {
|
||||
MinIdleSession: p.MinIdleSession,
|
||||
}
|
||||
}
|
||||
|
||||
type AnytlsMarshaler struct{}
|
||||
|
||||
func (m *AnytlsMarshaler) GetType() string {
|
||||
return "anytls"
|
||||
}
|
||||
|
||||
func (m *AnytlsMarshaler) MarshalProxy(p Proxy) (interface{}, error) {
|
||||
return ProxyToAnytls(p), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterMarshaler(&AnytlsMarshaler{})
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type Hysteria struct {
|
||||
Type string `yaml:"type"`
|
||||
@ -56,3 +56,13 @@ func ProxyToHysteria(p Proxy) Hysteria {
|
||||
HopInterval: p.HopInterval,
|
||||
}
|
||||
}
|
||||
|
||||
type HysteriaMarshaler struct{}
|
||||
|
||||
func (m *HysteriaMarshaler) GetType() string {
|
||||
return "hysteria"
|
||||
}
|
||||
|
||||
func (m *HysteriaMarshaler) MarshalProxy(p Proxy) (interface{}, error) {
|
||||
return ProxyToHysteria(p), nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type Hysteria2 struct {
|
||||
Type string `yaml:"type"`
|
||||
@ -39,3 +39,13 @@ func ProxyToHysteria2(p Proxy) Hysteria2 {
|
||||
CWND: p.CWND,
|
||||
}
|
||||
}
|
||||
|
||||
type Hysteria2Marshaler struct{}
|
||||
|
||||
func (m *Hysteria2Marshaler) GetType() string {
|
||||
return "hysteria2"
|
||||
}
|
||||
|
||||
func (m *Hysteria2Marshaler) MarshalProxy(p Proxy) (interface{}, error) {
|
||||
return ProxyToHysteria2(p), nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type SmuxStruct struct {
|
||||
Enabled bool `yaml:"enable"`
|
||||
@ -86,6 +86,12 @@ type WireGuardPeerOption struct {
|
||||
type _Proxy Proxy
|
||||
|
||||
func (p Proxy) MarshalYAML() (interface{}, error) {
|
||||
// 尝试使用注册的序列化器
|
||||
if marshaler, exists := GetMarshaler(p.Type); exists {
|
||||
return marshaler.MarshalProxy(p)
|
||||
}
|
||||
|
||||
// 保持向后兼容,对于未注册的类型使用原有逻辑
|
||||
switch p.Type {
|
||||
case "vmess":
|
||||
return ProxyToVmess(p), nil
|
64
model/proxy/registry.go
Normal file
64
model/proxy/registry.go
Normal file
@ -0,0 +1,64 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ProxyMarshaler 代理YAML序列化接口
|
||||
type ProxyMarshaler interface {
|
||||
// MarshalProxy 将通用Proxy对象序列化为特定协议的YAML结构
|
||||
MarshalProxy(p Proxy) (interface{}, error)
|
||||
// GetType 返回支持的协议类型
|
||||
GetType() string
|
||||
}
|
||||
|
||||
// marshalerRegistry YAML序列化器注册中心
|
||||
type marshalerRegistry struct {
|
||||
mu sync.RWMutex
|
||||
marshalers map[string]ProxyMarshaler // type -> marshaler
|
||||
}
|
||||
|
||||
var yamlRegistry = &marshalerRegistry{
|
||||
marshalers: make(map[string]ProxyMarshaler),
|
||||
}
|
||||
|
||||
// RegisterMarshaler 注册YAML序列化器
|
||||
func RegisterMarshaler(marshaler ProxyMarshaler) {
|
||||
yamlRegistry.mu.Lock()
|
||||
defer yamlRegistry.mu.Unlock()
|
||||
|
||||
yamlRegistry.marshalers[marshaler.GetType()] = marshaler
|
||||
}
|
||||
|
||||
// GetMarshaler 根据协议类型获取序列化器
|
||||
func GetMarshaler(proxyType string) (ProxyMarshaler, bool) {
|
||||
yamlRegistry.mu.RLock()
|
||||
defer yamlRegistry.mu.RUnlock()
|
||||
|
||||
marshaler, exists := yamlRegistry.marshalers[proxyType]
|
||||
return marshaler, exists
|
||||
}
|
||||
|
||||
// GetAllMarshalers 获取所有注册的序列化器
|
||||
func GetAllMarshalers() map[string]ProxyMarshaler {
|
||||
yamlRegistry.mu.RLock()
|
||||
defer yamlRegistry.mu.RUnlock()
|
||||
|
||||
result := make(map[string]ProxyMarshaler)
|
||||
for k, v := range yamlRegistry.marshalers {
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// GetSupportedTypes 获取所有支持的协议类型
|
||||
func GetSupportedTypes() []string {
|
||||
yamlRegistry.mu.RLock()
|
||||
defer yamlRegistry.mu.RUnlock()
|
||||
|
||||
types := make([]string, 0, len(yamlRegistry.marshalers))
|
||||
for proxyType := range yamlRegistry.marshalers {
|
||||
types = append(types, proxyType)
|
||||
}
|
||||
return types
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type ShadowSocks struct {
|
||||
Type string `yaml:"type"`
|
||||
@ -31,3 +31,21 @@ func ProxyToShadowSocks(p Proxy) ShadowSocks {
|
||||
ClientFingerprint: p.ClientFingerprint,
|
||||
}
|
||||
}
|
||||
|
||||
// ShadowsocksMarshaler Shadowsocks协议的YAML序列化器
|
||||
type ShadowsocksMarshaler struct{}
|
||||
|
||||
// GetType 返回协议类型
|
||||
func (m *ShadowsocksMarshaler) GetType() string {
|
||||
return "ss"
|
||||
}
|
||||
|
||||
// MarshalProxy 序列化Shadowsocks代理
|
||||
func (m *ShadowsocksMarshaler) MarshalProxy(p Proxy) (interface{}, error) {
|
||||
return ProxyToShadowSocks(p), nil
|
||||
}
|
||||
|
||||
// 注册序列化器
|
||||
func init() {
|
||||
RegisterMarshaler(&ShadowsocksMarshaler{})
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type ShadowSocksR struct {
|
||||
Type string `yaml:"type"`
|
||||
@ -29,3 +29,13 @@ func ProxyToShadowSocksR(p Proxy) ShadowSocksR {
|
||||
UDP: p.UDP,
|
||||
}
|
||||
}
|
||||
|
||||
type ShadowsocksRMarshaler struct{}
|
||||
|
||||
func (m *ShadowsocksRMarshaler) GetType() string {
|
||||
return "ssr"
|
||||
}
|
||||
|
||||
func (m *ShadowsocksRMarshaler) MarshalProxy(p Proxy) (interface{}, error) {
|
||||
return ProxyToShadowSocksR(p), nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type Trojan struct {
|
||||
Type string `yaml:"type"`
|
||||
@ -37,3 +37,13 @@ func ProxyToTrojan(p Proxy) Trojan {
|
||||
ClientFingerprint: p.ClientFingerprint,
|
||||
}
|
||||
}
|
||||
|
||||
type TrojanMarshaler struct{}
|
||||
|
||||
func (m *TrojanMarshaler) GetType() string {
|
||||
return "trojan"
|
||||
}
|
||||
|
||||
func (m *TrojanMarshaler) MarshalProxy(p Proxy) (interface{}, error) {
|
||||
return ProxyToTrojan(p), nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type Vless struct {
|
||||
Type string `yaml:"type"`
|
||||
@ -55,3 +55,13 @@ func ProxyToVless(p Proxy) Vless {
|
||||
ClientFingerprint: p.ClientFingerprint,
|
||||
}
|
||||
}
|
||||
|
||||
type VlessMarshaler struct{}
|
||||
|
||||
func (m *VlessMarshaler) GetType() string {
|
||||
return "vless"
|
||||
}
|
||||
|
||||
func (m *VlessMarshaler) MarshalProxy(p Proxy) (interface{}, error) {
|
||||
return ProxyToVless(p), nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package model
|
||||
package proxy
|
||||
|
||||
type HTTPOptions struct {
|
||||
Method string `yaml:"method,omitempty"`
|
||||
@ -102,3 +102,13 @@ func ProxyToVmess(p Proxy) Vmess {
|
||||
ClientFingerprint: p.ClientFingerprint,
|
||||
}
|
||||
}
|
||||
|
||||
type VmessMarshaler struct{}
|
||||
|
||||
func (m *VmessMarshaler) GetType() string {
|
||||
return "vmess"
|
||||
}
|
||||
|
||||
func (m *VmessMarshaler) MarshalProxy(p Proxy) (interface{}, error) {
|
||||
return ProxyToVmess(p), nil
|
||||
}
|
158
model/sub_config.go
Normal file
158
model/sub_config.go
Normal file
@ -0,0 +1,158 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SubConfig struct {
|
||||
Sub string `form:"sub" binding:""`
|
||||
Subs []string `form:"-" binding:""`
|
||||
Proxy string `form:"proxy" binding:""`
|
||||
Proxies []string `form:"-" binding:""`
|
||||
Refresh bool `form:"refresh,default=false" binding:""`
|
||||
Template string `form:"template" binding:""`
|
||||
RuleProvider string `form:"ruleProvider" binding:""`
|
||||
RuleProviders []RuleProviderStruct `form:"-" binding:""`
|
||||
Rule string `form:"rule" binding:""`
|
||||
Rules []RuleStruct `form:"-" binding:""`
|
||||
AutoTest bool `form:"autoTest,default=false" binding:""`
|
||||
Lazy bool `form:"lazy,default=false" binding:""`
|
||||
Sort string `form:"sort" binding:""`
|
||||
Remove string `form:"remove" binding:""`
|
||||
Replace string `form:"replace" binding:""`
|
||||
ReplaceKeys []string `form:"-" binding:""`
|
||||
ReplaceTo []string `form:"-" binding:""`
|
||||
NodeListMode bool `form:"nodeList,default=false" binding:""`
|
||||
IgnoreCountryGrooup bool `form:"ignoreCountryGroup,default=false" binding:""`
|
||||
UserAgent string `form:"userAgent" binding:""`
|
||||
}
|
||||
|
||||
type RuleProviderStruct struct {
|
||||
Behavior string
|
||||
Url string
|
||||
Group string
|
||||
Prepend bool
|
||||
Name string
|
||||
}
|
||||
|
||||
type RuleStruct struct {
|
||||
Rule string
|
||||
Prepend bool
|
||||
}
|
||||
|
||||
func ParseSubQuery(c *gin.Context) (SubConfig, error) {
|
||||
var query SubConfig
|
||||
if err := c.ShouldBind(&query); err != nil {
|
||||
return SubConfig{}, errors.New("参数错误: " + err.Error())
|
||||
}
|
||||
if query.Sub == "" && query.Proxy == "" {
|
||||
return SubConfig{}, errors.New("参数错误: sub 和 proxy 不能同时为空")
|
||||
}
|
||||
if query.Sub != "" {
|
||||
query.Subs = strings.Split(query.Sub, ",")
|
||||
for i := range query.Subs {
|
||||
if !strings.HasPrefix(query.Subs[i], "http") {
|
||||
return SubConfig{}, errors.New("参数错误: sub 格式错误")
|
||||
}
|
||||
if _, err := url.ParseRequestURI(query.Subs[i]); err != nil {
|
||||
return SubConfig{}, errors.New("参数错误: " + err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query.Subs = nil
|
||||
}
|
||||
if query.Proxy != "" {
|
||||
query.Proxies = strings.Split(query.Proxy, ",")
|
||||
} else {
|
||||
query.Proxies = nil
|
||||
}
|
||||
if query.Template != "" {
|
||||
if strings.HasPrefix(query.Template, "http") {
|
||||
uri, err := url.ParseRequestURI(query.Template)
|
||||
if err != nil {
|
||||
return SubConfig{}, err
|
||||
}
|
||||
query.Template = uri.String()
|
||||
}
|
||||
}
|
||||
if query.RuleProvider != "" {
|
||||
reg := regexp.MustCompile(`\[(.*?)\]`)
|
||||
ruleProviders := reg.FindAllStringSubmatch(query.RuleProvider, -1)
|
||||
for i := range ruleProviders {
|
||||
length := len(ruleProviders)
|
||||
parts := strings.Split(ruleProviders[length-i-1][1], ",")
|
||||
if len(parts) < 4 {
|
||||
return SubConfig{}, errors.New("参数错误: ruleProvider 格式错误")
|
||||
}
|
||||
u := parts[1]
|
||||
uri, err := url.ParseRequestURI(u)
|
||||
if err != nil {
|
||||
return SubConfig{}, errors.New("参数错误: " + err.Error())
|
||||
}
|
||||
u = uri.String()
|
||||
if len(parts) == 4 {
|
||||
hash := sha256.Sum224([]byte(u))
|
||||
parts = append(parts, hex.EncodeToString(hash[:]))
|
||||
}
|
||||
query.RuleProviders = append(
|
||||
query.RuleProviders, RuleProviderStruct{
|
||||
Behavior: parts[0],
|
||||
Url: u,
|
||||
Group: parts[2],
|
||||
Prepend: parts[3] == "true",
|
||||
Name: parts[4],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
names := make(map[string]bool)
|
||||
for _, ruleProvider := range query.RuleProviders {
|
||||
if _, ok := names[ruleProvider.Name]; ok {
|
||||
return SubConfig{}, errors.New("参数错误: Rule-Provider 名称重复")
|
||||
}
|
||||
names[ruleProvider.Name] = true
|
||||
}
|
||||
} else {
|
||||
query.RuleProviders = nil
|
||||
}
|
||||
if query.Rule != "" {
|
||||
reg := regexp.MustCompile(`\[(.*?)\]`)
|
||||
rules := reg.FindAllStringSubmatch(query.Rule, -1)
|
||||
for i := range rules {
|
||||
length := len(rules)
|
||||
r := rules[length-1-i][1]
|
||||
strings.LastIndex(r, ",")
|
||||
parts := [2]string{}
|
||||
parts[0] = r[:strings.LastIndex(r, ",")]
|
||||
parts[1] = r[strings.LastIndex(r, ",")+1:]
|
||||
query.Rules = append(
|
||||
query.Rules, RuleStruct{
|
||||
Rule: parts[0],
|
||||
Prepend: parts[1] == "true",
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
query.Rules = nil
|
||||
}
|
||||
if strings.TrimSpace(query.Replace) != "" {
|
||||
reg := regexp.MustCompile(`\[<(.*?)>,<(.*?)>\]`)
|
||||
replaces := reg.FindAllStringSubmatch(query.Replace, -1)
|
||||
for i := range replaces {
|
||||
length := len(replaces[i])
|
||||
if length != 3 {
|
||||
return SubConfig{}, errors.New("参数错误: replace 格式错误")
|
||||
}
|
||||
query.ReplaceKeys = append(query.ReplaceKeys, replaces[i][1])
|
||||
query.ReplaceTo = append(query.ReplaceTo, replaces[i][2])
|
||||
}
|
||||
}
|
||||
return query, nil
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
package model
|
||||
|
||||
import "github.com/bestnite/sub2clash/model/proxy"
|
||||
|
||||
type NodeList struct {
|
||||
Proxies []Proxy `yaml:"proxies,omitempty"`
|
||||
Proxies []proxy.Proxy `yaml:"proxies,omitempty"`
|
||||
}
|
||||
|
||||
type Subscription struct {
|
||||
@ -57,7 +59,7 @@ type Subscription struct {
|
||||
Experimental Experimental `yaml:"experimental,omitempty"`
|
||||
Profile Profile `yaml:"profile,omitempty"`
|
||||
GeoXUrl GeoXUrl `yaml:"geox-url,omitempty"`
|
||||
Proxies []Proxy `yaml:"proxies,omitempty"`
|
||||
Proxies []proxy.Proxy `yaml:"proxies,omitempty"`
|
||||
ProxyGroups []ProxyGroup `yaml:"proxy-groups,omitempty"`
|
||||
Rules []string `yaml:"rules,omitempty"`
|
||||
SubRules map[string][]string `yaml:"sub-rules,omitempty"`
|
Reference in New Issue
Block a user