diff --git a/.gitignore b/.gitignore index e56a728..9f8a715 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .vscode -dist \ No newline at end of file +dist +*test.go \ No newline at end of file diff --git a/cmd/convert.go b/cmd/convert.go new file mode 100644 index 0000000..f71cf2c --- /dev/null +++ b/cmd/convert.go @@ -0,0 +1,202 @@ +package cmd + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "os" + "strings" + "sub2sing-box/constant" + "sub2sing-box/model" + . "sub2sing-box/util" + + "github.com/spf13/cobra" +) + +var convertCmd = &cobra.Command{ + Use: "convert", + Long: "Convert common proxy format to json", + Short: "Convert common proxy format to json", + Run: func(cmd *cobra.Command, args []string) { + subscriptions, _ := cmd.Flags().GetStringSlice("subscription") + proxies, _ := cmd.Flags().GetStringSlice("proxy") + template, _ := cmd.Flags().GetString("template") + if template == "" { + result, err := ConvertSubscriptionsToJson(subscriptions) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(result) + } else { + config, err := ConvertWithTemplate(subscriptions, proxies, template) + if err != nil { + fmt.Println(err) + return + } + data, err := json.Marshal(config) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(string(data)) + } + }, +} + +func init() { + convertCmd.Flags().StringSliceP("subscription", "s", []string{}, "subscription urls") + convertCmd.Flags().StringSliceP("proxy", "p", []string{}, "common proxies") + convertCmd.Flags().StringP("template", "t", "", "path of template file") + RootCmd.AddCommand(convertCmd) +} + +func Convert(urls []string, proxies []string) ([]model.Proxy, error) { + proxyList := make([]model.Proxy, 0) + newProxies, err := ConvertSubscriptionsToSProxy(urls) + if err != nil { + return nil, err + } + proxyList = append(proxyList, newProxies...) + for _, p := range proxies { + proxy, err := ConvertCProxyToSProxy(p) + if err != nil { + return nil, err + } + proxyList = append(proxyList, proxy) + } + return proxyList, nil +} + +func ConvertWithTemplate(urls []string, proxies []string, template string) (model.Config, error) { + proxyList := make([]model.Proxy, 0) + newProxies, err := ConvertSubscriptionsToSProxy(urls) + if err != nil { + return model.Config{}, err + } + proxyList = append(proxyList, newProxies...) + for _, p := range proxies { + proxy, err := ConvertCProxyToSProxy(p) + if err != nil { + return model.Config{}, err + } + proxyList = append(proxyList, proxy) + } + config, err := ReadTemplate(template) + if err != nil { + return model.Config{}, err + } + ps, err := json.Marshal(proxyList) + if err != nil { + return model.Config{}, err + } + var newOutbounds []model.Outbound + err = json.Unmarshal(ps, &newOutbounds) + if err != nil { + return model.Config{}, err + } + config.Outbounds = append(config.Outbounds, newOutbounds...) + return config, nil +} + +func ConvertCProxyToSProxy(proxy string) (model.Proxy, error) { + for prefix, parseFunc := range constant.ParserMap { + if strings.HasPrefix(proxy, prefix) { + proxy, err := parseFunc(proxy) + if err != nil { + return model.Proxy{}, err + } + return proxy, nil + } + } + return model.Proxy{}, errors.New("Unknown proxy format") +} + +func ConvertCProxyToJson(proxy string) (string, error) { + sProxy, err := ConvertCProxyToSProxy(proxy) + if err != nil { + return "", err + } + data, err := json.Marshal(&sProxy) + if err != nil { + return "", err + } + return string(data), nil +} + +func FetchSubscription(url string, maxRetryTime int) (string, error) { + retryTime := 0 + var err error + for retryTime < maxRetryTime { + resp, err := http.Get(url) + if err != nil { + fmt.Println(err) + retryTime++ + continue + } + data, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Println(err) + retryTime++ + continue + } + return string(data), err + } + return "", err +} + +func ConvertSubscriptionsToSProxy(urls []string) ([]model.Proxy, error) { + proxyList := make([]model.Proxy, 0) + for _, url := range urls { + data, err := FetchSubscription(url, 3) + if err != nil { + fmt.Println(err) + return nil, err + } + proxy, err := DecodeBase64(data) + if err != nil { + fmt.Println(err) + return nil, err + } + proxies := strings.Split(proxy, "\n") + for _, p := range proxies { + for prefix, parseFunc := range constant.ParserMap { + if strings.HasPrefix(p, prefix) { + proxy, err := parseFunc(p) + if err != nil { + return nil, err + } + proxyList = append(proxyList, proxy) + } + } + } + } + return proxyList, nil +} + +func ConvertSubscriptionsToJson(urls []string) (string, error) { + proxyList, err := ConvertSubscriptionsToSProxy(urls) + if err != nil { + return "", err + } + result, err := json.Marshal(proxyList) + if err != nil { + return "", err + } + return string(result), nil +} + +func ReadTemplate(path string) (model.Config, error) { + data, err := os.ReadFile(path) + if err != nil { + return model.Config{}, err + } + var res model.Config + err = json.Unmarshal(data, &res) + if err != nil { + return model.Config{}, err + } + return res, nil +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..a62c8db --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,8 @@ +package cmd + +import "github.com/spf13/cobra" + +var RootCmd = &cobra.Command{} + +func init() { +} diff --git a/cmd/url.go b/cmd/url.go deleted file mode 100644 index 5fd9db7..0000000 --- a/cmd/url.go +++ /dev/null @@ -1,87 +0,0 @@ -package cmd - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - "sub2sing-box/model" - "sub2sing-box/parser" - . "sub2sing-box/util" - - "github.com/spf13/cobra" -) - -func Url(cmd *cobra.Command, args []string) { - proxyList := make([]model.Proxy, 0) - if cmd.Flag("url").Changed { - urls, _ := cmd.Flags().GetStringSlice("url") - for _, url := range urls { - resp, err := http.Get(url) - if err != nil { - fmt.Println(err) - return - } - data, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Println(err) - return - } - proxy, err := DecodeBase64(string(data)) - if err != nil { - fmt.Println(err) - return - } - proxies := strings.Split(proxy, "\n") - for _, p := range proxies { - if strings.HasPrefix(p, "ss://") { - proxy, err := parser.ParseShadowsocks(p) - if err != nil { - fmt.Println(proxy) - } - proxyList = append(proxyList, proxy) - } else if strings.HasPrefix(p, "vmess://") { - proxy, err := parser.ParseVmess(p) - if err != nil { - fmt.Println(proxy) - } - proxyList = append(proxyList, proxy) - } else if strings.HasPrefix(p, "trojan://") { - proxy, err := parser.ParseTrojan(p) - if err != nil { - fmt.Println(proxy) - } - proxyList = append(proxyList, proxy) - } else if strings.HasPrefix(p, "vless://") { - proxy, err := parser.ParseVless(p) - if err != nil { - fmt.Println(proxy) - } - proxyList = append(proxyList, proxy) - } else if strings.HasPrefix(p, "hysteria://") { - proxy, err := parser.ParseHysteria(p) - if err != nil { - fmt.Println(proxy) - } - proxyList = append(proxyList, proxy) - } else if strings.HasPrefix(p, "hy2://") || strings.HasPrefix(p, "hysteria2://") { - proxy, err := parser.ParseHysteria2(p) - if err != nil { - fmt.Println(proxy) - } - proxyList = append(proxyList, proxy) - } - } - } - result, err := json.Marshal(proxyList) - if err != nil { - fmt.Println(err) - return - } else { - fmt.Println(string(result)) - } - } else { - fmt.Println("No URLs provided") - } -} diff --git a/constant/parsers_map.go b/constant/parsers_map.go new file mode 100644 index 0000000..437c92c --- /dev/null +++ b/constant/parsers_map.go @@ -0,0 +1,16 @@ +package constant + +import ( + "sub2sing-box/model" + "sub2sing-box/parser" +) + +var ParserMap map[string]func(string) (model.Proxy, error) = map[string]func(string) (model.Proxy, error){ + "ss://": parser.ParseShadowsocks, + "vmess://": parser.ParseVmess, + "trojan://": parser.ParseTrojan, + "vless://": parser.ParseVless, + "hysteria://": parser.ParseHysteria, + "hy2://": parser.ParseHysteria2, + "hysteria2://": parser.ParseHysteria2, +} diff --git a/main.go b/main.go index 98cfc41..408dbce 100644 --- a/main.go +++ b/main.go @@ -3,21 +3,10 @@ package main import ( "fmt" "sub2sing-box/cmd" - - "github.com/spf13/cobra" ) -var rootCmd = &cobra.Command{ - Use: "process", - Run: cmd.Url, -} - -func init() { - rootCmd.Flags().StringSliceP("url", "u", []string{}, "URLs to process") -} - func main() { - if err := rootCmd.Execute(); err != nil { + if err := cmd.RootCmd.Execute(); err != nil { fmt.Println(err) } } diff --git a/model/config.go b/model/config.go new file mode 100644 index 0000000..1a40dad --- /dev/null +++ b/model/config.go @@ -0,0 +1,379 @@ +package model + +type Config struct { + Log *LogOptions `json:"log,omitempty"` + DNS *DNSOptions `json:"dns,omitempty"` + NTP *NTPOptions `json:"ntp,omitempty"` + Inbounds []Inbound `json:"inbounds,omitempty"` + Outbounds []Outbound `json:"outbounds,omitempty"` + Route *RouteOptions `json:"route,omitempty"` + Experimental *ExperimentalOptions `json:"experimental,omitempty"` +} + +type LogOptions struct { + Disabled bool `json:"disabled,omitempty"` + Level string `json:"level,omitempty"` + Output string `json:"output,omitempty"` + Timestamp bool `json:"timestamp,omitempty"` +} + +type DNSOptions struct { + Servers []DNSServerOptions `json:"servers,omitempty"` + Rules []DNSRule `json:"rules,omitempty"` + Final string `json:"final,omitempty"` + ReverseMapping bool `json:"reverse_mapping,omitempty"` + FakeIP *DNSFakeIPOptions `json:"fakeip,omitempty"` + Strategy string `json:"strategy,omitempty"` + DisableCache bool `json:"disable_cache,omitempty"` + DisableExpire bool `json:"disable_expire,omitempty"` + IndependentCache bool `json:"independent_cache,omitempty"` + ClientSubnet string `json:"client_subnet,omitempty"` +} + +type DNSServerOptions struct { + Tag string `json:"tag,omitempty"` + Address string `json:"address"` + AddressResolver string `json:"address_resolver,omitempty"` + AddressStrategy string `json:"address_strategy,omitempty"` + Strategy string `json:"strategy,omitempty"` + Detour string `json:"detour,omitempty"` + ClientSubnet string `json:"client_subnet,omitempty"` +} + +type DNSRule struct { + Type string `json:"type,omitempty"` + Inbound []string `json:"inbound,omitempty"` + IPVersion int `json:"ip_version,omitempty"` + QueryType []string `json:"query_type,omitempty"` + Network []string `json:"network,omitempty"` + AuthUser []string `json:"auth_user,omitempty"` + Protocol []string `json:"protocol,omitempty"` + Domain []string `json:"domain,omitempty"` + DomainSuffix []string `json:"domain_suffix,omitempty"` + DomainKeyword []string `json:"domain_keyword,omitempty"` + DomainRegex []string `json:"domain_regex,omitempty"` + Geosite []string `json:"geosite,omitempty"` + SourceGeoIP []string `json:"source_geoip,omitempty"` + GeoIP []string `json:"geoip,omitempty"` + IPCIDR []string `json:"ip_cidr,omitempty"` + IPIsPrivate bool `json:"ip_is_private,omitempty"` + SourceIPCIDR []string `json:"source_ip_cidr,omitempty"` + SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"` + SourcePort []uint16 `json:"source_port,omitempty"` + SourcePortRange []string `json:"source_port_range,omitempty"` + Port []uint16 `json:"port,omitempty"` + PortRange []string `json:"port_range,omitempty"` + ProcessName []string `json:"process_name,omitempty"` + ProcessPath []string `json:"process_path,omitempty"` + PackageName []string `json:"package_name,omitempty"` + User []string `json:"user,omitempty"` + UserID []int32 `json:"user_id,omitempty"` + Outbound []string `json:"outbound,omitempty"` + ClashMode string `json:"clash_mode,omitempty"` + WIFISSID []string `json:"wifi_ssid,omitempty"` + WIFIBSSID []string `json:"wifi_bssid,omitempty"` + RuleSet []string `json:"rule_set,omitempty"` + RuleSetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"` + Invert bool `json:"invert,omitempty"` + Server string `json:"server,omitempty"` + DisableCache bool `json:"disable_cache,omitempty"` + RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"` + ClientSubnet string `json:"client_subnet,omitempty"` + Mode string `json:"mode"` + Rules []DNSRule `json:"rules,omitempty"` +} + +type DNSFakeIPOptions struct { + Enabled bool `json:"enabled,omitempty"` + Inet4Range string `json:"inet4_range,omitempty"` + Inet6Range string `json:"inet6_range,omitempty"` +} + +type NTPOptions struct { + Enabled bool `json:"enabled,omitempty"` + Server string `json:"server,omitempty"` + ServerPort uint16 `json:"server_port,omitempty"` + Interval string `json:"interval,omitempty"` + WriteToSystem bool `json:"write_to_system,omitempty"` + Detour string `json:"detour,omitempty"` + BindInterface string `json:"bind_interface,omitempty"` + Inet4BindAddress string `json:"inet4_bind_address,omitempty"` + Inet6BindAddress string `json:"inet6_bind_address,omitempty"` + ProtectPath string `json:"protect_path,omitempty"` + RoutingMark int `json:"routing_mark,omitempty"` + ReuseAddr bool `json:"reuse_addr,omitempty"` + ConnectTimeout string `json:"connect_timeout,omitempty"` + TCPFastOpen bool `json:"tcp_fast_open,omitempty"` + TCPMultiPath bool `json:"tcp_multi_path,omitempty"` + UDPFragment bool `json:"udp_fragment,omitempty"` + DomainStrategy string `json:"domain_strategy,omitempty"` + FallbackDelay string `json:"fallback_delay,omitempty"` +} + +type Inbound struct { + Type string `json:"type"` + Tag string `json:"tag,omitempty"` + InterfaceName string `json:"interface_name,omitempty"` + MTU uint32 `json:"mtu,omitempty"` + GSO bool `json:"gso,omitempty"` + Inet4Address []string `json:"inet4_address,omitempty"` + Inet6Address []string `json:"inet6_address,omitempty"` + AutoRoute bool `json:"auto_route,omitempty"` + StrictRoute bool `json:"strict_route,omitempty"` + Inet4RouteAddress []string `json:"inet4_route_address,omitempty"` + Inet6RouteAddress []string `json:"inet6_route_address,omitempty"` + Inet4RouteExcludeAddress []string `json:"inet4_route_exclude_address,omitempty"` + Inet6RouteExcludeAddress []string `json:"inet6_route_exclude_address,omitempty"` + IncludeInterface []string `json:"include_interface,omitempty"` + ExcludeInterface []string `json:"exclude_interface,omitempty"` + IncludeUID []uint32 `json:"include_uid,omitempty"` + IncludeUIDRange []string `json:"include_uid_range,omitempty"` + ExcludeUID []uint32 `json:"exclude_uid,omitempty"` + ExcludeUIDRange []string `json:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `json:"include_android_user,omitempty"` + IncludePackage []string `json:"include_package,omitempty"` + ExcludePackage []string `json:"exclude_package,omitempty"` + EndpointIndependentNat bool `json:"endpoint_independent_nat,omitempty"` + UDPTimeout string `json:"udp_timeout,omitempty"` + Stack string `json:"stack,omitempty"` + Platform *TunPlatformOptions `json:"platform,omitempty"` + SniffEnabled bool `json:"sniff,omitempty"` + SniffOverrideDestination bool `json:"sniff_override_destination,omitempty"` + SniffTimeout string `json:"sniff_timeout,omitempty"` + DomainStrategy string `json:"domain_strategy,omitempty"` + UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"` +} + +type TunPlatformOptions struct { + HTTPProxy *HTTPProxyOptions `json:"http_proxy,omitempty"` +} + +type HTTPProxyOptions struct { + Enabled bool `json:"enabled,omitempty"` + Server string `json:"server"` + ServerPort uint16 `json:"server_port"` + BypassDomain []string `json:"bypass_domain,omitempty"` + MatchDomain []string `json:"match_domain,omitempty"` +} + +type Outbound struct { + Type string `json:"type"` + Tag string `json:"tag,omitempty"` + Detour string `json:"detour,omitempty"` + BindInterface string `json:"bind_interface,omitempty"` + Inet4BindAddress string `json:"inet4_bind_address,omitempty"` + Inet6BindAddress string `json:"inet6_bind_address,omitempty"` + ProtectPath string `json:"protect_path,omitempty"` + RoutingMark int `json:"routing_mark,omitempty"` + ReuseAddr bool `json:"reuse_addr,omitempty"` + ConnectTimeout string `json:"connect_timeout,omitempty"` + TCPFastOpen bool `json:"tcp_fast_open,omitempty"` + TCPMultiPath bool `json:"tcp_multi_path,omitempty"` + UDPFragment *bool `json:"udp_fragment,omitempty"` + DomainStrategy string `json:"domain_strategy,omitempty"` + FallbackDelay string `json:"fallback_delay,omitempty"` + OverrideAddress string `json:"override_address,omitempty"` + OverridePort uint16 `json:"override_port,omitempty"` + ProxyProtocol uint8 `json:"proxy_protocol,omitempty"` + Server string `json:"server"` + ServerPort uint16 `json:"server_port"` + Version string `json:"version,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Network string `json:"network,omitempty"` + UDPOverTCP *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"` + TLS *OutboundTLSOptions `json:"tls,omitempty"` + Path string `json:"path,omitempty"` + Headers map[string][]string `json:"headers,omitempty"` + Method string `json:"method"` + Plugin string `json:"plugin,omitempty"` + PluginOptions string `json:"plugin_opts,omitempty"` + Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"` + UUID string `json:"uuid"` + Security string `json:"security"` + AlterId int `json:"alter_id,omitempty"` + GlobalPadding bool `json:"global_padding,omitempty"` + AuthenticatedLength bool `json:"authenticated_length,omitempty"` + PacketEncoding string `json:"packet_encoding,omitempty"` + Transport *V2RayTransportOptions `json:"transport,omitempty"` + SystemInterface bool `json:"system_interface,omitempty"` + GSO bool `json:"gso,omitempty"` + InterfaceName string `json:"interface_name,omitempty"` + LocalAddress []string `json:"local_address"` + PrivateKey string `json:"private_key"` + Peers []WireGuardPeer `json:"peers,omitempty"` + PeerPublicKey string `json:"peer_public_key"` + PreSharedKey string `json:"pre_shared_key,omitempty"` + Reserved []uint8 `json:"reserved,omitempty"` + Workers int `json:"workers,omitempty"` + MTU uint32 `json:"mtu,omitempty"` + Up string `json:"up,omitempty"` + UpMbps int `json:"up_mbps,omitempty"` + Down string `json:"down,omitempty"` + DownMbps int `json:"down_mbps,omitempty"` + Obfs struct { + string + *Hysteria2Obfs + } `json:"obfs,omitempty"` + Auth []byte `json:"auth,omitempty"` + AuthString string `json:"auth_str,omitempty"` + ReceiveWindowConn uint64 `json:"recv_window_conn,omitempty"` + ReceiveWindow uint64 `json:"recv_window,omitempty"` + DisableMTUDiscovery bool `json:"disable_mtu_discovery,omitempty"` + ExecutablePath string `json:"executable_path,omitempty"` + ExtraArgs []string `json:"extra_args,omitempty"` + DataDirectory string `json:"data_directory,omitempty"` + Options map[string]string `json:"torrc,omitempty"` + User string `json:"user,omitempty"` + PrivateKeyPath string `json:"private_key_path,omitempty"` + PrivateKeyPassphrase string `json:"private_key_passphrase,omitempty"` + HostKey []string `json:"host_key,omitempty"` + HostKeyAlgorithms []string `json:"host_key_algorithms,omitempty"` + ClientVersion string `json:"client_version,omitempty"` + ObfsParam string `json:"obfs_param,omitempty"` + Protocol string `json:"protocol,omitempty"` + ProtocolParam string `json:"protocol_param,omitempty"` + Flow string `json:"flow,omitempty"` + CongestionControl string `json:"congestion_control,omitempty"` + UDPRelayMode string `json:"udp_relay_mode,omitempty"` + UDPOverStream bool `json:"udp_over_stream,omitempty"` + ZeroRTTHandshake bool `json:"zero_rtt_handshake,omitempty"` + Heartbeat string `json:"heartbeat,omitempty"` + BrutalDebug bool `json:"brutal_debug,omitempty"` + Default string `json:"default,omitempty"` + Outbounds []string `json:"outbounds"` + URL string `json:"url,omitempty"` + Interval string `json:"interval,omitempty"` + Tolerance uint16 `json:"tolerance,omitempty"` + IdleTimeout string `json:"idle_timeout,omitempty"` + InterruptExistConnections bool `json:"interrupt_exist_connections,omitempty"` +} + +type WireGuardPeer struct { + Server string `json:"server"` + ServerPort uint16 `json:"server_port"` + PublicKey string `json:"public_key,omitempty"` + PreSharedKey string `json:"pre_shared_key,omitempty"` + AllowedIPs []string `json:"allowed_ips,omitempty"` + Reserved []uint8 `json:"reserved,omitempty"` +} + +type RouteOptions struct { + GeoIP *GeoIPOptions `json:"geoip,omitempty"` + Geosite *GeositeOptions `json:"geosite,omitempty"` + Rules []Rule `json:"rules,omitempty"` + RuleSet []RuleSet `json:"rule_set,omitempty"` + Final string `json:"final,omitempty"` + FindProcess bool `json:"find_process,omitempty"` + AutoDetectInterface bool `json:"auto_detect_interface,omitempty"` + OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"` + DefaultInterface string `json:"default_interface,omitempty"` + DefaultMark int `json:"default_mark,omitempty"` +} + +type Rule struct { + Type string `json:"type,omitempty"` + Inbound []string `json:"inbound,omitempty"` + IPVersion int `json:"ip_version,omitempty"` + Network []string `json:"network,omitempty"` + AuthUser []string `json:"auth_user,omitempty"` + Protocol []string `json:"protocol,omitempty"` + Domain []string `json:"domain,omitempty"` + DomainSuffix []string `json:"domain_suffix,omitempty"` + DomainKeyword []string `json:"domain_keyword,omitempty"` + DomainRegex []string `json:"domain_regex,omitempty"` + Geosite []string `json:"geosite,omitempty"` + SourceGeoIP []string `json:"source_geoip,omitempty"` + GeoIP []string `json:"geoip,omitempty"` + SourceIPCIDR []string `json:"source_ip_cidr,omitempty"` + SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"` + IPCIDR []string `json:"ip_cidr,omitempty"` + IPIsPrivate bool `json:"ip_is_private,omitempty"` + SourcePort []uint16 `json:"source_port,omitempty"` + SourcePortRange []string `json:"source_port_range,omitempty"` + Port []uint16 `json:"port,omitempty"` + PortRange []string `json:"port_range,omitempty"` + ProcessName []string `json:"process_name,omitempty"` + ProcessPath []string `json:"process_path,omitempty"` + PackageName []string `json:"package_name,omitempty"` + User []string `json:"user,omitempty"` + UserID []int32 `json:"user_id,omitempty"` + ClashMode string `json:"clash_mode,omitempty"` + WIFISSID []string `json:"wifi_ssid,omitempty"` + WIFIBSSID []string `json:"wifi_bssid,omitempty"` + RuleSet []string `json:"rule_set,omitempty"` + RuleSetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"` + Invert bool `json:"invert,omitempty"` + Outbound string `json:"outbound,omitempty"` + Mode string `json:"mode"` + Rules []Rule `json:"rules,omitempty"` +} + +type GeoIPOptions struct { + Path string `json:"path,omitempty"` + DownloadURL string `json:"download_url,omitempty"` + DownloadDetour string `json:"download_detour,omitempty"` +} + +type GeositeOptions struct { + Path string `json:"path,omitempty"` + DownloadURL string `json:"download_url,omitempty"` + DownloadDetour string `json:"download_detour,omitempty"` +} + +type RuleSet struct { + Type string `json:"type"` + Tag string `json:"tag"` + Format string `json:"format"` + Path string `json:"path,omitempty"` + URL string `json:"url"` + DownloadDetour string `json:"download_detour,omitempty"` + UpdateInterval string `json:"update_interval,omitempty"` +} + +type ExperimentalOptions struct { + CacheFile *CacheFileOptions `json:"cache_file,omitempty"` + ClashAPI *ClashAPIOptions `json:"clash_api,omitempty"` + V2RayAPI *V2RayAPIOptions `json:"v2ray_api,omitempty"` +} + +type CacheFileOptions struct { + Enabled bool `json:"enabled,omitempty"` + Path string `json:"path,omitempty"` + CacheID string `json:"cache_id,omitempty"` + StoreFakeIP bool `json:"store_fakeip,omitempty"` + StoreRDRC bool `json:"store_rdrc,omitempty"` + RDRCTimeout string `json:"rdrc_timeout,omitempty"` +} + +type ClashAPIOptions struct { + ExternalController string `json:"external_controller,omitempty"` + ExternalUI string `json:"external_ui,omitempty"` + ExternalUIDownloadURL string `json:"external_ui_download_url,omitempty"` + ExternalUIDownloadDetour string `json:"external_ui_download_detour,omitempty"` + Secret string `json:"secret,omitempty"` + DefaultMode string `json:"default_mode,omitempty"` + + // Deprecated: migrated to global cache file + CacheFile string `json:"cache_file,omitempty"` + // Deprecated: migrated to global cache file + CacheID string `json:"cache_id,omitempty"` + // Deprecated: migrated to global cache file + StoreMode bool `json:"store_mode,omitempty"` + // Deprecated: migrated to global cache file + StoreSelected bool `json:"store_selected,omitempty"` + // Deprecated: migrated to global cache file + StoreFakeIP bool `json:"store_fakeip,omitempty"` +} + +type V2RayAPIOptions struct { + Listen string `json:"listen,omitempty"` + Stats *V2RayStatsServiceOptions `json:"stats,omitempty"` +} + +type V2RayStatsServiceOptions struct { + Enabled bool `json:"enabled,omitempty"` + Inbounds []string `json:"inbounds,omitempty"` + Outbounds []string `json:"outbounds,omitempty"` + Users []string `json:"users,omitempty"` +} diff --git a/model/shadowsocks.go b/model/shadowsocks.go index 6cf6824..bc9e0af 100644 --- a/model/shadowsocks.go +++ b/model/shadowsocks.go @@ -1,7 +1,5 @@ package model -type NetworkList string - type Shadowsocks struct { Tag string `json:"tag,omitempty"` Server string `json:"server"` diff --git a/model/tuic.go b/model/tuic.go index 5fcf8b4..c17854e 100644 --- a/model/tuic.go +++ b/model/tuic.go @@ -11,7 +11,7 @@ type TUIC struct { UDPRelayMode string `json:"udp_relay_mode,omitempty"` UDPOverStream bool `json:"udp_over_stream,omitempty"` ZeroRTTHandshake bool `json:"zero_rtt_handshake,omitempty"` - Heartbeat Duration `json:"heartbeat,omitempty"` + Heartbeat string `json:"heartbeat,omitempty"` Network string `json:"network,omitempty"` TLS *OutboundTLSOptions `json:"tls,omitempty"` } diff --git a/model/types.go b/model/types.go deleted file mode 100644 index 6f36009..0000000 --- a/model/types.go +++ /dev/null @@ -1,5 +0,0 @@ -package model - -import "time" - -type Duration time.Duration diff --git a/model/v2ray_transport.go b/model/v2ray_transport.go index 3488e8c..2b9ea80 100644 --- a/model/v2ray_transport.go +++ b/model/v2ray_transport.go @@ -57,8 +57,8 @@ type V2RayHTTPOptions struct { Path string `json:"path,omitempty"` Method string `json:"method,omitempty"` Headers map[string]string `json:"headers,omitempty"` - IdleTimeout Duration `json:"idle_timeout,omitempty"` - PingTimeout Duration `json:"ping_timeout,omitempty"` + IdleTimeout string `json:"idle_timeout,omitempty"` + PingTimeout string `json:"ping_timeout,omitempty"` } type V2RayWebsocketOptions struct { @@ -71,11 +71,11 @@ type V2RayWebsocketOptions struct { type V2RayQUICOptions struct{} type V2RayGRPCOptions struct { - ServiceName string `json:"service_name,omitempty"` - IdleTimeout Duration `json:"idle_timeout,omitempty"` - PingTimeout Duration `json:"ping_timeout,omitempty"` - PermitWithoutStream bool `json:"permit_without_stream,omitempty"` - ForceLite bool `json:"-"` // for test + ServiceName string `json:"service_name,omitempty"` + IdleTimeout string `json:"idle_timeout,omitempty"` + PingTimeout string `json:"ping_timeout,omitempty"` + PermitWithoutStream bool `json:"permit_without_stream,omitempty"` + ForceLite bool `json:"-"` // for test } type V2RayHTTPUpgradeOptions struct { diff --git a/parser/vmess.go b/parser/vmess.go index d7afde0..d5ec23f 100644 --- a/parser/vmess.go +++ b/parser/vmess.go @@ -61,7 +61,6 @@ func ParseVmess(proxy string) (model.Proxy, error) { UUID: vmess.Id, AlterId: aid, Security: vmess.Scy, - Network: vmess.Net, }, }