Update On Thu Nov 6 19:42:18 CET 2025

This commit is contained in:
github-action[bot]
2025-11-06 19:42:18 +01:00
parent 4a37a53ca8
commit f7290fe662
95 changed files with 1936 additions and 1084 deletions
+1
View File
@@ -1173,3 +1173,4 @@ Update On Sun Nov 2 19:34:13 CET 2025
Update On Mon Nov 3 19:37:13 CET 2025
Update On Tue Nov 4 19:40:23 CET 2025
Update On Wed Nov 5 19:38:37 CET 2025
Update On Thu Nov 6 19:42:10 CET 2025
+2 -2
View File
@@ -10,7 +10,7 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
type Fallback struct {
@@ -150,7 +150,7 @@ func (f *Fallback) ForceSet(name string) {
f.selected = name
}
func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallback {
return &Fallback{
GroupBase: NewGroupBase(GroupBaseOption{
Name: option.Name,
@@ -12,8 +12,7 @@ import (
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/tunnel"
@@ -26,7 +25,7 @@ type GroupBase struct {
filterRegs []*regexp2.Regexp
excludeFilterRegs []*regexp2.Regexp
excludeTypeArray []string
providers []provider.ProxyProvider
providers []P.ProxyProvider
failedTestMux sync.Mutex
failedTimes int
failedTime time.Time
@@ -48,7 +47,7 @@ type GroupBaseOption struct {
ExcludeType string
TestTimeout int
MaxFailedTimes int
Providers []provider.ProxyProvider
Providers []P.ProxyProvider
}
func NewGroupBase(opt GroupBaseOption) *GroupBase {
@@ -125,7 +124,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
}
} else {
for _, pd := range gb.providers {
if pd.VehicleType() == types.Compatible { // compatible provider unneeded filter
if pd.VehicleType() == P.Compatible { // compatible provider unneeded filter
proxies = append(proxies, pd.Proxies()...)
continue
}
@@ -14,7 +14,7 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"golang.org/x/net/publicsuffix"
)
@@ -239,7 +239,7 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
})
}
func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvider, strategy string) (lb *LoadBalance, err error) {
func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, strategy string) (lb *LoadBalance, err error) {
var strategyFn strategyFn
switch strategy {
case "consistent-hashing":
+8 -8
View File
@@ -11,7 +11,7 @@ import (
"github.com/metacubex/mihomo/common/structure"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
)
@@ -48,7 +48,7 @@ type GroupCommonOption struct {
RoutingMark int `group:"routing-mark,omitempty"`
}
func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider, AllProxies []string, AllProviders []string) (C.ProxyAdapter, error) {
func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]P.ProxyProvider, AllProxies []string, AllProviders []string) (C.ProxyAdapter, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "group", WeaklyTypedInput: true})
groupOption := &GroupCommonOption{
@@ -71,7 +71,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
groupName := groupOption.Name
providers := []types.ProxyProvider{}
providers := []P.ProxyProvider{}
if groupOption.IncludeAll {
groupOption.IncludeAllProviders = true
@@ -169,7 +169,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
return nil, fmt.Errorf("%s: %w", groupName, err)
}
providers = append([]types.ProxyProvider{pd}, providers...)
providers = append([]P.ProxyProvider{pd}, providers...)
providersMap[groupName] = pd
}
@@ -206,15 +206,15 @@ func getProxies(mapping map[string]C.Proxy, list []string) ([]C.Proxy, error) {
return ps, nil
}
func getProviders(mapping map[string]types.ProxyProvider, list []string) ([]types.ProxyProvider, error) {
var ps []types.ProxyProvider
func getProviders(mapping map[string]P.ProxyProvider, list []string) ([]P.ProxyProvider, error) {
var ps []P.ProxyProvider
for _, name := range list {
p, ok := mapping[name]
if !ok {
return nil, fmt.Errorf("'%s' not found", name)
}
if p.VehicleType() == types.Compatible {
if p.VehicleType() == P.Compatible {
return nil, fmt.Errorf("proxy group %s can't contains in `use`", name)
}
ps = append(ps, p)
@@ -222,7 +222,7 @@ func getProviders(mapping map[string]types.ProxyProvider, list []string) ([]type
return ps, nil
}
func addTestUrlToProviders(providers []types.ProxyProvider, url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) {
func addTestUrlToProviders(providers []P.ProxyProvider, url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) {
if len(providers) == 0 || len(url) == 0 {
return
}
@@ -4,22 +4,22 @@ package outboundgroup
import (
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
type ProxyGroup interface {
C.ProxyAdapter
Providers() []provider.ProxyProvider
Providers() []P.ProxyProvider
Proxies() []C.Proxy
Now() string
}
func (f *Fallback) Providers() []provider.ProxyProvider {
func (f *Fallback) Providers() []P.ProxyProvider {
return f.providers
}
func (lb *LoadBalance) Providers() []provider.ProxyProvider {
func (lb *LoadBalance) Providers() []P.ProxyProvider {
return lb.providers
}
@@ -35,7 +35,7 @@ func (lb *LoadBalance) Now() string {
return ""
}
func (r *Relay) Providers() []provider.ProxyProvider {
func (r *Relay) Providers() []P.ProxyProvider {
return r.providers
}
@@ -47,7 +47,7 @@ func (r *Relay) Now() string {
return ""
}
func (s *Selector) Providers() []provider.ProxyProvider {
func (s *Selector) Providers() []P.ProxyProvider {
return s.providers
}
@@ -55,7 +55,7 @@ func (s *Selector) Proxies() []C.Proxy {
return s.GetProxies(false)
}
func (u *URLTest) Providers() []provider.ProxyProvider {
func (u *URLTest) Providers() []P.ProxyProvider {
return u.providers
}
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
)
@@ -149,7 +149,7 @@ func (r *Relay) Addr() string {
return proxies[len(proxies)-1].Addr()
}
func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
func NewRelay(option *GroupCommonOption, providers []P.ProxyProvider) *Relay {
log.Warnln("The group [%s] with relay type is deprecated, please using dialer-proxy instead", option.Name)
return &Relay{
GroupBase: NewGroupBase(GroupBaseOption{
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"errors"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
type Selector struct {
@@ -108,7 +108,7 @@ func (s *Selector) selectedProxy(touch bool) C.Proxy {
return proxies[0]
}
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Selector {
return &Selector{
GroupBase: NewGroupBase(GroupBaseOption{
Name: option.Name,
+2 -2
View File
@@ -11,7 +11,7 @@ import (
"github.com/metacubex/mihomo/common/singledo"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
type urlTestOption func(*URLTest)
@@ -202,7 +202,7 @@ func parseURLTestOption(config map[string]any) []urlTestOption {
return opts
}
func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, options ...urlTestOption) *URLTest {
func NewURLTest(option *GroupCommonOption, providers []P.ProxyProvider, options ...urlTestOption) *URLTest {
urlTest := &URLTest{
GroupBase: NewGroupBase(GroupBaseOption{
Name: option.Name,
+3 -3
View File
@@ -10,7 +10,7 @@ import (
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/resource"
C "github.com/metacubex/mihomo/constant"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/dlclark/regexp2"
)
@@ -73,7 +73,7 @@ type proxyProviderSchema struct {
Header map[string][]string `provider:"header,omitempty"`
}
func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) {
func ParseProxyProvider(name string, mapping map[string]any) (P.ProxyProvider, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
schema := &proxyProviderSchema{
@@ -104,7 +104,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
return nil, err
}
var vehicle types.Vehicle
var vehicle P.Vehicle
switch schema.Type {
case "file":
path := C.Path.Resolve(schema.Path)
+8 -8
View File
@@ -16,7 +16,7 @@ import (
"github.com/metacubex/mihomo/component/profile/cachefile"
"github.com/metacubex/mihomo/component/resource"
C "github.com/metacubex/mihomo/constant"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/tunnel/statistic"
"github.com/dlclark/regexp2"
@@ -68,8 +68,8 @@ func (bp *baseProvider) HealthCheck() {
bp.healthCheck.check()
}
func (bp *baseProvider) Type() types.ProviderType {
return types.Proxy
func (bp *baseProvider) Type() P.ProviderType {
return P.Proxy
}
func (bp *baseProvider) Proxies() []C.Proxy {
@@ -171,7 +171,7 @@ func (pp *proxySetProvider) Close() error {
return pp.Fetcher.Close()
}
func NewProxySetProvider(name string, interval time.Duration, payload []map[string]any, parser resource.Parser[[]C.Proxy], vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
func NewProxySetProvider(name string, interval time.Duration, payload []map[string]any, parser resource.Parser[[]C.Proxy], vehicle P.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
pd := &proxySetProvider{
baseProvider: baseProvider{
name: name,
@@ -238,8 +238,8 @@ func (ip *inlineProvider) MarshalJSON() ([]byte, error) {
})
}
func (ip *inlineProvider) VehicleType() types.VehicleType {
return types.Inline
func (ip *inlineProvider) VehicleType() P.VehicleType {
return P.Inline
}
func (ip *inlineProvider) Update() error {
@@ -303,8 +303,8 @@ func (cp *compatibleProvider) Update() error {
return nil
}
func (cp *compatibleProvider) VehicleType() types.VehicleType {
return types.Compatible
func (cp *compatibleProvider) VehicleType() P.VehicleType {
return P.Compatible
}
func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) {
+7 -7
View File
@@ -8,7 +8,7 @@ import (
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/slowdown"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/fswatch"
@@ -22,7 +22,7 @@ type Fetcher[V any] struct {
ctxCancel context.CancelFunc
resourceType string
name string
vehicle types.Vehicle
vehicle P.Vehicle
updatedAt time.Time
hash utils.HashType
parser Parser[V]
@@ -37,11 +37,11 @@ func (f *Fetcher[V]) Name() string {
return f.name
}
func (f *Fetcher[V]) Vehicle() types.Vehicle {
func (f *Fetcher[V]) Vehicle() P.Vehicle {
return f.vehicle
}
func (f *Fetcher[V]) VehicleType() types.VehicleType {
func (f *Fetcher[V]) VehicleType() P.VehicleType {
return f.vehicle.Type()
}
@@ -88,7 +88,7 @@ func (f *Fetcher[V]) Update() (V, bool, error) {
f.backoff.AddAttempt() // add a failed attempt to backoff
return lo.Empty[V](), false, err
}
return f.loadBuf(buf, hash, f.vehicle.Type() != types.File)
return f.loadBuf(buf, hash, f.vehicle.Type() != P.File)
}
func (f *Fetcher[V]) SideUpdate(buf []byte) (V, bool, error) {
@@ -180,7 +180,7 @@ func (f *Fetcher[V]) pullLoop(forceUpdate bool) {
func (f *Fetcher[V]) startPullLoop(forceUpdate bool) (err error) {
// pull contents automatically
if f.vehicle.Type() == types.File {
if f.vehicle.Type() == P.File {
f.watcher, err = fswatch.NewWatcher(fswatch.Options{
Path: []string{f.vehicle.Path()},
Callback: f.updateCallback,
@@ -218,7 +218,7 @@ func (f *Fetcher[V]) updateWithLog() {
return
}
func NewFetcher[V any](name string, interval time.Duration, vehicle types.Vehicle, parser Parser[V], onUpdate func(V)) *Fetcher[V] {
func NewFetcher[V any](name string, interval time.Duration, vehicle P.Vehicle, parser Parser[V], onUpdate func(V)) *Fetcher[V] {
ctx, cancel := context.WithCancel(context.Background())
minBackoff := 10 * time.Second
if interval < minBackoff {
+6 -6
View File
@@ -12,7 +12,7 @@ import (
"github.com/metacubex/mihomo/common/utils"
mihomoHttp "github.com/metacubex/mihomo/component/http"
"github.com/metacubex/mihomo/component/profile/cachefile"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
const (
@@ -50,8 +50,8 @@ type FileVehicle struct {
path string
}
func (f *FileVehicle) Type() types.VehicleType {
return types.File
func (f *FileVehicle) Type() P.VehicleType {
return P.File
}
func (f *FileVehicle) Path() string {
@@ -91,15 +91,15 @@ type HTTPVehicle struct {
timeout time.Duration
sizeLimit int64
inRead func(response *http.Response)
provider types.ProxyProvider
provider P.ProxyProvider
}
func (h *HTTPVehicle) Url() string {
return h.url
}
func (h *HTTPVehicle) Type() types.VehicleType {
return types.HTTP
func (h *HTTPVehicle) Type() P.VehicleType {
return P.HTTP
}
func (h *HTTPVehicle) Path() string {
+97 -96
View File
@@ -20,15 +20,15 @@ import (
"github.com/metacubex/mihomo/component/cidr"
"github.com/metacubex/mihomo/component/fakeip"
"github.com/metacubex/mihomo/component/geodata"
P "github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/component/sniffer"
"github.com/metacubex/mihomo/component/trie"
C "github.com/metacubex/mihomo/constant"
providerTypes "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
snifferTypes "github.com/metacubex/mihomo/constant/sniffer"
"github.com/metacubex/mihomo/dns"
L "github.com/metacubex/mihomo/listener"
"github.com/metacubex/mihomo/listener"
LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/log"
R "github.com/metacubex/mihomo/rules"
@@ -44,27 +44,27 @@ import (
// General config
type General struct {
Inbound
Mode T.TunnelMode `json:"mode"`
UnifiedDelay bool `json:"unified-delay"`
LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"`
Interface string `json:"interface-name"`
RoutingMark int `json:"routing-mark"`
GeoXUrl GeoXUrl `json:"geox-url"`
GeoAutoUpdate bool `json:"geo-auto-update"`
GeoUpdateInterval int `json:"geo-update-interval"`
GeodataMode bool `json:"geodata-mode"`
GeodataLoader string `json:"geodata-loader"`
GeositeMatcher string `json:"geosite-matcher"`
TCPConcurrent bool `json:"tcp-concurrent"`
FindProcessMode P.FindProcessMode `json:"find-process-mode"`
Sniffing bool `json:"sniffing"`
GlobalClientFingerprint string `json:"global-client-fingerprint"`
GlobalUA string `json:"global-ua"`
ETagSupport bool `json:"etag-support"`
KeepAliveIdle int `json:"keep-alive-idle"`
KeepAliveInterval int `json:"keep-alive-interval"`
DisableKeepAlive bool `json:"disable-keep-alive"`
Mode T.TunnelMode `json:"mode"`
UnifiedDelay bool `json:"unified-delay"`
LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"`
Interface string `json:"interface-name"`
RoutingMark int `json:"routing-mark"`
GeoXUrl GeoXUrl `json:"geox-url"`
GeoAutoUpdate bool `json:"geo-auto-update"`
GeoUpdateInterval int `json:"geo-update-interval"`
GeodataMode bool `json:"geodata-mode"`
GeodataLoader string `json:"geodata-loader"`
GeositeMatcher string `json:"geosite-matcher"`
TCPConcurrent bool `json:"tcp-concurrent"`
FindProcessMode process.FindProcessMode `json:"find-process-mode"`
Sniffing bool `json:"sniffing"`
GlobalClientFingerprint string `json:"global-client-fingerprint"`
GlobalUA string `json:"global-ua"`
ETagSupport bool `json:"etag-support"`
KeepAliveIdle int `json:"keep-alive-idle"`
KeepAliveInterval int `json:"keep-alive-interval"`
DisableKeepAlive bool `json:"disable-keep-alive"`
}
// Inbound config
@@ -199,8 +199,8 @@ type Config struct {
Users []auth.AuthUser
Proxies map[string]C.Proxy
Listeners map[string]C.InboundListener
Providers map[string]providerTypes.ProxyProvider
RuleProviders map[string]providerTypes.RuleProvider
Providers map[string]P.ProxyProvider
RuleProviders map[string]P.RuleProvider
Tunnels []LC.Tunnel
Sniffer *sniffer.Config
TLS *TLS
@@ -382,51 +382,51 @@ type RawTLS struct {
}
type RawConfig struct {
Port int `yaml:"port" json:"port"`
SocksPort int `yaml:"socks-port" json:"socks-port"`
RedirPort int `yaml:"redir-port" json:"redir-port"`
TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"`
MixedPort int `yaml:"mixed-port" json:"mixed-port"`
ShadowSocksConfig string `yaml:"ss-config" json:"ss-config"`
VmessConfig string `yaml:"vmess-config" json:"vmess-config"`
InboundTfo bool `yaml:"inbound-tfo" json:"inbound-tfo"`
InboundMPTCP bool `yaml:"inbound-mptcp" json:"inbound-mptcp"`
Authentication []string `yaml:"authentication" json:"authentication"`
SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes" json:"skip-auth-prefixes"`
LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips" json:"lan-allowed-ips"`
LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips" json:"lan-disallowed-ips"`
AllowLan bool `yaml:"allow-lan" json:"allow-lan"`
BindAddress string `yaml:"bind-address" json:"bind-address"`
Mode T.TunnelMode `yaml:"mode" json:"mode"`
UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"`
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
IPv6 bool `yaml:"ipv6" json:"ipv6"`
ExternalController string `yaml:"external-controller" json:"external-controller"`
ExternalControllerPipe string `yaml:"external-controller-pipe" json:"external-controller-pipe"`
ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"`
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
ExternalControllerCors RawCors `yaml:"external-controller-cors" json:"external-controller-cors"`
ExternalUI string `yaml:"external-ui" json:"external-ui"`
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
ExternalDohServer string `yaml:"external-doh-server" json:"external-doh-server"`
Secret string `yaml:"secret" json:"secret"`
Interface string `yaml:"interface-name" json:"interface-name"`
RoutingMark int `yaml:"routing-mark" json:"routing-mark"`
Tunnels []LC.Tunnel `yaml:"tunnels" json:"tunnels"`
GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"`
GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"`
GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"`
GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"`
GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"`
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"`
GlobalClientFingerprint string `yaml:"global-client-fingerprint" json:"global-client-fingerprint"`
GlobalUA string `yaml:"global-ua" json:"global-ua"`
ETagSupport bool `yaml:"etag-support" json:"etag-support"`
KeepAliveIdle int `yaml:"keep-alive-idle" json:"keep-alive-idle"`
KeepAliveInterval int `yaml:"keep-alive-interval" json:"keep-alive-interval"`
DisableKeepAlive bool `yaml:"disable-keep-alive" json:"disable-keep-alive"`
Port int `yaml:"port" json:"port"`
SocksPort int `yaml:"socks-port" json:"socks-port"`
RedirPort int `yaml:"redir-port" json:"redir-port"`
TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"`
MixedPort int `yaml:"mixed-port" json:"mixed-port"`
ShadowSocksConfig string `yaml:"ss-config" json:"ss-config"`
VmessConfig string `yaml:"vmess-config" json:"vmess-config"`
InboundTfo bool `yaml:"inbound-tfo" json:"inbound-tfo"`
InboundMPTCP bool `yaml:"inbound-mptcp" json:"inbound-mptcp"`
Authentication []string `yaml:"authentication" json:"authentication"`
SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes" json:"skip-auth-prefixes"`
LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips" json:"lan-allowed-ips"`
LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips" json:"lan-disallowed-ips"`
AllowLan bool `yaml:"allow-lan" json:"allow-lan"`
BindAddress string `yaml:"bind-address" json:"bind-address"`
Mode T.TunnelMode `yaml:"mode" json:"mode"`
UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"`
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
IPv6 bool `yaml:"ipv6" json:"ipv6"`
ExternalController string `yaml:"external-controller" json:"external-controller"`
ExternalControllerPipe string `yaml:"external-controller-pipe" json:"external-controller-pipe"`
ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"`
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
ExternalControllerCors RawCors `yaml:"external-controller-cors" json:"external-controller-cors"`
ExternalUI string `yaml:"external-ui" json:"external-ui"`
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
ExternalDohServer string `yaml:"external-doh-server" json:"external-doh-server"`
Secret string `yaml:"secret" json:"secret"`
Interface string `yaml:"interface-name" json:"interface-name"`
RoutingMark int `yaml:"routing-mark" json:"routing-mark"`
Tunnels []LC.Tunnel `yaml:"tunnels" json:"tunnels"`
GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"`
GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"`
GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"`
GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"`
GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"`
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
FindProcessMode process.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"`
GlobalClientFingerprint string `yaml:"global-client-fingerprint" json:"global-client-fingerprint"`
GlobalUA string `yaml:"global-ua" json:"global-ua"`
ETagSupport bool `yaml:"etag-support" json:"etag-support"`
KeepAliveIdle int `yaml:"keep-alive-idle" json:"keep-alive-idle"`
KeepAliveInterval int `yaml:"keep-alive-interval" json:"keep-alive-interval"`
DisableKeepAlive bool `yaml:"disable-keep-alive" json:"disable-keep-alive"`
ProxyProvider map[string]map[string]any `yaml:"proxy-providers" json:"proxy-providers"`
RuleProvider map[string]map[string]any `yaml:"rule-providers" json:"rule-providers"`
@@ -479,7 +479,7 @@ func DefaultRawConfig() *RawConfig {
Proxy: []map[string]any{},
ProxyGroup: []map[string]any{},
TCPConcurrent: false,
FindProcessMode: P.FindProcessStrict,
FindProcessMode: process.FindProcessStrict,
GlobalUA: "clash.meta/" + C.Version,
ETagSupport: true,
DNS: RawDNS{
@@ -653,11 +653,11 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
config.Proxies = proxies
config.Providers = providers
listener, err := parseListeners(rawCfg)
listeners, err := parseListeners(rawCfg)
if err != nil {
return nil, err
}
config.Listeners = listener
config.Listeners = listeners
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
log.Infoln("Geosite Matcher implementation: %s", geodata.SiteMatcherName())
@@ -845,9 +845,9 @@ func parseTLS(cfg *RawConfig) (*TLS, error) {
}, nil
}
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]P.ProxyProvider, err error) {
proxies = make(map[string]C.Proxy)
providersMap = make(map[string]providerTypes.ProxyProvider)
providersMap = make(map[string]P.ProxyProvider)
proxiesConfig := cfg.Proxy
groupsConfig := cfg.ProxyGroup
providersConfig := cfg.ProxyProvider
@@ -947,7 +947,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
&outboundgroup.GroupCommonOption{
Name: "GLOBAL",
},
[]providerTypes.ProxyProvider{pd},
[]P.ProxyProvider{pd},
)
proxies["GLOBAL"] = adapter.NewProxy(global)
}
@@ -957,24 +957,25 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
func parseListeners(cfg *RawConfig) (listeners map[string]C.InboundListener, err error) {
listeners = make(map[string]C.InboundListener)
for index, mapping := range cfg.Listeners {
listener, err := L.ParseListener(mapping)
inboundListener, err := listener.ParseListener(mapping)
if err != nil {
return nil, fmt.Errorf("proxy %d: %w", index, err)
}
if _, exist := mapping[listener.Name()]; exist {
return nil, fmt.Errorf("listener %s is the duplicate name", listener.Name())
name := inboundListener.Name()
if _, exist := mapping[name]; exist {
return nil, fmt.Errorf("listener %s is the duplicate name", name)
}
listeners[listener.Name()] = listener
listeners[name] = inboundListener
}
return
}
func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]providerTypes.RuleProvider, err error) {
func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]P.RuleProvider, err error) {
RP.SetTunnel(T.Tunnel)
ruleProviders = map[string]providerTypes.RuleProvider{}
ruleProviders = map[string]P.RuleProvider{}
// parse rule provider
for name, mapping := range cfg.RuleProvider {
rp, err := RP.ParseRuleProvider(name, mapping, R.ParseRule)
@@ -987,7 +988,7 @@ func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]providerTypes.
return
}
func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy, ruleProviders map[string]providerTypes.RuleProvider) (subRules map[string][]C.Rule, err error) {
func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy, ruleProviders map[string]P.RuleProvider) (subRules map[string][]C.Rule, err error) {
subRules = map[string][]C.Rule{}
for name := range cfg.SubRules {
subRules[name] = make([]C.Rule, 0)
@@ -1050,7 +1051,7 @@ func verifySubRuleCircularReferences(n string, subRules map[string][]C.Rule, arr
return nil
}
func parseRules(rulesConfig []string, proxies map[string]C.Proxy, ruleProviders map[string]providerTypes.RuleProvider, subRules map[string][]C.Rule, format string) ([]C.Rule, error) {
func parseRules(rulesConfig []string, proxies map[string]C.Proxy, ruleProviders map[string]P.RuleProvider, subRules map[string][]C.Rule, format string) ([]C.Rule, error) {
var rules []C.Rule
// parse rules
@@ -1273,7 +1274,7 @@ func parsePureDNSServer(server string) string {
}
}
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]P.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
var policy []dns.Policy
for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() {
@@ -1348,7 +1349,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro
return policy, nil
}
func parseDNS(rawCfg *RawConfig, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) {
func parseDNS(rawCfg *RawConfig, ruleProviders map[string]P.RuleProvider) (*DNS, error) {
cfg := rawCfg.DNS
if cfg.Enable && len(cfg.NameServer) == 0 {
return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
@@ -1632,7 +1633,7 @@ func parseTuicServer(rawTuic RawTuicServer, general *General) error {
return nil
}
func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]providerTypes.RuleProvider) (*sniffer.Config, error) {
func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]P.RuleProvider) (*sniffer.Config, error) {
snifferConfig := &sniffer.Config{
Enable: snifferRaw.Enable,
ForceDnsMapping: snifferRaw.ForceDnsMapping,
@@ -1722,7 +1723,7 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]providerTypes.
return snifferConfig, nil
}
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.IpMatcher, err error) {
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]P.RuleProvider) (matchers []C.IpMatcher, err error) {
var matcher C.IpMatcher
for _, ipcidr := range addresses {
ipcidrLower := strings.ToLower(ipcidr)
@@ -1769,7 +1770,7 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
return
}
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.DomainMatcher, err error) {
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]P.RuleProvider) (matchers []C.DomainMatcher, err error) {
var matcher C.DomainMatcher
for _, domain := range domains {
domainLower := strings.ToLower(domain)
@@ -1812,14 +1813,14 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
return
}
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.IpMatcher, error) {
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]P.RuleProvider) (C.IpMatcher, error) {
if rp, ok := ruleProviders[domainSetName]; !ok {
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
} else {
switch rp.Behavior() {
case providerTypes.Domain:
case P.Domain:
return nil, fmt.Errorf("rule provider type error, except ipcidr,actual %s", rp.Behavior())
case providerTypes.Classical:
case P.Classical:
log.Warnln("%s provider is %s, only matching it contain ip rule", rp.Name(), rp.Behavior())
default:
}
@@ -1827,14 +1828,14 @@ func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[
return RP.NewRuleSet(domainSetName, adapterName, false, true)
}
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.DomainMatcher, error) {
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]P.RuleProvider) (C.DomainMatcher, error) {
if rp, ok := ruleProviders[domainSetName]; !ok {
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
} else {
switch rp.Behavior() {
case providerTypes.IPCIDR:
case P.IPCIDR:
return nil, fmt.Errorf("rule provider type error, except domain,actual %s", rp.Behavior())
case providerTypes.Classical:
case P.Classical:
log.Warnln("%s provider is %s, only matching it contain domain rule", rp.Name(), rp.Behavior())
default:
}
+8 -8
View File
@@ -31,7 +31,7 @@ import (
"github.com/metacubex/mihomo/component/updater"
"github.com/metacubex/mihomo/config"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/dns"
"github.com/metacubex/mihomo/listener"
authStore "github.com/metacubex/mihomo/listener/auth"
@@ -303,18 +303,18 @@ func updateHosts(tree *trie.DomainTrie[resolver.HostValue]) {
resolver.DefaultHosts = resolver.NewHosts(tree)
}
func updateProxies(proxies map[string]C.Proxy, providers map[string]provider.ProxyProvider) {
func updateProxies(proxies map[string]C.Proxy, providers map[string]P.ProxyProvider) {
tunnel.UpdateProxies(proxies, providers)
}
func updateRules(rules []C.Rule, subRules map[string][]C.Rule, ruleProviders map[string]provider.RuleProvider) {
func updateRules(rules []C.Rule, subRules map[string][]C.Rule, ruleProviders map[string]P.RuleProvider) {
tunnel.UpdateRules(rules, subRules, ruleProviders)
}
func loadProvider[P provider.Provider](providers map[string]P) {
load := func(pv P) {
func loadProvider[T P.Provider](providers map[string]T) {
load := func(pv T) {
name := pv.Name()
if pv.VehicleType() == provider.Compatible {
if pv.VehicleType() == P.Compatible {
log.Infoln("Start initial compatible provider %s", name)
} else {
log.Infoln("Start initial provider %s", name)
@@ -322,11 +322,11 @@ func loadProvider[P provider.Provider](providers map[string]P) {
if err := pv.Initial(); err != nil {
switch pv.Type() {
case provider.Proxy:
case P.Proxy:
{
log.Errorln("initial proxy provider %s error: %v", name, err)
}
case provider.Rule:
case P.Rule:
{
log.Errorln("initial rule provider %s error: %v", name, err)
}
+13 -13
View File
@@ -13,7 +13,7 @@ import (
"github.com/metacubex/mihomo/config"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/hub/executor"
P "github.com/metacubex/mihomo/listener"
"github.com/metacubex/mihomo/listener"
LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/tunnel"
@@ -306,7 +306,7 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
}
if general.AllowLan != nil {
P.SetAllowLan(*general.AllowLan)
listener.SetAllowLan(*general.AllowLan)
}
if general.SkipAuthPrefixes != nil {
@@ -322,7 +322,7 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
}
if general.BindAddress != nil {
P.SetBindAddress(*general.BindAddress)
listener.SetBindAddress(*general.BindAddress)
}
if general.Sniffing != nil {
@@ -337,17 +337,17 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
dialer.DefaultInterface.Store(*general.InterfaceName)
}
ports := P.GetPorts()
ports := listener.GetPorts()
P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tunnel.Tunnel)
P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tunnel.Tunnel)
P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tunnel.Tunnel)
P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tunnel.Tunnel)
P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tunnel.Tunnel)
P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tunnel.Tunnel)
P.ReCreateShadowSocks(pointerOrDefault(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel)
P.ReCreateVmess(pointerOrDefault(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel)
P.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, P.LastTuicConf), tunnel.Tunnel)
listener.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tunnel.Tunnel)
listener.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tunnel.Tunnel)
listener.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tunnel.Tunnel)
listener.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tunnel.Tunnel)
listener.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tunnel.Tunnel)
listener.ReCreateTun(pointerOrDefaultTun(general.Tun, listener.LastTunConf), tunnel.Tunnel)
listener.ReCreateShadowSocks(pointerOrDefault(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel)
listener.ReCreateVmess(pointerOrDefault(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel)
listener.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, listener.LastTuicConf), tunnel.Tunnel)
if general.Mode != nil {
tunnel.SetMode(*general.Mode)
+6 -6
View File
@@ -5,7 +5,7 @@ import (
"net/http"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/tunnel"
"github.com/go-chi/chi/v5"
@@ -45,12 +45,12 @@ func getProviders(w http.ResponseWriter, r *http.Request) {
}
func getProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
provider := r.Context().Value(CtxKeyProvider).(P.ProxyProvider)
render.JSON(w, r, provider)
}
func updateProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
provider := r.Context().Value(CtxKeyProvider).(P.ProxyProvider)
if err := provider.Update(); err != nil {
render.Status(r, http.StatusServiceUnavailable)
render.JSON(w, r, newError(err.Error()))
@@ -60,7 +60,7 @@ func updateProvider(w http.ResponseWriter, r *http.Request) {
}
func healthCheckProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
provider := r.Context().Value(CtxKeyProvider).(P.ProxyProvider)
provider.HealthCheck()
render.NoContent(w, r)
}
@@ -93,7 +93,7 @@ func findProviderProxyByName(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var (
name = r.Context().Value(CtxKeyProxyName).(string)
pd = r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
pd = r.Context().Value(CtxKeyProvider).(P.ProxyProvider)
)
proxy, exist := lo.Find(pd.Proxies(), func(proxy C.Proxy) bool {
return proxy.Name() == name
@@ -128,7 +128,7 @@ func getRuleProviders(w http.ResponseWriter, r *http.Request) {
}
func updateRuleProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(provider.RuleProvider)
provider := r.Context().Value(CtxKeyProvider).(P.RuleProvider)
if err := provider.Update(); err != nil {
render.Status(r, http.StatusServiceUnavailable)
render.JSON(w, r, newError(err.Error()))
+4 -4
View File
@@ -18,7 +18,7 @@ import (
"github.com/metacubex/mihomo/component/iface"
"github.com/metacubex/mihomo/component/resolver"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/listener/sing"
"github.com/metacubex/mihomo/log"
@@ -133,7 +133,7 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis
}
}
ctx := context.TODO()
rpTunnel := tunnel.(provider.Tunnel)
rpTunnel := tunnel.(P.Tunnel)
if options.GSOMaxSize == 0 {
options.GSOMaxSize = 65536
}
@@ -504,7 +504,7 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis
return
}
func (l *Listener) ruleUpdateCallback(ruleProvider provider.RuleProvider) {
func (l *Listener) ruleUpdateCallback(ruleProvider P.RuleProvider) {
name := ruleProvider.Name()
if slices.Contains(l.options.RouteAddressSet, name) {
l.updateRule(ruleProvider, false, true)
@@ -520,7 +520,7 @@ type toIpCidr interface {
ToIpCidr() *netipx.IPSet
}
func (l *Listener) updateRule(ruleProvider provider.RuleProvider, exclude bool, update bool) {
func (l *Listener) updateRule(ruleProvider P.RuleProvider, exclude bool, update bool) {
l.ruleUpdateMutex.Lock()
defer l.ruleUpdateMutex.Unlock()
name := ruleProvider.Name()
+21 -21
View File
@@ -17,13 +17,13 @@ import (
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/loopback"
"github.com/metacubex/mihomo/component/nat"
P "github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/component/slowdown"
"github.com/metacubex/mihomo/component/sniffer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/features"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
icontext "github.com/metacubex/mihomo/context"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/tunnel/statistic"
@@ -43,8 +43,8 @@ var (
listeners = make(map[string]C.InboundListener)
subRules map[string][]C.Rule
proxies = make(map[string]C.Proxy)
providers map[string]provider.ProxyProvider
ruleProviders map[string]provider.RuleProvider
providers map[string]P.ProxyProvider
ruleProviders map[string]P.RuleProvider
configMux sync.RWMutex
// for compatibility, lazy init
@@ -59,19 +59,19 @@ var (
// default timeout for UDP session
udpTimeout = 60 * time.Second
findProcessMode = atomic.NewInt32Enum(P.FindProcessStrict)
findProcessMode = atomic.NewInt32Enum(process.FindProcessStrict)
snifferDispatcher *sniffer.Dispatcher
sniffingEnable = false
ruleUpdateCallback = utils.NewCallback[provider.RuleProvider]()
ruleUpdateCallback = utils.NewCallback[P.RuleProvider]()
)
type tunnel struct{}
var Tunnel = tunnel{}
var _ C.Tunnel = Tunnel
var _ provider.Tunnel = Tunnel
var _ P.Tunnel = Tunnel
func (t tunnel) HandleTCPConn(conn net.Conn, metadata *C.Metadata) {
connCtx := icontext.NewConnContext(conn, metadata)
@@ -112,15 +112,15 @@ func (t tunnel) NatTable() C.NatTable {
return natTable
}
func (t tunnel) Providers() map[string]provider.ProxyProvider {
func (t tunnel) Providers() map[string]P.ProxyProvider {
return providers
}
func (t tunnel) RuleProviders() map[string]provider.RuleProvider {
func (t tunnel) RuleProviders() map[string]P.RuleProvider {
return ruleProviders
}
func (t tunnel) RuleUpdateCallback() *utils.Callback[provider.RuleProvider] {
func (t tunnel) RuleUpdateCallback() *utils.Callback[P.RuleProvider] {
return ruleUpdateCallback
}
@@ -195,7 +195,7 @@ func Listeners() map[string]C.InboundListener {
}
// UpdateRules handle update rules
func UpdateRules(newRules []C.Rule, newSubRule map[string][]C.Rule, rp map[string]provider.RuleProvider) {
func UpdateRules(newRules []C.Rule, newSubRule map[string][]C.Rule, rp map[string]P.RuleProvider) {
configMux.Lock()
rules = newRules
ruleProviders = rp
@@ -223,17 +223,17 @@ func ProxiesWithProviders() map[string]C.Proxy {
}
// Providers return all compatible providers
func Providers() map[string]provider.ProxyProvider {
func Providers() map[string]P.ProxyProvider {
return providers
}
// RuleProviders return all loaded rule providers
func RuleProviders() map[string]provider.RuleProvider {
func RuleProviders() map[string]P.RuleProvider {
return ruleProviders
}
// UpdateProxies handle update proxies
func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]provider.ProxyProvider) {
func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]P.ProxyProvider) {
configMux.Lock()
proxies = newProxies
providers = newProviders
@@ -263,13 +263,13 @@ func SetMode(m TunnelMode) {
mode = m
}
func FindProcessMode() P.FindProcessMode {
func FindProcessMode() process.FindProcessMode {
return findProcessMode.Load()
}
// SetFindProcessMode replace SetAlwaysFindProcess
// always find process info if legacyAlways = true or mode.Always() = true, may be increase many memory
func SetFindProcessMode(mode P.FindProcessMode) {
func SetFindProcessMode(mode process.FindProcessMode) {
findProcessMode.Store(mode)
}
@@ -358,7 +358,7 @@ func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err erro
attemptProcessLookup = false
if !features.CMFA {
// normal check for process
uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort))
uid, path, err := process.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort))
if err != nil {
log.Debugln("[Process] find process error for %s: %v", metadata.String(), err)
} else {
@@ -366,13 +366,13 @@ func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err erro
metadata.ProcessPath = path
metadata.Uid = uid
if pkg, err := P.FindPackageName(metadata); err == nil { // for android (not CMFA) package names
if pkg, err := process.FindPackageName(metadata); err == nil { // for android (not CMFA) package names
metadata.Process = pkg
}
}
} else {
// check package names
pkg, err := P.FindPackageName(metadata)
pkg, err := process.FindPackageName(metadata)
if err != nil {
log.Debugln("[Process] find process error for %s: %v", metadata.String(), err)
} else {
@@ -384,10 +384,10 @@ func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err erro
}
switch FindProcessMode() {
case P.FindProcessAlways:
case process.FindProcessAlways:
helper.FindProcess()
helper.FindProcess = nil
case P.FindProcessOff:
case process.FindProcessOff:
helper.FindProcess = nil
}
+84 -84
View File
@@ -365,7 +365,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -531,7 +531,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -566,7 +566,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -615,7 +615,7 @@ checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -860,7 +860,7 @@ dependencies = [
"regex",
"rustc-hash 1.1.0",
"shlex",
"syn 2.0.108",
"syn 2.0.109",
"which 4.4.2",
]
@@ -1058,7 +1058,7 @@ checksum = "9fd3f870829131332587f607a7ff909f1af5fc523fd1b192db55fbbdf52e8d3c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"synstructure",
]
@@ -1196,7 +1196,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -1488,7 +1488,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -1722,7 +1722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f76990911f2267d837d9d0ad060aa63aaad170af40904b29461734c339030d4d"
dependencies = [
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2003,7 +2003,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2013,7 +2013,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
dependencies = [
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2054,7 +2054,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2065,7 +2065,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2156,7 +2156,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2177,7 +2177,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2187,7 +2187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2200,7 +2200,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2355,7 +2355,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2387,7 +2387,7 @@ checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2685,7 +2685,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2706,7 +2706,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2777,7 +2777,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -2898,7 +2898,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -3055,7 +3055,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -3205,7 +3205,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -3511,7 +3511,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -3773,7 +3773,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -4302,7 +4302,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -4404,7 +4404,7 @@ dependencies = [
"proc-macro2",
"quote",
"sha2 0.10.9",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -4421,7 +4421,7 @@ dependencies = [
"serde",
"serde_json",
"sha2 0.10.9",
"syn 2.0.108",
"syn 2.0.109",
"url",
]
@@ -4519,7 +4519,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -5122,7 +5122,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -5632,7 +5632,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -5694,7 +5694,7 @@ dependencies = [
"proc-macro-crate 3.3.0",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -5763,7 +5763,7 @@ version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -6419,7 +6419,7 @@ checksum = "05bbaa5b6b98826bb62b164406f703bee72c5287af9986f9c863fa8ea992b476"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -6461,7 +6461,7 @@ dependencies = [
"phf 0.13.1",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -6721,7 +6721,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -6869,7 +6869,7 @@ dependencies = [
"phf_shared 0.11.3",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"unicase",
]
@@ -6883,7 +6883,7 @@ dependencies = [
"phf_shared 0.13.1",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -6946,7 +6946,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -7124,7 +7124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -7210,7 +7210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
dependencies = [
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -7608,7 +7608,7 @@ checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -7817,7 +7817,7 @@ dependencies = [
"serde",
"serde_json",
"serde_yaml",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8025,7 +8025,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8169,7 +8169,7 @@ checksum = "d6185cf75117e20e62b1ff867b9518577271e58abe0037c40bb4794969355ab0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8180,7 +8180,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8215,7 +8215,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8277,7 +8277,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8325,7 +8325,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8717,7 +8717,7 @@ dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8841,7 +8841,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -8884,9 +8884,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.108"
version = "2.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f"
dependencies = [
"proc-macro2",
"quote",
@@ -8910,7 +8910,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -9032,7 +9032,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -9152,7 +9152,7 @@ dependencies = [
"serde",
"serde_json",
"sha2 0.10.9",
"syn 2.0.108",
"syn 2.0.109",
"tauri-utils",
"thiserror 2.0.17",
"time",
@@ -9170,7 +9170,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"tauri-codegen",
"tauri-utils",
]
@@ -9476,7 +9476,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -9645,7 +9645,7 @@ checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -9691,7 +9691,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -9702,7 +9702,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -9859,7 +9859,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -10082,7 +10082,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -10174,7 +10174,7 @@ version = "0.2.5"
source = "git+https://github.com/Frando/tracing-test.git?rev=e81ec65#e81ec655a5ec5c4351104628b1b1ba694f80a1dc"
dependencies = [
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -10680,7 +10680,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"wasm-bindgen-shared",
]
@@ -10715,7 +10715,7 @@ checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -10997,7 +10997,7 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -11414,7 +11414,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -11425,7 +11425,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -11436,7 +11436,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -11447,7 +11447,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -12229,7 +12229,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"synstructure",
]
@@ -12241,7 +12241,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"synstructure",
]
@@ -12297,7 +12297,7 @@ checksum = "dc6821851fa840b708b4cbbaf6241868cabc85a2dc22f426361b0292bfc0b836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"zbus-lockstep",
"zbus_xml",
"zvariant",
@@ -12312,7 +12312,7 @@ dependencies = [
"proc-macro-crate 3.3.0",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"zbus_names",
"zvariant",
"zvariant_utils",
@@ -12360,7 +12360,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -12380,7 +12380,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"synstructure",
]
@@ -12401,7 +12401,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -12445,7 +12445,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -12456,7 +12456,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
]
[[package]]
@@ -12601,7 +12601,7 @@ dependencies = [
"proc-macro-crate 3.3.0",
"proc-macro2",
"quote",
"syn 2.0.108",
"syn 2.0.109",
"zvariant_utils",
]
@@ -12614,6 +12614,6 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.108",
"syn 2.0.109",
"winnow 0.7.13",
]
@@ -11,7 +11,7 @@
"build": "tsc"
},
"dependencies": {
"@tanstack/react-query": "5.90.6",
"@tanstack/react-query": "5.90.7",
"@tauri-apps/api": "2.8.0",
"ahooks": "3.9.6",
"dayjs": "1.11.19",
@@ -56,9 +56,9 @@
"@csstools/normalize.css": "12.1.1",
"@emotion/babel-plugin": "11.13.5",
"@emotion/react": "11.14.0",
"@iconify/json": "2.2.403",
"@iconify/json": "2.2.404",
"@monaco-editor/react": "4.7.0",
"@tanstack/react-query": "5.90.6",
"@tanstack/react-query": "5.90.7",
"@tanstack/react-router": "1.134.12",
"@tanstack/react-router-devtools": "1.134.12",
"@tanstack/router-plugin": "1.134.12",
+2 -2
View File
@@ -2,7 +2,7 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.19.15",
"mihomo_alpha": "alpha-5a285ac",
"mihomo_alpha": "alpha-8b32c43",
"clash_rs": "v0.9.2",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.9.2-alpha+sha.b24d5a9"
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
"updated_at": "2025-11-04T22:21:06.320Z"
"updated_at": "2025-11-05T22:21:12.319Z"
}
+16 -16
View File
@@ -179,8 +179,8 @@ importers:
frontend/interface:
dependencies:
'@tanstack/react-query':
specifier: 5.90.6
version: 5.90.6(react@19.2.0)
specifier: 5.90.7
version: 5.90.7(react@19.2.0)
'@tauri-apps/api':
specifier: 2.8.0
version: 2.8.0
@@ -346,14 +346,14 @@ importers:
specifier: 11.14.0
version: 11.14.0(@types/react@19.2.2)(react@19.2.0)
'@iconify/json':
specifier: 2.2.403
version: 2.2.403
specifier: 2.2.404
version: 2.2.404
'@monaco-editor/react':
specifier: 4.7.0
version: 4.7.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@tanstack/react-query':
specifier: 5.90.6
version: 5.90.6(react@19.2.0)
specifier: 5.90.7
version: 5.90.7(react@19.2.0)
'@tanstack/react-router':
specifier: 1.134.12
version: 1.134.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -1821,8 +1821,8 @@ packages:
prettier-plugin-ember-template-tag:
optional: true
'@iconify/json@2.2.403':
resolution: {integrity: sha512-TU27b9pVsbYuTKF7i/OHAB5rUscWhe85AEk0vPkDT1MMqV7ZWWxUk5B7j03JHacX5NCtggB1KiCz985wjc7HVQ==}
'@iconify/json@2.2.404':
resolution: {integrity: sha512-K11bUBMW7gb/PhzJNZvDDJDq3hEVXoJArsdbr+9LQQqd2TrWEd5+PtctNcfJLu4epgjwDppaLJnN6AEPI1BL9w==}
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
@@ -3170,11 +3170,11 @@ packages:
resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==}
engines: {node: '>=12'}
'@tanstack/query-core@5.90.6':
resolution: {integrity: sha512-AnZSLF26R8uX+tqb/ivdrwbVdGemdEDm1Q19qM6pry6eOZ6bEYiY7mWhzXT1YDIPTNEVcZ5kYP9nWjoxDLiIVw==}
'@tanstack/query-core@5.90.7':
resolution: {integrity: sha512-6PN65csiuTNfBMXqQUxQhCNdtm1rV+9kC9YwWAIKcaxAauq3Wu7p18j3gQY3YIBJU70jT/wzCCZ2uqto/vQgiQ==}
'@tanstack/react-query@5.90.6':
resolution: {integrity: sha512-gB1sljYjcobZKxjPbKSa31FUTyr+ROaBdoH+wSSs9Dk+yDCmMs+TkTV3PybRRVLC7ax7q0erJ9LvRWnMktnRAw==}
'@tanstack/react-query@5.90.7':
resolution: {integrity: sha512-wAHc/cgKzW7LZNFloThyHnV/AX9gTg3w5yAv0gvQHPZoCnepwqCMtzbuPbb2UvfvO32XZ46e8bPOYbfZhzVnnQ==}
peerDependencies:
react: ^18 || ^19
@@ -10349,7 +10349,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@iconify/json@2.2.403':
'@iconify/json@2.2.404':
dependencies:
'@iconify/types': 2.0.0
pathe: 2.0.3
@@ -11598,11 +11598,11 @@ snapshots:
dependencies:
remove-accents: 0.5.0
'@tanstack/query-core@5.90.6': {}
'@tanstack/query-core@5.90.7': {}
'@tanstack/react-query@5.90.6(react@19.2.0)':
'@tanstack/react-query@5.90.7(react@19.2.0)':
dependencies:
'@tanstack/query-core': 5.90.6
'@tanstack/query-core': 5.90.7
react: 19.2.0
'@tanstack/react-router-devtools@1.134.12(@tanstack/react-router@1.134.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.134.12)(@types/node@24.10.0)(csstype@3.1.3)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass-embedded@1.93.3)(sass@1.93.3)(solid-js@1.9.5)(stylus@0.62.0)(terser@5.36.0)(tiny-invariant@1.3.3)(tsx@4.20.6)(yaml@2.8.1)':
+2 -2
View File
@@ -41,8 +41,8 @@ async function resolvePublish() {
const nextVersion = `${a}.${b}.${c}`
const nextNightlyVersion = `${a}.${b}.${c + 1}`
packageJson.version = nextVersion
tauriJson.package.version = nextVersion
tauriNightlyJson.package.version = nextNightlyVersion
tauriJson.version = nextVersion
tauriNightlyJson.version = nextNightlyVersion
// 发布更新前先写更新日志
// const nextTag = `v${nextVersion}`;
+2 -3
View File
@@ -321,15 +321,14 @@ menu "Target Images"
depends on USES_BOOT_PART
default 8 if TARGET_apm821xx_sata
default 128 if TARGET_armsr
default 64 if TARGET_bcm27xx
default 64 if TARGET_bcm27xx || TARGET_x86 || TARGET_loongarch64
default 32 if TARGET_rockchip
default 16
config TARGET_ROOTFS_PARTSIZE
int "Root filesystem partition size (in MiB)"
depends on USES_ROOTFS_PART || TARGET_ROOTFS_EXT4FS
default 232 if TARGET_loongarch64
default 448 if TARGET_mediatek || TARGET_x86
default 448 if TARGET_mediatek || TARGET_x86 || TARGET_loongarch64
default 160
help
Select the root filesystem partition size.
+27 -3
View File
@@ -481,15 +481,14 @@ define KernelPackage/drm-amdgpu
DEPENDS:=@TARGET_x86 @DISPLAY_SUPPORT +kmod-backlight +kmod-drm-ttm \
+kmod-drm-ttm-helper +kmod-drm-kms-helper +kmod-i2c-algo-bit +amdgpu-firmware \
+kmod-drm-display-helper +kmod-drm-buddy +kmod-acpi-video \
+(LINUX_6_6||LINUX_6_12):kmod-drm-exec +(LINUX_6_6||LINUX_6_12):kmod-drm-suballoc-helper
+(LINUX_6_6||LINUX_6_12):kmod-drm-exec +(LINUX_6_6||LINUX_6_12):kmod-drm-suballoc-helper +kmod-drm-sched
KCONFIG:=CONFIG_DRM_AMDGPU \
CONFIG_DRM_AMDGPU_SI=y \
CONFIG_DRM_AMDGPU_CIK=y \
CONFIG_DRM_AMD_DC=y \
CONFIG_DEBUG_KERNEL_DC=n
FILES:=$(LINUX_DIR)/drivers/gpu/drm/amd/amdgpu/amdgpu.ko \
$(LINUX_DIR)/drivers/gpu/drm/amd/amdxcp/amdxcp.ko@ge6.5 \
$(LINUX_DIR)/drivers/gpu/drm/scheduler/gpu-sched.ko
$(LINUX_DIR)/drivers/gpu/drm/amd/amdxcp/amdxcp.ko@ge6.5
AUTOLOAD:=$(call AutoProbe,amdgpu)
endef
@@ -754,6 +753,31 @@ endef
$(eval $(call KernelPackage,drm-nouveau))
define KernelPackage/drm-xe
SUBMENU:=$(VIDEO_MENU)
TITLE:=Intel Xe GPU drm support
DEPENDS:=@TARGET_x86 +kmod-drm-buddy +kmod-drm-ttm +kmod-drm-kms-helper +kmod-drm-i915 +i915-firmware \
+kmod-drm-display-helper +kmod-acpi-video \
+kmod-drm-exec +kmod-drm-suballoc-helper +kmod-drm-sched @LINUX_6_12
KCONFIG:= \
CONFIG_DRM_GPUVM \
CONFIG_DRM_SCHED \
CONFIG_DRM_XE
FILES:= \
$(LINUX_DIR)/drivers/gpu/drm/drm_gpuvm.ko \
$(LINUX_DIR)/drivers/gpu/drm/xe/xe.ko
AUTOLOAD:=$(call AutoProbe,gpu-sched drm_gpuvm xe)
endef
define KernelPackage/drm-xe/description
The drm/xe driver supports some future GFX cards with rendering, display,
compute and media. Support for currently available platforms like TGL, ADL,
DG2, etc is provided to prototype the driver.
endef
$(eval $(call KernelPackage,drm-xe))
#
# Video Capture
#
+25
View File
@@ -22,6 +22,13 @@ define Package/autocore-arm
VARIANT:=arm
endef
define Package/autocore-loongarch64
TITLE:=Loongarch64 auto core loadbalance script.
MAINTAINER:=LEAN
DEPENDS:=@loongarch64 +bc +ethtool +pciutils
VARIANT:=loongarch64
endef
define Package/autocore-x86
TITLE:=x86/x64 auto core loadbalance script.
MAINTAINER:=Lean
@@ -33,6 +40,10 @@ define Package/autocore-arm/description
A luci autoconfig hotplug script.
endef
define Package/autocore-loongarch64/description
A luci autoconfig hotplug script.
endef
define Package/autocore-x86/description
A usb autoconfig hotplug script.
endef
@@ -57,6 +68,19 @@ endif
$(CP) ./files/luci-mod-status-autocore.json $(1)/usr/share/rpcd/acl.d/
endef
define Package/autocore-loongarch64/install
$(INSTALL_DIR) $(1)/etc
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/loongarch64/autocore $(1)/etc/init.d/autocore
$(INSTALL_BIN) ./files/60-autocore-reload-rpcd $(1)/etc/uci-defaults/
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) ./files/loongarch64/sbin/cpuinfo $(1)/sbin/cpuinfo
$(INSTALL_BIN) ./files/loongarch64/sbin/tempinfo $(1)/sbin/tempinfo
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(CP) ./files/luci-mod-status-autocore.json $(1)/usr/share/rpcd/acl.d/
endef
define Package/autocore-x86/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/x86/autocore $(1)/etc/init.d/autocore
@@ -71,4 +95,5 @@ define Package/autocore-x86/install
endef
$(eval $(call BuildPackage,autocore-arm))
$(eval $(call BuildPackage,autocore-loongarch64))
$(eval $(call BuildPackage,autocore-x86))
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2025 lean <coolsnowwolf@gmail.com>
START=99
start()
{
a=$(cat /proc/cpuinfo | grep 'Model Name' | cut -f2 -d: | head -n 1)
b=$(echo -n ' : ')
c=$(cat /proc/cpuinfo | grep 'core' | sort -u | wc -l)
d=$(echo -n 'C')
e=$(cat /proc/cpuinfo | grep 'global_id' | sort -u | wc -l)
f=$(echo -n 'T ')
g=$(cat /proc/cpuinfo | grep 'CPU Family' | cut -f2 -d: | head -n 1)
h=${g}' - '${a}${b}${c}${d}${e}${f}
mkdir -p /tmp/sysinfo
echo $h > /tmp/sysinfo/model
}
@@ -0,0 +1,5 @@
#!/bin/sh
MHz=`grep 'MHz' /proc/cpuinfo | cut -c13- |sed -n '1p'`
echo "$MHz MHz"
@@ -0,0 +1,45 @@
#!/usr/bin/lua
-- Copyright (C) 2022 ImmortalWrt.org
local util = require "luci.util"
local jsonc = require "luci.jsonc"
local eth_info = {}
local ifname, stat
for ifname, stat in pairs(util.ubus("network.device", "status")) do
while true do
if (ifname:match("^(br-.+)$")) == ifname then
break
else
local status, speed, duplex
if(stat.speed ~= nil) then
status = stat.carrier and 1 or 0
if stat.speed:sub(1, 1) == "-" then
speed = " - "
else
speed = stat.speed:sub(1, -2) .. "Mb/s"
end
if stat.carrier and stat.speed:sub(-1) == "F" then
duplex = 1
else
duplex = 0
end
eth_info[#eth_info+1] = { name = ifname, status = status,
speed = speed, duplex = duplex }
end
break
end
end
end
table.sort(eth_info,
function(a, b)
return a.name < b.name
end)
print(jsonc.stringify(eth_info))
@@ -0,0 +1,5 @@
#!/bin/sh
TEMP=`awk '{printf("%.1f°C", $0 / 1000)}' "/sys/class/thermal/thermal_zone0/temp" 2>"/dev/null"`
echo "$TEMP "
+1 -1
View File
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fstools
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/fstools.git
@@ -0,0 +1,11 @@
--- a/libfstools/common.h
+++ b/libfstools/common.h
@@ -19,7 +19,7 @@
#include "libfstools.h"
#include "volume.h"
-#define F2FS_MINSIZE (100ULL * 1024ULL * 1024ULL)
+#define F2FS_MINSIZE (1024ULL * 1024ULL * 1024ULL)
int read_uint_from_file(char *dirname, char *filename, unsigned int *i);
char *read_string_from_file(const char *dirname, const char *filename, char *buf, size_t bufsz);
+3 -2
View File
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
ARCH:=loongarch64
BOARD:=loongarch64
BOARDNAME:=Loongson LoongArch
FEATURES:=audio display ext4 pcie boot-part rootfs-part rtc usb targz
FEATURES:=squashfs audio display ext4 pcie boot-part rootfs-part rtc usb targz
SUBTARGETS:=generic
KERNEL_PATCHVER:=6.12
@@ -18,6 +18,7 @@ KERNELNAME:=vmlinuz.efi dtbs
include $(INCLUDE_DIR)/target.mk
DEFAULT_PACKAGES += \
partx-utils blkid e2fsprogs grub2-efi-loongarch64 kmod-yt6801
partx-utils blkid e2fsprogs grub2-efi-loongarch64 kmod-yt6801 \
kmod-fs-ext4 kmod-fs-f2fs losetup mkf2fs f2fsck e2fsprogs autocore-loongarch64
$(eval $(call BuildTarget))
+2 -2
View File
@@ -10,7 +10,7 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
type Fallback struct {
@@ -150,7 +150,7 @@ func (f *Fallback) ForceSet(name string) {
f.selected = name
}
func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallback {
return &Fallback{
GroupBase: NewGroupBase(GroupBaseOption{
Name: option.Name,
+4 -5
View File
@@ -12,8 +12,7 @@ import (
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/tunnel"
@@ -26,7 +25,7 @@ type GroupBase struct {
filterRegs []*regexp2.Regexp
excludeFilterRegs []*regexp2.Regexp
excludeTypeArray []string
providers []provider.ProxyProvider
providers []P.ProxyProvider
failedTestMux sync.Mutex
failedTimes int
failedTime time.Time
@@ -48,7 +47,7 @@ type GroupBaseOption struct {
ExcludeType string
TestTimeout int
MaxFailedTimes int
Providers []provider.ProxyProvider
Providers []P.ProxyProvider
}
func NewGroupBase(opt GroupBaseOption) *GroupBase {
@@ -125,7 +124,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
}
} else {
for _, pd := range gb.providers {
if pd.VehicleType() == types.Compatible { // compatible provider unneeded filter
if pd.VehicleType() == P.Compatible { // compatible provider unneeded filter
proxies = append(proxies, pd.Proxies()...)
continue
}
+2 -2
View File
@@ -14,7 +14,7 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"golang.org/x/net/publicsuffix"
)
@@ -239,7 +239,7 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
})
}
func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvider, strategy string) (lb *LoadBalance, err error) {
func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, strategy string) (lb *LoadBalance, err error) {
var strategyFn strategyFn
switch strategy {
case "consistent-hashing":
+8 -8
View File
@@ -11,7 +11,7 @@ import (
"github.com/metacubex/mihomo/common/structure"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
)
@@ -48,7 +48,7 @@ type GroupCommonOption struct {
RoutingMark int `group:"routing-mark,omitempty"`
}
func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider, AllProxies []string, AllProviders []string) (C.ProxyAdapter, error) {
func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]P.ProxyProvider, AllProxies []string, AllProviders []string) (C.ProxyAdapter, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "group", WeaklyTypedInput: true})
groupOption := &GroupCommonOption{
@@ -71,7 +71,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
groupName := groupOption.Name
providers := []types.ProxyProvider{}
providers := []P.ProxyProvider{}
if groupOption.IncludeAll {
groupOption.IncludeAllProviders = true
@@ -169,7 +169,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
return nil, fmt.Errorf("%s: %w", groupName, err)
}
providers = append([]types.ProxyProvider{pd}, providers...)
providers = append([]P.ProxyProvider{pd}, providers...)
providersMap[groupName] = pd
}
@@ -206,15 +206,15 @@ func getProxies(mapping map[string]C.Proxy, list []string) ([]C.Proxy, error) {
return ps, nil
}
func getProviders(mapping map[string]types.ProxyProvider, list []string) ([]types.ProxyProvider, error) {
var ps []types.ProxyProvider
func getProviders(mapping map[string]P.ProxyProvider, list []string) ([]P.ProxyProvider, error) {
var ps []P.ProxyProvider
for _, name := range list {
p, ok := mapping[name]
if !ok {
return nil, fmt.Errorf("'%s' not found", name)
}
if p.VehicleType() == types.Compatible {
if p.VehicleType() == P.Compatible {
return nil, fmt.Errorf("proxy group %s can't contains in `use`", name)
}
ps = append(ps, p)
@@ -222,7 +222,7 @@ func getProviders(mapping map[string]types.ProxyProvider, list []string) ([]type
return ps, nil
}
func addTestUrlToProviders(providers []types.ProxyProvider, url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) {
func addTestUrlToProviders(providers []P.ProxyProvider, url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) {
if len(providers) == 0 || len(url) == 0 {
return
}
@@ -4,22 +4,22 @@ package outboundgroup
import (
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
type ProxyGroup interface {
C.ProxyAdapter
Providers() []provider.ProxyProvider
Providers() []P.ProxyProvider
Proxies() []C.Proxy
Now() string
}
func (f *Fallback) Providers() []provider.ProxyProvider {
func (f *Fallback) Providers() []P.ProxyProvider {
return f.providers
}
func (lb *LoadBalance) Providers() []provider.ProxyProvider {
func (lb *LoadBalance) Providers() []P.ProxyProvider {
return lb.providers
}
@@ -35,7 +35,7 @@ func (lb *LoadBalance) Now() string {
return ""
}
func (r *Relay) Providers() []provider.ProxyProvider {
func (r *Relay) Providers() []P.ProxyProvider {
return r.providers
}
@@ -47,7 +47,7 @@ func (r *Relay) Now() string {
return ""
}
func (s *Selector) Providers() []provider.ProxyProvider {
func (s *Selector) Providers() []P.ProxyProvider {
return s.providers
}
@@ -55,7 +55,7 @@ func (s *Selector) Proxies() []C.Proxy {
return s.GetProxies(false)
}
func (u *URLTest) Providers() []provider.ProxyProvider {
func (u *URLTest) Providers() []P.ProxyProvider {
return u.providers
}
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
)
@@ -149,7 +149,7 @@ func (r *Relay) Addr() string {
return proxies[len(proxies)-1].Addr()
}
func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
func NewRelay(option *GroupCommonOption, providers []P.ProxyProvider) *Relay {
log.Warnln("The group [%s] with relay type is deprecated, please using dialer-proxy instead", option.Name)
return &Relay{
GroupBase: NewGroupBase(GroupBaseOption{
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"errors"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
type Selector struct {
@@ -108,7 +108,7 @@ func (s *Selector) selectedProxy(touch bool) C.Proxy {
return proxies[0]
}
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Selector {
return &Selector{
GroupBase: NewGroupBase(GroupBaseOption{
Name: option.Name,
+2 -2
View File
@@ -11,7 +11,7 @@ import (
"github.com/metacubex/mihomo/common/singledo"
"github.com/metacubex/mihomo/common/utils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
type urlTestOption func(*URLTest)
@@ -202,7 +202,7 @@ func parseURLTestOption(config map[string]any) []urlTestOption {
return opts
}
func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, options ...urlTestOption) *URLTest {
func NewURLTest(option *GroupCommonOption, providers []P.ProxyProvider, options ...urlTestOption) *URLTest {
urlTest := &URLTest{
GroupBase: NewGroupBase(GroupBaseOption{
Name: option.Name,
+3 -3
View File
@@ -10,7 +10,7 @@ import (
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/resource"
C "github.com/metacubex/mihomo/constant"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/dlclark/regexp2"
)
@@ -73,7 +73,7 @@ type proxyProviderSchema struct {
Header map[string][]string `provider:"header,omitempty"`
}
func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) {
func ParseProxyProvider(name string, mapping map[string]any) (P.ProxyProvider, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
schema := &proxyProviderSchema{
@@ -104,7 +104,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
return nil, err
}
var vehicle types.Vehicle
var vehicle P.Vehicle
switch schema.Type {
case "file":
path := C.Path.Resolve(schema.Path)
+8 -8
View File
@@ -16,7 +16,7 @@ import (
"github.com/metacubex/mihomo/component/profile/cachefile"
"github.com/metacubex/mihomo/component/resource"
C "github.com/metacubex/mihomo/constant"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/tunnel/statistic"
"github.com/dlclark/regexp2"
@@ -68,8 +68,8 @@ func (bp *baseProvider) HealthCheck() {
bp.healthCheck.check()
}
func (bp *baseProvider) Type() types.ProviderType {
return types.Proxy
func (bp *baseProvider) Type() P.ProviderType {
return P.Proxy
}
func (bp *baseProvider) Proxies() []C.Proxy {
@@ -171,7 +171,7 @@ func (pp *proxySetProvider) Close() error {
return pp.Fetcher.Close()
}
func NewProxySetProvider(name string, interval time.Duration, payload []map[string]any, parser resource.Parser[[]C.Proxy], vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
func NewProxySetProvider(name string, interval time.Duration, payload []map[string]any, parser resource.Parser[[]C.Proxy], vehicle P.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
pd := &proxySetProvider{
baseProvider: baseProvider{
name: name,
@@ -238,8 +238,8 @@ func (ip *inlineProvider) MarshalJSON() ([]byte, error) {
})
}
func (ip *inlineProvider) VehicleType() types.VehicleType {
return types.Inline
func (ip *inlineProvider) VehicleType() P.VehicleType {
return P.Inline
}
func (ip *inlineProvider) Update() error {
@@ -303,8 +303,8 @@ func (cp *compatibleProvider) Update() error {
return nil
}
func (cp *compatibleProvider) VehicleType() types.VehicleType {
return types.Compatible
func (cp *compatibleProvider) VehicleType() P.VehicleType {
return P.Compatible
}
func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) {
+7 -7
View File
@@ -8,7 +8,7 @@ import (
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/slowdown"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/fswatch"
@@ -22,7 +22,7 @@ type Fetcher[V any] struct {
ctxCancel context.CancelFunc
resourceType string
name string
vehicle types.Vehicle
vehicle P.Vehicle
updatedAt time.Time
hash utils.HashType
parser Parser[V]
@@ -37,11 +37,11 @@ func (f *Fetcher[V]) Name() string {
return f.name
}
func (f *Fetcher[V]) Vehicle() types.Vehicle {
func (f *Fetcher[V]) Vehicle() P.Vehicle {
return f.vehicle
}
func (f *Fetcher[V]) VehicleType() types.VehicleType {
func (f *Fetcher[V]) VehicleType() P.VehicleType {
return f.vehicle.Type()
}
@@ -88,7 +88,7 @@ func (f *Fetcher[V]) Update() (V, bool, error) {
f.backoff.AddAttempt() // add a failed attempt to backoff
return lo.Empty[V](), false, err
}
return f.loadBuf(buf, hash, f.vehicle.Type() != types.File)
return f.loadBuf(buf, hash, f.vehicle.Type() != P.File)
}
func (f *Fetcher[V]) SideUpdate(buf []byte) (V, bool, error) {
@@ -180,7 +180,7 @@ func (f *Fetcher[V]) pullLoop(forceUpdate bool) {
func (f *Fetcher[V]) startPullLoop(forceUpdate bool) (err error) {
// pull contents automatically
if f.vehicle.Type() == types.File {
if f.vehicle.Type() == P.File {
f.watcher, err = fswatch.NewWatcher(fswatch.Options{
Path: []string{f.vehicle.Path()},
Callback: f.updateCallback,
@@ -218,7 +218,7 @@ func (f *Fetcher[V]) updateWithLog() {
return
}
func NewFetcher[V any](name string, interval time.Duration, vehicle types.Vehicle, parser Parser[V], onUpdate func(V)) *Fetcher[V] {
func NewFetcher[V any](name string, interval time.Duration, vehicle P.Vehicle, parser Parser[V], onUpdate func(V)) *Fetcher[V] {
ctx, cancel := context.WithCancel(context.Background())
minBackoff := 10 * time.Second
if interval < minBackoff {
+6 -6
View File
@@ -12,7 +12,7 @@ import (
"github.com/metacubex/mihomo/common/utils"
mihomoHttp "github.com/metacubex/mihomo/component/http"
"github.com/metacubex/mihomo/component/profile/cachefile"
types "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
)
const (
@@ -50,8 +50,8 @@ type FileVehicle struct {
path string
}
func (f *FileVehicle) Type() types.VehicleType {
return types.File
func (f *FileVehicle) Type() P.VehicleType {
return P.File
}
func (f *FileVehicle) Path() string {
@@ -91,15 +91,15 @@ type HTTPVehicle struct {
timeout time.Duration
sizeLimit int64
inRead func(response *http.Response)
provider types.ProxyProvider
provider P.ProxyProvider
}
func (h *HTTPVehicle) Url() string {
return h.url
}
func (h *HTTPVehicle) Type() types.VehicleType {
return types.HTTP
func (h *HTTPVehicle) Type() P.VehicleType {
return P.HTTP
}
func (h *HTTPVehicle) Path() string {
+97 -96
View File
@@ -20,15 +20,15 @@ import (
"github.com/metacubex/mihomo/component/cidr"
"github.com/metacubex/mihomo/component/fakeip"
"github.com/metacubex/mihomo/component/geodata"
P "github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/component/sniffer"
"github.com/metacubex/mihomo/component/trie"
C "github.com/metacubex/mihomo/constant"
providerTypes "github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
snifferTypes "github.com/metacubex/mihomo/constant/sniffer"
"github.com/metacubex/mihomo/dns"
L "github.com/metacubex/mihomo/listener"
"github.com/metacubex/mihomo/listener"
LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/log"
R "github.com/metacubex/mihomo/rules"
@@ -44,27 +44,27 @@ import (
// General config
type General struct {
Inbound
Mode T.TunnelMode `json:"mode"`
UnifiedDelay bool `json:"unified-delay"`
LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"`
Interface string `json:"interface-name"`
RoutingMark int `json:"routing-mark"`
GeoXUrl GeoXUrl `json:"geox-url"`
GeoAutoUpdate bool `json:"geo-auto-update"`
GeoUpdateInterval int `json:"geo-update-interval"`
GeodataMode bool `json:"geodata-mode"`
GeodataLoader string `json:"geodata-loader"`
GeositeMatcher string `json:"geosite-matcher"`
TCPConcurrent bool `json:"tcp-concurrent"`
FindProcessMode P.FindProcessMode `json:"find-process-mode"`
Sniffing bool `json:"sniffing"`
GlobalClientFingerprint string `json:"global-client-fingerprint"`
GlobalUA string `json:"global-ua"`
ETagSupport bool `json:"etag-support"`
KeepAliveIdle int `json:"keep-alive-idle"`
KeepAliveInterval int `json:"keep-alive-interval"`
DisableKeepAlive bool `json:"disable-keep-alive"`
Mode T.TunnelMode `json:"mode"`
UnifiedDelay bool `json:"unified-delay"`
LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"`
Interface string `json:"interface-name"`
RoutingMark int `json:"routing-mark"`
GeoXUrl GeoXUrl `json:"geox-url"`
GeoAutoUpdate bool `json:"geo-auto-update"`
GeoUpdateInterval int `json:"geo-update-interval"`
GeodataMode bool `json:"geodata-mode"`
GeodataLoader string `json:"geodata-loader"`
GeositeMatcher string `json:"geosite-matcher"`
TCPConcurrent bool `json:"tcp-concurrent"`
FindProcessMode process.FindProcessMode `json:"find-process-mode"`
Sniffing bool `json:"sniffing"`
GlobalClientFingerprint string `json:"global-client-fingerprint"`
GlobalUA string `json:"global-ua"`
ETagSupport bool `json:"etag-support"`
KeepAliveIdle int `json:"keep-alive-idle"`
KeepAliveInterval int `json:"keep-alive-interval"`
DisableKeepAlive bool `json:"disable-keep-alive"`
}
// Inbound config
@@ -199,8 +199,8 @@ type Config struct {
Users []auth.AuthUser
Proxies map[string]C.Proxy
Listeners map[string]C.InboundListener
Providers map[string]providerTypes.ProxyProvider
RuleProviders map[string]providerTypes.RuleProvider
Providers map[string]P.ProxyProvider
RuleProviders map[string]P.RuleProvider
Tunnels []LC.Tunnel
Sniffer *sniffer.Config
TLS *TLS
@@ -382,51 +382,51 @@ type RawTLS struct {
}
type RawConfig struct {
Port int `yaml:"port" json:"port"`
SocksPort int `yaml:"socks-port" json:"socks-port"`
RedirPort int `yaml:"redir-port" json:"redir-port"`
TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"`
MixedPort int `yaml:"mixed-port" json:"mixed-port"`
ShadowSocksConfig string `yaml:"ss-config" json:"ss-config"`
VmessConfig string `yaml:"vmess-config" json:"vmess-config"`
InboundTfo bool `yaml:"inbound-tfo" json:"inbound-tfo"`
InboundMPTCP bool `yaml:"inbound-mptcp" json:"inbound-mptcp"`
Authentication []string `yaml:"authentication" json:"authentication"`
SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes" json:"skip-auth-prefixes"`
LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips" json:"lan-allowed-ips"`
LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips" json:"lan-disallowed-ips"`
AllowLan bool `yaml:"allow-lan" json:"allow-lan"`
BindAddress string `yaml:"bind-address" json:"bind-address"`
Mode T.TunnelMode `yaml:"mode" json:"mode"`
UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"`
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
IPv6 bool `yaml:"ipv6" json:"ipv6"`
ExternalController string `yaml:"external-controller" json:"external-controller"`
ExternalControllerPipe string `yaml:"external-controller-pipe" json:"external-controller-pipe"`
ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"`
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
ExternalControllerCors RawCors `yaml:"external-controller-cors" json:"external-controller-cors"`
ExternalUI string `yaml:"external-ui" json:"external-ui"`
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
ExternalDohServer string `yaml:"external-doh-server" json:"external-doh-server"`
Secret string `yaml:"secret" json:"secret"`
Interface string `yaml:"interface-name" json:"interface-name"`
RoutingMark int `yaml:"routing-mark" json:"routing-mark"`
Tunnels []LC.Tunnel `yaml:"tunnels" json:"tunnels"`
GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"`
GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"`
GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"`
GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"`
GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"`
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"`
GlobalClientFingerprint string `yaml:"global-client-fingerprint" json:"global-client-fingerprint"`
GlobalUA string `yaml:"global-ua" json:"global-ua"`
ETagSupport bool `yaml:"etag-support" json:"etag-support"`
KeepAliveIdle int `yaml:"keep-alive-idle" json:"keep-alive-idle"`
KeepAliveInterval int `yaml:"keep-alive-interval" json:"keep-alive-interval"`
DisableKeepAlive bool `yaml:"disable-keep-alive" json:"disable-keep-alive"`
Port int `yaml:"port" json:"port"`
SocksPort int `yaml:"socks-port" json:"socks-port"`
RedirPort int `yaml:"redir-port" json:"redir-port"`
TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"`
MixedPort int `yaml:"mixed-port" json:"mixed-port"`
ShadowSocksConfig string `yaml:"ss-config" json:"ss-config"`
VmessConfig string `yaml:"vmess-config" json:"vmess-config"`
InboundTfo bool `yaml:"inbound-tfo" json:"inbound-tfo"`
InboundMPTCP bool `yaml:"inbound-mptcp" json:"inbound-mptcp"`
Authentication []string `yaml:"authentication" json:"authentication"`
SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes" json:"skip-auth-prefixes"`
LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips" json:"lan-allowed-ips"`
LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips" json:"lan-disallowed-ips"`
AllowLan bool `yaml:"allow-lan" json:"allow-lan"`
BindAddress string `yaml:"bind-address" json:"bind-address"`
Mode T.TunnelMode `yaml:"mode" json:"mode"`
UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"`
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
IPv6 bool `yaml:"ipv6" json:"ipv6"`
ExternalController string `yaml:"external-controller" json:"external-controller"`
ExternalControllerPipe string `yaml:"external-controller-pipe" json:"external-controller-pipe"`
ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"`
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
ExternalControllerCors RawCors `yaml:"external-controller-cors" json:"external-controller-cors"`
ExternalUI string `yaml:"external-ui" json:"external-ui"`
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
ExternalDohServer string `yaml:"external-doh-server" json:"external-doh-server"`
Secret string `yaml:"secret" json:"secret"`
Interface string `yaml:"interface-name" json:"interface-name"`
RoutingMark int `yaml:"routing-mark" json:"routing-mark"`
Tunnels []LC.Tunnel `yaml:"tunnels" json:"tunnels"`
GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"`
GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"`
GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"`
GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"`
GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"`
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
FindProcessMode process.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"`
GlobalClientFingerprint string `yaml:"global-client-fingerprint" json:"global-client-fingerprint"`
GlobalUA string `yaml:"global-ua" json:"global-ua"`
ETagSupport bool `yaml:"etag-support" json:"etag-support"`
KeepAliveIdle int `yaml:"keep-alive-idle" json:"keep-alive-idle"`
KeepAliveInterval int `yaml:"keep-alive-interval" json:"keep-alive-interval"`
DisableKeepAlive bool `yaml:"disable-keep-alive" json:"disable-keep-alive"`
ProxyProvider map[string]map[string]any `yaml:"proxy-providers" json:"proxy-providers"`
RuleProvider map[string]map[string]any `yaml:"rule-providers" json:"rule-providers"`
@@ -479,7 +479,7 @@ func DefaultRawConfig() *RawConfig {
Proxy: []map[string]any{},
ProxyGroup: []map[string]any{},
TCPConcurrent: false,
FindProcessMode: P.FindProcessStrict,
FindProcessMode: process.FindProcessStrict,
GlobalUA: "clash.meta/" + C.Version,
ETagSupport: true,
DNS: RawDNS{
@@ -653,11 +653,11 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
config.Proxies = proxies
config.Providers = providers
listener, err := parseListeners(rawCfg)
listeners, err := parseListeners(rawCfg)
if err != nil {
return nil, err
}
config.Listeners = listener
config.Listeners = listeners
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
log.Infoln("Geosite Matcher implementation: %s", geodata.SiteMatcherName())
@@ -845,9 +845,9 @@ func parseTLS(cfg *RawConfig) (*TLS, error) {
}, nil
}
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]P.ProxyProvider, err error) {
proxies = make(map[string]C.Proxy)
providersMap = make(map[string]providerTypes.ProxyProvider)
providersMap = make(map[string]P.ProxyProvider)
proxiesConfig := cfg.Proxy
groupsConfig := cfg.ProxyGroup
providersConfig := cfg.ProxyProvider
@@ -947,7 +947,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
&outboundgroup.GroupCommonOption{
Name: "GLOBAL",
},
[]providerTypes.ProxyProvider{pd},
[]P.ProxyProvider{pd},
)
proxies["GLOBAL"] = adapter.NewProxy(global)
}
@@ -957,24 +957,25 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
func parseListeners(cfg *RawConfig) (listeners map[string]C.InboundListener, err error) {
listeners = make(map[string]C.InboundListener)
for index, mapping := range cfg.Listeners {
listener, err := L.ParseListener(mapping)
inboundListener, err := listener.ParseListener(mapping)
if err != nil {
return nil, fmt.Errorf("proxy %d: %w", index, err)
}
if _, exist := mapping[listener.Name()]; exist {
return nil, fmt.Errorf("listener %s is the duplicate name", listener.Name())
name := inboundListener.Name()
if _, exist := mapping[name]; exist {
return nil, fmt.Errorf("listener %s is the duplicate name", name)
}
listeners[listener.Name()] = listener
listeners[name] = inboundListener
}
return
}
func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]providerTypes.RuleProvider, err error) {
func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]P.RuleProvider, err error) {
RP.SetTunnel(T.Tunnel)
ruleProviders = map[string]providerTypes.RuleProvider{}
ruleProviders = map[string]P.RuleProvider{}
// parse rule provider
for name, mapping := range cfg.RuleProvider {
rp, err := RP.ParseRuleProvider(name, mapping, R.ParseRule)
@@ -987,7 +988,7 @@ func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]providerTypes.
return
}
func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy, ruleProviders map[string]providerTypes.RuleProvider) (subRules map[string][]C.Rule, err error) {
func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy, ruleProviders map[string]P.RuleProvider) (subRules map[string][]C.Rule, err error) {
subRules = map[string][]C.Rule{}
for name := range cfg.SubRules {
subRules[name] = make([]C.Rule, 0)
@@ -1050,7 +1051,7 @@ func verifySubRuleCircularReferences(n string, subRules map[string][]C.Rule, arr
return nil
}
func parseRules(rulesConfig []string, proxies map[string]C.Proxy, ruleProviders map[string]providerTypes.RuleProvider, subRules map[string][]C.Rule, format string) ([]C.Rule, error) {
func parseRules(rulesConfig []string, proxies map[string]C.Proxy, ruleProviders map[string]P.RuleProvider, subRules map[string][]C.Rule, format string) ([]C.Rule, error) {
var rules []C.Rule
// parse rules
@@ -1273,7 +1274,7 @@ func parsePureDNSServer(server string) string {
}
}
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]P.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
var policy []dns.Policy
for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() {
@@ -1348,7 +1349,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro
return policy, nil
}
func parseDNS(rawCfg *RawConfig, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) {
func parseDNS(rawCfg *RawConfig, ruleProviders map[string]P.RuleProvider) (*DNS, error) {
cfg := rawCfg.DNS
if cfg.Enable && len(cfg.NameServer) == 0 {
return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
@@ -1632,7 +1633,7 @@ func parseTuicServer(rawTuic RawTuicServer, general *General) error {
return nil
}
func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]providerTypes.RuleProvider) (*sniffer.Config, error) {
func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]P.RuleProvider) (*sniffer.Config, error) {
snifferConfig := &sniffer.Config{
Enable: snifferRaw.Enable,
ForceDnsMapping: snifferRaw.ForceDnsMapping,
@@ -1722,7 +1723,7 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]providerTypes.
return snifferConfig, nil
}
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.IpMatcher, err error) {
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]P.RuleProvider) (matchers []C.IpMatcher, err error) {
var matcher C.IpMatcher
for _, ipcidr := range addresses {
ipcidrLower := strings.ToLower(ipcidr)
@@ -1769,7 +1770,7 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
return
}
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.DomainMatcher, err error) {
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]P.RuleProvider) (matchers []C.DomainMatcher, err error) {
var matcher C.DomainMatcher
for _, domain := range domains {
domainLower := strings.ToLower(domain)
@@ -1812,14 +1813,14 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
return
}
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.IpMatcher, error) {
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]P.RuleProvider) (C.IpMatcher, error) {
if rp, ok := ruleProviders[domainSetName]; !ok {
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
} else {
switch rp.Behavior() {
case providerTypes.Domain:
case P.Domain:
return nil, fmt.Errorf("rule provider type error, except ipcidr,actual %s", rp.Behavior())
case providerTypes.Classical:
case P.Classical:
log.Warnln("%s provider is %s, only matching it contain ip rule", rp.Name(), rp.Behavior())
default:
}
@@ -1827,14 +1828,14 @@ func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[
return RP.NewRuleSet(domainSetName, adapterName, false, true)
}
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.DomainMatcher, error) {
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]P.RuleProvider) (C.DomainMatcher, error) {
if rp, ok := ruleProviders[domainSetName]; !ok {
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
} else {
switch rp.Behavior() {
case providerTypes.IPCIDR:
case P.IPCIDR:
return nil, fmt.Errorf("rule provider type error, except domain,actual %s", rp.Behavior())
case providerTypes.Classical:
case P.Classical:
log.Warnln("%s provider is %s, only matching it contain domain rule", rp.Name(), rp.Behavior())
default:
}
+8 -8
View File
@@ -31,7 +31,7 @@ import (
"github.com/metacubex/mihomo/component/updater"
"github.com/metacubex/mihomo/config"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/dns"
"github.com/metacubex/mihomo/listener"
authStore "github.com/metacubex/mihomo/listener/auth"
@@ -303,18 +303,18 @@ func updateHosts(tree *trie.DomainTrie[resolver.HostValue]) {
resolver.DefaultHosts = resolver.NewHosts(tree)
}
func updateProxies(proxies map[string]C.Proxy, providers map[string]provider.ProxyProvider) {
func updateProxies(proxies map[string]C.Proxy, providers map[string]P.ProxyProvider) {
tunnel.UpdateProxies(proxies, providers)
}
func updateRules(rules []C.Rule, subRules map[string][]C.Rule, ruleProviders map[string]provider.RuleProvider) {
func updateRules(rules []C.Rule, subRules map[string][]C.Rule, ruleProviders map[string]P.RuleProvider) {
tunnel.UpdateRules(rules, subRules, ruleProviders)
}
func loadProvider[P provider.Provider](providers map[string]P) {
load := func(pv P) {
func loadProvider[T P.Provider](providers map[string]T) {
load := func(pv T) {
name := pv.Name()
if pv.VehicleType() == provider.Compatible {
if pv.VehicleType() == P.Compatible {
log.Infoln("Start initial compatible provider %s", name)
} else {
log.Infoln("Start initial provider %s", name)
@@ -322,11 +322,11 @@ func loadProvider[P provider.Provider](providers map[string]P) {
if err := pv.Initial(); err != nil {
switch pv.Type() {
case provider.Proxy:
case P.Proxy:
{
log.Errorln("initial proxy provider %s error: %v", name, err)
}
case provider.Rule:
case P.Rule:
{
log.Errorln("initial rule provider %s error: %v", name, err)
}
+13 -13
View File
@@ -13,7 +13,7 @@ import (
"github.com/metacubex/mihomo/config"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/hub/executor"
P "github.com/metacubex/mihomo/listener"
"github.com/metacubex/mihomo/listener"
LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/tunnel"
@@ -306,7 +306,7 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
}
if general.AllowLan != nil {
P.SetAllowLan(*general.AllowLan)
listener.SetAllowLan(*general.AllowLan)
}
if general.SkipAuthPrefixes != nil {
@@ -322,7 +322,7 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
}
if general.BindAddress != nil {
P.SetBindAddress(*general.BindAddress)
listener.SetBindAddress(*general.BindAddress)
}
if general.Sniffing != nil {
@@ -337,17 +337,17 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
dialer.DefaultInterface.Store(*general.InterfaceName)
}
ports := P.GetPorts()
ports := listener.GetPorts()
P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tunnel.Tunnel)
P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tunnel.Tunnel)
P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tunnel.Tunnel)
P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tunnel.Tunnel)
P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tunnel.Tunnel)
P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tunnel.Tunnel)
P.ReCreateShadowSocks(pointerOrDefault(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel)
P.ReCreateVmess(pointerOrDefault(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel)
P.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, P.LastTuicConf), tunnel.Tunnel)
listener.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tunnel.Tunnel)
listener.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tunnel.Tunnel)
listener.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tunnel.Tunnel)
listener.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tunnel.Tunnel)
listener.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tunnel.Tunnel)
listener.ReCreateTun(pointerOrDefaultTun(general.Tun, listener.LastTunConf), tunnel.Tunnel)
listener.ReCreateShadowSocks(pointerOrDefault(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel)
listener.ReCreateVmess(pointerOrDefault(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel)
listener.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, listener.LastTuicConf), tunnel.Tunnel)
if general.Mode != nil {
tunnel.SetMode(*general.Mode)
+6 -6
View File
@@ -5,7 +5,7 @@ import (
"net/http"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/tunnel"
"github.com/go-chi/chi/v5"
@@ -45,12 +45,12 @@ func getProviders(w http.ResponseWriter, r *http.Request) {
}
func getProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
provider := r.Context().Value(CtxKeyProvider).(P.ProxyProvider)
render.JSON(w, r, provider)
}
func updateProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
provider := r.Context().Value(CtxKeyProvider).(P.ProxyProvider)
if err := provider.Update(); err != nil {
render.Status(r, http.StatusServiceUnavailable)
render.JSON(w, r, newError(err.Error()))
@@ -60,7 +60,7 @@ func updateProvider(w http.ResponseWriter, r *http.Request) {
}
func healthCheckProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
provider := r.Context().Value(CtxKeyProvider).(P.ProxyProvider)
provider.HealthCheck()
render.NoContent(w, r)
}
@@ -93,7 +93,7 @@ func findProviderProxyByName(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var (
name = r.Context().Value(CtxKeyProxyName).(string)
pd = r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
pd = r.Context().Value(CtxKeyProvider).(P.ProxyProvider)
)
proxy, exist := lo.Find(pd.Proxies(), func(proxy C.Proxy) bool {
return proxy.Name() == name
@@ -128,7 +128,7 @@ func getRuleProviders(w http.ResponseWriter, r *http.Request) {
}
func updateRuleProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(provider.RuleProvider)
provider := r.Context().Value(CtxKeyProvider).(P.RuleProvider)
if err := provider.Update(); err != nil {
render.Status(r, http.StatusServiceUnavailable)
render.JSON(w, r, newError(err.Error()))
+4 -4
View File
@@ -18,7 +18,7 @@ import (
"github.com/metacubex/mihomo/component/iface"
"github.com/metacubex/mihomo/component/resolver"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/listener/sing"
"github.com/metacubex/mihomo/log"
@@ -133,7 +133,7 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis
}
}
ctx := context.TODO()
rpTunnel := tunnel.(provider.Tunnel)
rpTunnel := tunnel.(P.Tunnel)
if options.GSOMaxSize == 0 {
options.GSOMaxSize = 65536
}
@@ -504,7 +504,7 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis
return
}
func (l *Listener) ruleUpdateCallback(ruleProvider provider.RuleProvider) {
func (l *Listener) ruleUpdateCallback(ruleProvider P.RuleProvider) {
name := ruleProvider.Name()
if slices.Contains(l.options.RouteAddressSet, name) {
l.updateRule(ruleProvider, false, true)
@@ -520,7 +520,7 @@ type toIpCidr interface {
ToIpCidr() *netipx.IPSet
}
func (l *Listener) updateRule(ruleProvider provider.RuleProvider, exclude bool, update bool) {
func (l *Listener) updateRule(ruleProvider P.RuleProvider, exclude bool, update bool) {
l.ruleUpdateMutex.Lock()
defer l.ruleUpdateMutex.Unlock()
name := ruleProvider.Name()
+21 -21
View File
@@ -17,13 +17,13 @@ import (
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/loopback"
"github.com/metacubex/mihomo/component/nat"
P "github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/component/slowdown"
"github.com/metacubex/mihomo/component/sniffer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/features"
"github.com/metacubex/mihomo/constant/provider"
P "github.com/metacubex/mihomo/constant/provider"
icontext "github.com/metacubex/mihomo/context"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/tunnel/statistic"
@@ -43,8 +43,8 @@ var (
listeners = make(map[string]C.InboundListener)
subRules map[string][]C.Rule
proxies = make(map[string]C.Proxy)
providers map[string]provider.ProxyProvider
ruleProviders map[string]provider.RuleProvider
providers map[string]P.ProxyProvider
ruleProviders map[string]P.RuleProvider
configMux sync.RWMutex
// for compatibility, lazy init
@@ -59,19 +59,19 @@ var (
// default timeout for UDP session
udpTimeout = 60 * time.Second
findProcessMode = atomic.NewInt32Enum(P.FindProcessStrict)
findProcessMode = atomic.NewInt32Enum(process.FindProcessStrict)
snifferDispatcher *sniffer.Dispatcher
sniffingEnable = false
ruleUpdateCallback = utils.NewCallback[provider.RuleProvider]()
ruleUpdateCallback = utils.NewCallback[P.RuleProvider]()
)
type tunnel struct{}
var Tunnel = tunnel{}
var _ C.Tunnel = Tunnel
var _ provider.Tunnel = Tunnel
var _ P.Tunnel = Tunnel
func (t tunnel) HandleTCPConn(conn net.Conn, metadata *C.Metadata) {
connCtx := icontext.NewConnContext(conn, metadata)
@@ -112,15 +112,15 @@ func (t tunnel) NatTable() C.NatTable {
return natTable
}
func (t tunnel) Providers() map[string]provider.ProxyProvider {
func (t tunnel) Providers() map[string]P.ProxyProvider {
return providers
}
func (t tunnel) RuleProviders() map[string]provider.RuleProvider {
func (t tunnel) RuleProviders() map[string]P.RuleProvider {
return ruleProviders
}
func (t tunnel) RuleUpdateCallback() *utils.Callback[provider.RuleProvider] {
func (t tunnel) RuleUpdateCallback() *utils.Callback[P.RuleProvider] {
return ruleUpdateCallback
}
@@ -195,7 +195,7 @@ func Listeners() map[string]C.InboundListener {
}
// UpdateRules handle update rules
func UpdateRules(newRules []C.Rule, newSubRule map[string][]C.Rule, rp map[string]provider.RuleProvider) {
func UpdateRules(newRules []C.Rule, newSubRule map[string][]C.Rule, rp map[string]P.RuleProvider) {
configMux.Lock()
rules = newRules
ruleProviders = rp
@@ -223,17 +223,17 @@ func ProxiesWithProviders() map[string]C.Proxy {
}
// Providers return all compatible providers
func Providers() map[string]provider.ProxyProvider {
func Providers() map[string]P.ProxyProvider {
return providers
}
// RuleProviders return all loaded rule providers
func RuleProviders() map[string]provider.RuleProvider {
func RuleProviders() map[string]P.RuleProvider {
return ruleProviders
}
// UpdateProxies handle update proxies
func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]provider.ProxyProvider) {
func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]P.ProxyProvider) {
configMux.Lock()
proxies = newProxies
providers = newProviders
@@ -263,13 +263,13 @@ func SetMode(m TunnelMode) {
mode = m
}
func FindProcessMode() P.FindProcessMode {
func FindProcessMode() process.FindProcessMode {
return findProcessMode.Load()
}
// SetFindProcessMode replace SetAlwaysFindProcess
// always find process info if legacyAlways = true or mode.Always() = true, may be increase many memory
func SetFindProcessMode(mode P.FindProcessMode) {
func SetFindProcessMode(mode process.FindProcessMode) {
findProcessMode.Store(mode)
}
@@ -358,7 +358,7 @@ func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err erro
attemptProcessLookup = false
if !features.CMFA {
// normal check for process
uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort))
uid, path, err := process.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort))
if err != nil {
log.Debugln("[Process] find process error for %s: %v", metadata.String(), err)
} else {
@@ -366,13 +366,13 @@ func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err erro
metadata.ProcessPath = path
metadata.Uid = uid
if pkg, err := P.FindPackageName(metadata); err == nil { // for android (not CMFA) package names
if pkg, err := process.FindPackageName(metadata); err == nil { // for android (not CMFA) package names
metadata.Process = pkg
}
}
} else {
// check package names
pkg, err := P.FindPackageName(metadata)
pkg, err := process.FindPackageName(metadata)
if err != nil {
log.Debugln("[Process] find process error for %s: %v", metadata.String(), err)
} else {
@@ -384,10 +384,10 @@ func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err erro
}
switch FindProcessMode() {
case P.FindProcessAlways:
case process.FindProcessAlways:
helper.FindProcess()
helper.FindProcess = nil
case P.FindProcessOff:
case process.FindProcessOff:
helper.FindProcess = nil
}
+2 -2
View File
@@ -7,8 +7,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-ddns-go
PKG_VERSION:=1.6.3
PKG_RELEASE:=20251025
PKG_VERSION:=1.6.4
PKG_RELEASE:=20251106
PKG_MAINTAINER:=sirpdboy <herboy2008@gmail.com>
PKG_CONFIG_DEPENDS:=
@@ -77,8 +77,8 @@ function renderStatus(isRunning, listen_port, noweb, version) {
);
if (isRunning) {
html += String.format('&#160;<a class="btn cbi-button" href="%s//%s:%s" target="_blank">%s</a>',
window.location.protocol, window.location.hostname, listen_port, _('Open Web Interface'));
html += String.format('&#160;<a class="btn cbi-button" href="http://%s:%s" target="_blank">%s</a>',
window.location.hostname, listen_port, _('Open Web Interface'));
}
return html;
@@ -21,57 +21,84 @@ return view.extend({
});
});
},
render: function() {
var self = this;
render: function() {
var self = this;
return this.checkRunning().then(function(checkResult) {
var isRunning = checkResult.isRunning;
var port = uci.get('ddns-go', 'config', 'port') || '[::]:9876';
var noweb = uci.get('ddns-go', 'config', 'noweb');
port = port.split(':').pop();
return this.checkRunning().then(function(checkResult) {
var isRunning = checkResult.isRunning;
var port = uci.get('ddns-go', 'config', 'port') || '[::]:9876';
var noweb = uci.get('ddns-go', 'config', 'noweb') ;
port = port.split(':').pop();
var container = E('div');
console.log('Debug: isRunning=' + isRunning + ', noweb=' + noweb + ', port=' + port);
if (!isRunning || noweb === '1') {
var container = E('div');
if (!isRunning || noweb === '1') {
if (!isRunning) {
var message = _('DDNS-GO Service Not Running');
}
if (noweb === '1') {
if (noweb === '1') {
var message = _('DDNS-GO Web Interface Disabled');
}
container.appendChild(E('div', {
style: 'text-align: center; padding: 2em;'
container.appendChild(E('div', {
style: 'text-align: center; padding: 2em;'
}, [
E('img', {
src: 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMjQiIGhlaWdodD0iMTAyNCIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCI+PHBhdGggZmlsbD0iI2RmMDAwMCIgZD0iTTk0Mi40MjEgMjM0LjYyNGw4MC44MTEtODAuODExLTE1My4wNDUtMTUzLjA0NS04MC44MTEgODAuODExYy03OS45NTctNTEuNjI3LTE3NS4xNDctODEuNTc5LTI3Ny4zNzYtODEuNTc5LTI4Mi43NTIgMC01MTIgMjI5LjI0OC01MTIgNTEyIDAgMTAyLjIyOSAyOS45NTIgMTk3LjQxOSA4MS41NzkgMjc3LjM3NmwtODAuODExIDgwLjgxMSAxNTMuMDQ1IDE1My4wNDUgODAuODExLTgwLjgxMWM3OS45NTcgNTEuNjI3IDE3NS4xNDcgODEuNTc5IDI3Ny4zNzYgODEuNTc5IDI4Mi43NTIgMCA1MTItMjI5LjI0OCA1MTItNTEyIDAtMTAyLjIyOS0yOS45NTItMTk3LjQxOS04MS41NzktMjc3LjM3NnpNMTk0Ljk0NCA1MTJjMC0xNzUuMTA0IDE0MS45NTItMzE3LjA1NiAzMTcuMDU2LTMxNy4wNTYgNDggMCA5My40ODMgMTAuNjY3IDEzNC4yMjkgMjkuNzgxbC00MjEuNTQ3IDQyMS41NDdjLTE5LjA3Mi00MC43ODktMjkuNzM5LTg2LjI3Mi0yOS43MzktMTM0LjI3MnpNNTEyIDgyOS4wNTZjLTQ4IDAtOTMuNDgzLTEwLjY2Ny0xMzQuMjI5LTI5Ljc4MWw0MjEuNTQ3LTQyMS41NDdjMTkuMDcyIDQwLjc4OSAyOS43ODEgODYuMjcyIDI5Ljc4MSAxMzQuMjI5LTAuMDQzIDE3NS4xNDctMTQxLjk5NSAzMTcuMDk5LTMxNy4wOTkgMzE3LjA5OXoiLz48L3N2Zz4=',
style: 'width: 100px; height: 100px; margin-bottom: 1em;'
}),
E('h2', {}, message)
]));
} else {
var isHttps = window.location.protocol === 'https:';
if (isHttps) {
var buttonContainer = E('div', {
style: 'text-align: center; padding: 2em;'
}, [
E('img', {
src: 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMjQiIGhlaWdodD0iMTAyNCIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCI+PHBhdGggZmlsbD0iI2RmMDAwMCIgZD0iTTk0Mi40MjEgMjM0LjYyNGw4MC44MTEtODAuODExLTE1My4wNDUtMTUzLjA0NS04MC44MTEgODAuODExYy03OS45NTctNTEuNjI3LTE3NS4xNDctODEuNTc5LTI3Ny4zNzYtODEuNTc5LTI4Mi43NTIgMC01MTIgMjI5LjI0OC01MTIgNTEyIDAgMTAyLjIyOSAyOS45NTIgMTk3LjQxOSA4MS41NzkgMjc3LjM3NmwtODAuODExIDgwLjgxMSAxNTMuMDQ1IDE1My4wNDUgODAuODExLTgwLjgxMWM3OS45NTcgNTEuNjI3IDE3NS4xNDcgODEuNTc5IDI3Ny4zNzYgODEuNTc5IDI4Mi43NTIgMCA1MTItMjI5LjI0OCA1MTItNTEyIDAtMTAyLjIyOS0yOS45NTItMTk3LjQxOS04MS41NzktMjc3LjM3NnpNMTk0Ljk0NCA1MTJjMC0xNzUuMTA0IDE0MS45NTItMzE3LjA1NiAzMTcuMDU2LTMxNy4wNTYgNDggMCA5My40ODMgMTAuNjY3IDEzNC4yMjkgMjkuNzgxbC00MjEuNTQ3IDQyMS41NDdjLTE5LjA3Mi00MC43ODktMjkuNzM5LTg2LjI3Mi0yOS43MzktMTM0LjI3MnpNNTEyIDgyOS4wNTZjLTQ4IDAtOTMuNDgzLTEwLjY2Ny0xMzQuMjI5LTI5Ljc4MWw0MjEuNTQ3LTQyMS41NDdjMTkuMDcyIDQwLjc4OSAyOS43ODEgODYuMjcyIDI5Ljc4MSAxMzQuMjI5LTAuMDQzIDE3NS4xNDctMTQxLjk5NSAzMTcuMDk5LTMxNy4wOTkgMzE3LjA5OXoiLz48L3N2Zz4=',
style: 'width: 100px; height: 100px; margin-bottom: 1em;'
}),
E('h2', {}, message)
]));
E('h2', {}, _('DDNS-GO Control panel')),
E('p', {}, _('Due to browser security policies, the DDNS-GO interface https cannot be embedded directly.')),
E('a', {
href: 'http://' + window.location.hostname + ':' + port,
target: '_blank',
class: 'cbi-button cbi-button-apply',
style: 'display: inline-block; margin-top: 1em; padding: 10px 20px; font-size: 16px; text-decoration: none; color: white;'
}, _('Open Web Interface')),
E('div', { 'style': 'text-align: right; font-style: italic;' }, [
E('span', {}, [
_('© github '),
E('a', {
'href': 'https://github.com/sirpdboy',
'target': '_blank',
'style': 'text-decoration: none;'
}, 'by sirpdboy')
])
])
]);
container.appendChild(buttonContainer);
} else {
var iframe = E('iframe', {
src: window.location.protocol + '//' + window.location.hostname + ':' + port,
src: 'http://' + window.location.hostname + ':' + port,
style: 'width: 100%; min-height: 100vh; border: none;'
});
container.appendChild(iframe);
}
poll.add(function() {
return self.checkRunning().then(function(checkResult) {
var newStatus = checkResult.isRunning;
if (newStatus !== isRunning) {
window.location.reload();
}
});
}, 5);
poll.start();
return container;
});
},
}
poll.add(function() {
return self.checkRunning().then(function(checkResult) {
var newStatus = checkResult.isRunning;
if (newStatus !== isRunning) {
window.location.reload();
}
});
}, 5);
poll.start();
return container;
});
},
handleSaveApply: null,
handleSave: null,
@@ -118,5 +118,5 @@ msgstr "立刻重启服务"
msgid "Restart Later"
msgstr "稍后重启"
msgid ""
msgstr ""
msgid "Due to browser security policies, the DDNS-GO interface https cannot be embedded directly."
msgstr "由于浏览器安全策略,DDNS-GO接口https不能直接嵌入。"
+2 -2
View File
@@ -10,8 +10,8 @@ THEME_TITLE:=Kucat Theme
PKG_NAME:=luci-theme-$(THEME_NAME)
LUCI_TITLE:=Kucat Theme by sirpdboy
LUCI_DEPENDS:=
PKG_VERSION:=2.7.3
PKG_RELEASE:=20251028
PKG_VERSION:=2.7.4
PKG_RELEASE:=20251106
define Package/luci-theme-$(THEME_NAME)/conffiles
/www/luci-static/resources/background/
@@ -869,7 +869,7 @@ small {
.main-right>#maincontent {
position: relative;
background-color: rgba(var(--primary-rgbbody),var(--primary-rgbm-ts));
padding: 0.2rem 0.2rem 3rem 0.2rem;
padding: 0.2rem 0.2rem 3rem 0.5rem;
z-index: 50
}
@@ -960,7 +960,51 @@ header .fill .status span {
flex-wrap: nowrap
}
span[data-indicator="uci-changes"],span[data-indicator="poll-status"] {
span[data-indicator="poll-status"] {
font-size: 0 !important;
cursor: pointer;
background-repeat: no-repeat;
background-position: center;
color: transparent !important;
-webkit-appearance: none;
display: flex;
background-color: rgba(255, 255, 255, 0);
-moz-appearance: none;
padding: 1rem;
transition: all .3s
}
span[data-indicator="poll-status"]:not([data-style="inactive"]):before {
font-size: 1.5rem !important;
font-family: 'kucat' !important;
content: "\e20b";
color: var(--body-color);
text-decoration: none
}
span[data-indicator="poll-status"]:not([data-style="active"]):before {
font-size: 1.5rem !important;
font-family: 'kucat' !important;
content: "\e20a";
color: var(--body-color);
text-decoration: none
}
#indicators span[data-indicator="poll-status"],{
line-height: 1;
padding: 1rem;
cursor: pointer !important;
font-weight: normal !important;
margin: 0;
display: inline-block
}
#indicators span[data-indicator="poll-status"]:hover {
border-radius: var(--radius1);
text-decoration: none
}
span[data-indicator="uci-changes"],#indicators span[data-indicator="poll-status"] {
font-size: 0 !important;
cursor: pointer;
background-repeat: no-repeat;
@@ -979,7 +1023,7 @@ span[data-indicator="uci-changes"]:before {
text-decoration: none
}
span[data-indicator="poll-status"]:not([data-style="inactive"]):before {
#indicators span[data-indicator="poll-status"]:not([data-style="inactive"]):before {
font-size: 1.5rem !important;
font-family: 'kucat' !important;
content: "\e936";
@@ -987,7 +1031,7 @@ span[data-indicator="poll-status"]:not([data-style="inactive"]):before {
text-decoration: none
}
span[data-indicator="poll-status"]:not([data-style="active"]):before {
#indicators span[data-indicator="poll-status"]:not([data-style="active"]):before {
font-family: 'kucat' !important;
font-size: 1.5rem !important;
content: "\e932";
@@ -995,7 +1039,7 @@ span[data-indicator="poll-status"]:not([data-style="active"]):before {
text-decoration: none
}
.pdboy-dark:hover,.pdboy-light:hover,
span[data-indicator="uci-changes"]:hover,span[data-indicator="poll-status"]:hover,.pdboy-qlogout:hover,.showSide:hover {
span[data-indicator="uci-changes"]:hover,#indicators span[data-indicator="poll-status"]:hover,.pdboy-qlogout:hover,.showSide:hover {
background-color: var(--menu-hover-barbgcolor) !important;
color: var(--menu-hover-color);
border-radius: var(--radius1);
@@ -1003,7 +1047,7 @@ span[data-indicator="uci-changes"]:hover,span[data-indicator="poll-status"]:hove
}
.pdboy-dark,.pdboy-light,
span[data-indicator="uci-changes"],span[data-indicator="poll-status"],.pdboy-qlogout {
span[data-indicator="uci-changes"],#indicators span[data-indicator="poll-status"],.pdboy-qlogout {
line-height: 1;
padding: 1rem;
cursor: pointer !important;
@@ -1089,63 +1133,6 @@ span[data-indicator="uci-changes"],span[data-indicator="poll-status"],.pdboy-qlo
-moz-osx-font-smoothing: grayscale
}
.danger {
background-color: #d9534f !important;
color: #eee
}
.warning {
background-color: #b98413 !important;
margin: 0 0 0.5rem 0;
color: #eee
}
.success {
background-color: #1a8361 !important;
color: #eee;
width: 14rem !important
}
#log_textarea {
box-shadow: 0 1px 1px 0 rgba(0,0,0,0.16),0 0 1px 0 var(--input-boxcolor)
}
.error {
color: #f00
}
.alert,.alert-message {
padding: 1rem;
border: 0;
font-weight: normal;
font-style: normal;
line-height: 1.6em;
font-family: inherit;
min-width: inherit;
overflow: unset;
border-radius: var(--radius1);
background-color: rgba(var(--primary-rgbbody),var(--primary-rgbm-ts));
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 var(--input-boxcolor)
}
.alert-message>* {
margin: 0;
white-space: normal
}
.alert-message>h4 {
margin: 0.5rem;
color: red;
padding: 0.5rem 1rem;
font-weight: bold
}
.errorbox {
color: #f8f8f8;
background-color: #f0ad4e;
border-color: #eea236
}
.container .alert,.container .alert-message {
margin-top: 1rem
}
@@ -1420,7 +1407,7 @@ h2 {
h3 {
font-size: var(--font-d);
display: block;
margin: 0.5rem 0;
margin: 0.5rem 0 0 1rem;
color: var(--primary-title-color);
font-weight: bold;
letter-spacing: 0.1rem;
@@ -1433,7 +1420,7 @@ h4 {
padding: 0.75rem 1.25rem;
font-weight: 600;
font-size: var(--font-z);
color: var(--primary-title-color) !important;
color: var(--primary-title-color) ;
padding-bottom: 10px
}
@@ -2529,11 +2516,68 @@ select,input {
min-width: 270px;
max-width: 900px;
min-height: 32px;
border-radius: var(--radius2) !important;
background-color: rgba(var(--primary-rgbbody), 1)!important;
color: var(--primary-title-color)!important;
box-shadow: 0 2px 10px 0px rgba(255, 255, 255, .16), 0 0 10px 0 rgba(255, 255, 255, .12);
margin: 5em auto;
padding: 1rem;
border-radius: var(--radius2) !important;
background-color: rgba(var(--primary-rgbbody),1)!important;
box-shadow: 0 2px 10px 0px rgba(255,255,255,.16),0 0 10px 0 rgba(255,255,255,.12)
}
.danger {
background-color: #d9534f ;
color: #eee
}
#log_textarea {
box-shadow: 0 1px 1px 0 rgba(0,0,0,0.16),0 0 1px 0 var(--input-boxcolor)
}
.error {
color: #f00
}
.alert,.alert-message {
padding: 1rem;
border: 0;
font-weight: normal;
font-style: normal;
line-height: 1.6em;
font-family: inherit;
min-width: inherit;
overflow: unset;
border-radius: var(--radius1);
background-color: rgba(var(--primary-rgbbody),var(--primary-rgbm-ts));
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 var(--input-boxcolor)
}
.alert-message>* {
margin: 0;
white-space: normal
}
.alert-message>h4 {
margin: 0.5rem;
color: red;
padding: 0.5rem 1rem;
font-weight: bold
}
.warning {
background-color: #b98413 !important;
color: #eee!important;
}
.success {
background-color: #1a8361 !important;
color: #eee!important;
width: 14rem !important
}
.errorbox {
color: #f8f8f8!important;
background-color: #f0ad4e!important;
border-color: #eea236
}
#modal_overlay .cbi-section,.modal .cbi-section {
@@ -2599,10 +2643,9 @@ select,input {
}
.notice {
background-color: #b98413 !important;
background-color: rgba(var(--primary-rgbm),1) !important;
color: var(--primary-title-color);
background-color: rgba(var(--primary-rgbbody), 1);
padding: 2rem 1rem;
color: #eee
}
.modal>p {
font-size: var(--font-x);
@@ -2718,9 +2761,8 @@ body.modal-overlay-active #modal_overlay {
bottom: 0;
left: .2em;
width: 32px;
color: var(--body-color);
content: "";
color: var(--body-color);
background: url(../../resources/icons/loading.svg) no-repeat center,
url(../../resources/icons/loading.gif) no-repeat center;
background-size: 20px;
@@ -4028,6 +4070,7 @@ pre.command-output {
--bg-light: rgba(255, 255, 255, 0);
--bg-gray: rgba(var(--primary-rgbm), 0.02);
--text-title: var(--primary-title-color);
--text-secondary: var(--body-color);
--border-color: rgba(255, 255, 255, 0);
--border-light: rgba(255, 255, 255, 0);
--text-primary: var(--inputtext-color);
@@ -4189,12 +4232,11 @@ pre.command-output {
.bandix-card ,
.stats-card
{
background-color: rgba(var(--primary-rgbm), 0.1)!important;
border-radius: 0 !important;
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0) !important;
margin-bottom: 0 !important;
background-color: rgba(var(--primary-rgbm), 0.05)!important;
box-shadow: 0 1px 3px 0 var(--input-boxcolor) !important;
border: 0px solid #333!important;
border-bottom: 0px solid var(--input-boxcolor)!important;
margin-bottom: 0 !important;
overflow: auto!important;
}
@@ -4283,6 +4325,9 @@ border-bottom: 0px solid #f1f5f9!important;
[data-page="admin-system-package-manager"] .modal>textarea {
white-space: nowrap
}
[data-page="admin-status-overview"] #view>div {
padding: 0rem 0rem 1rem 0.5rem;
}
.main>.main-left,.cbi-section,[data-tab-title],[data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear),#maincontent>.container>form,#maincontent>.container>form>div,.tabs,.cbi-tabmenu,.cbi-tooltip,#view>p,#view>div,#view>table {
backdrop-filter: var(--ufilter);
@@ -4392,24 +4437,29 @@ div#add_link_div {
padding: 0.5rem
}
div#file-manager-container {
#file-manager-container {
margin-left: 0.5rem
}
div#content-filemanager>div#file-list-container {
margin-top: 10px !important
#content-filemanager>#file-list-container {
margin-top: 10px !important;
min-width: 800px !important;
max-width: 100% !important;
width: auto !important;
}
div#file-manager-container #file-table tr>th {
#file-manager-container #file-table tr>th {
background-color: rgba(var(--primary-rgbm),1);
color: var(--menu-color)
}
div#file-manager-container #status-bar {
#file-list-container table>tbody>tr>td span {
padding: 0.5rem;
}
#file-manager-container #status-bar {
background-color: rgba(var(--primary-rgbm),0.3)
}
div#file-manager-container #status-bar #status-info {
#file-manager-container #status-bar #status-info {
color: var(--title-color)
}
@@ -4417,6 +4467,9 @@ div#file-manager-container #status-bar #status-info {
background-color: rgba(var(--primary-rgbm),0.4) !important
}
#file-list-container table>tbody>tr>td {
padding: 0.2rem
}
.cbi-tabcontainer-content #editor-container {
width: 100%;
border: 1px solid var(--inputborder-color)
@@ -4441,9 +4494,6 @@ div#file-manager-container #status-bar #status-info {
--clr-header: var(--title-color)
}
#file-list-container table>tbody>tr>td {
padding: 0.2rem
}
.tr.cbi-section-table-row[id*="wolplus"],.tr.cbi-section-table-row[id*="firewall"] {
flex-wrap: wrap;
@@ -140,6 +140,7 @@ function link_add_node()
local chunk = http.formvalue("chunk")
local chunk_index = tonumber(http.formvalue("chunk_index"))
local total_chunks = tonumber(http.formvalue("total_chunks"))
local group = http.formvalue("group") or "default"
if chunk and chunk_index ~= nil and total_chunks ~= nil then
-- 按顺序拼接到文件
@@ -154,7 +155,7 @@ function link_add_node()
end
-- 如果是最后一片,才执行
if chunk_index + 1 == total_chunks then
luci.sys.call("lua /usr/share/passwall/subscribe.lua add log")
luci.sys.call("lua /usr/share/passwall/subscribe.lua add " .. group)
end
end
end
@@ -23,10 +23,12 @@ o.default = translate("Remarks")
o.rmempty = false
o = s:option(Value, "group", translate("Group Name"))
o.default = ""
o:value("", translate("default"))
local groups = {}
m.uci:foreach(appname, "nodes", function(s)
if s[".name"] ~= arg[1] then
if s.group then
if s.group and s.group ~= "" then
groups[s.group] = true
end
end
@@ -4,7 +4,7 @@ local api = require "luci.passwall.api"
<script type="text/javascript">
//<![CDATA[
function ajax_add_node(link) {
function ajax_add_node(link, group) {
const chunkSize = 1000; // 分片发送以突破uhttpd的限制,每块1000字符
const totalChunks = Math.ceil(link.length / chunkSize);
let currentChunk = 0;
@@ -31,6 +31,7 @@ local api = require "luci.passwall.api"
formData.append("chunk", chunk);
formData.append("chunk_index", currentChunk);
formData.append("total_chunks", totalChunks);
formData.append("group", group);
xhr.send(formData);
} else {
window.location.href = '<%=api.url("node_list")%>';
@@ -50,11 +51,12 @@ local api = require "luci.passwall.api"
function add_node() {
var nodes_link = document.getElementById("nodes_link").value;
var group = (document.querySelector('#addlink_group_custom input[type="hidden"]')?.value || "default");
nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").trim();
if (nodes_link != "") {
var s = nodes_link.split('://');
if (s.length > 1) {
ajax_add_node(nodes_link);
ajax_add_node(nodes_link, group);
}
else {
alert("<%:Please enter the correct link.%>");
@@ -83,6 +85,84 @@ local api = require "luci.passwall.api"
window.location.href = '<%=api.url("add_node")%>?redirect=1';
}
//自定义分组下拉列表事件
document.addEventListener("DOMContentLoaded", function() {
var dropdown = document.getElementById("addlink_group_custom");
if (!dropdown) return;
var display = dropdown.querySelector(".selected-display");
var displayText = display.querySelector(".text");
var list = dropdown.querySelector(".dropdown-list");
var hidden = dropdown.querySelector('input[type="hidden"]');
var input = dropdown.querySelector(".create-item-input");
display.addEventListener("click", function() {
list.style.display = list.style.display === "none" ? "block" : "none";
input.value = "";
input.focus();
});
function selectItem(li) {
list.querySelectorAll(".dropdown-item").forEach(function(el){
el.classList.remove("selected");
});
li.classList.add("selected");
hidden.value = li.dataset.value;
displayText.textContent = li.dataset.value || "<%:default%>";
list.style.display = "none";
}
list.addEventListener("click", function(e){
var li = e.target.closest(".dropdown-item");
if (!li || li.classList.contains("custom-input")) return;
selectItem(li);
});
input.addEventListener("keydown", function(e){
if (e.keyCode !== 13) return;
e.stopPropagation();
e.preventDefault();
var val = input.value.trim();
if (!val) return;
var li = Array.from(list.querySelectorAll(".dropdown-item")).find(function(el){
return el.dataset.value === val;
});
if (!li) {
li = document.createElement("li");
li.className = "dropdown-item";
li.dataset.value = val;
li.textContent = val;
list.insertBefore(li, input.parentNode);
}
input.value = "";
selectItem(li);
});
// 从tab中读取分组名称
var observer = new MutationObserver(function(mutations, obs){
var tabs = document.querySelectorAll(".cbi-tabmenu li");
if(!tabs.length) return;
tabs.forEach(function(li){
var group = li.id.split('.').pop();
if(group === "default") return;
if(Array.from(list.querySelectorAll(".dropdown-item")).some(el => el.dataset.value === group)) return;
var newLi = document.createElement("li");
newLi.className = "dropdown-item";
newLi.dataset.value = group;
newLi.textContent = group;
list.insertBefore(newLi, input.parentNode);
});
obs.disconnect();
});
observer.observe(document.body, {childList: true, subtree: true});
});
//]]>
</script>
@@ -93,6 +173,24 @@ local api = require "luci.passwall.api"
<textarea id="nodes_link" rows="10"></textarea>
<p id="nodes_link_text"><%:Enter share links, one per line. Subscription links are not supported!%></p>
</div>
<div class="cbi-value modal-center">
<label class="cbi-value-title"><%:Group Name%></label>
<div class="cbi-value-field">
<div id="addlink_group_custom" class="custom-dropdown">
<div class="selected-display">
<span class="text"><%:default%></span>
<span class="arrow"></span>
</div>
<ul class="dropdown-list" style="display:none;">
<li class="dropdown-item" data-value=""><%:default%></li>
<li class="dropdown-item custom-input">
<input type="text" placeholder="-- <%:custom%> --" class="create-item-input">
</li>
</ul>
<input type="hidden" name="addlink_group" value="">
</div>
</div>
</div>
<div id="add_link_button_container">
<input class="btn cbi-button cbi-button-add" type="button" onclick="add_node()" value="<%:Add%>" />
<input class="btn cbi-button cbi-button-remove" type="button" onclick="close_add_link_div()" value="<%:Close%>" />
@@ -107,7 +205,7 @@ local api = require "luci.passwall.api"
<input class="btn cbi-button cbi-button-add" type="button" onclick="open_add_link_div()" value="<%:Add the node via the link%>" />
<input class="btn cbi-button cbi-button-remove" type="button" onclick="clear_all_nodes()" value="<%:Clear all nodes%>" />
<input class="btn cbi-button cbi-button-remove" type="button" onclick="delete_select_nodes()" value="<%:Delete select nodes%>" />
<input class="btn cbi-button" type="button" onclick="checked_all_node(this)" value="<%:Select all%>" />
<input class="btn cbi-button" type="button" id="select_all_btn" onclick="checked_all_node(this)" value="<%:Select all%>" />
<input class="btn cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:Save & Apply%>" />
<input class="btn cbi-button cbi-button-save" type="submit" name="cbi.save" value="<%:Save%>" />
<input class="btn cbi-button cbi-button-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" />
@@ -147,12 +245,13 @@ local api = require "luci.passwall.api"
padding: 5px;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: -10px;
}
#nodes_link_text {
color: red;
font-size: 14px;
margin-top: 5px;
margin-top: 0;
text-align: center;
width: 100%;
}
@@ -164,4 +263,99 @@ local api = require "luci.passwall.api"
max-width: 300px;
margin-top: 10px;
}
#add_link_modal_container .modal-center {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 10px;
margin-bottom: 15px;
width: auto;
}
#add_link_modal_container .modal-center .cbi-value-title {
display: inline-block;
width: 80px;
text-align: right;
font-size: 13px;
line-height: 28px;
margin: 0;
white-space: nowrap;
flex-shrink: 0;
}
#add_link_modal_container .modal-center .cbi-value-field {
display: flex;
justify-content: flex-start;
width: 200px;
}
.custom-dropdown {
position: relative;
border: 1px solid #d9d9d9;
border-radius: 2px;
width: 200px;
font-size: 13px;
background: #fff;
cursor: pointer;
box-sizing: border-box;
height: 28px;
}
.selected-display {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 8px;
height: 100%;
}
.selected-display:hover {
background-color: #f7f7f7;
}
.selected-display .arrow {
font-size: 12px;
color: #666;
}
.dropdown-list {
position: absolute;
top: 100%;
left: 0;
width: 100%;
border: 1px solid #d9d9d9;
border-top: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.15);
background: #fff;
list-style: none;
margin: 0;
padding: 0;
max-height: 250px;
overflow-y: auto;
overflow-x: hidden;
z-index: 100;
box-sizing: border-box;
}
.dropdown-item {
padding: 4px 8px;
line-height: 20px;
}
.dropdown-item.selected {
background-color: #1e90ff;
color: #fff;
}
.dropdown-item.custom-input input {
width: 100%;
max-width: 200px;
box-sizing: border-box;
padding: 3px;
font-size: 13px;
line-height: 20px;
border: 1px solid #ccc;
}
</style>
@@ -60,6 +60,12 @@ table td, .table .td {
function cbi_t_switch(section, tab) {
if( cbi_t[section] && cbi_t[section][tab] ) {
//在切换选项卡之前,先取消当前激活选项卡的全选状态
var btn = document.getElementById("select_all_btn");
if (btn) {
dechecked_all_node(btn);
}
var o = cbi_t[section][tab];
var h = document.getElementById('tab.' + section);
for( var tid in cbi_t[section] ) {
@@ -176,7 +182,9 @@ table td, .table .td {
}
function checked_all_node(btn) {
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
if (!visibleContainer) return;
var doms = visibleContainer.getElementsByClassName("nodes_select");
if (doms && doms.length > 0) {
for (var i = 0 ; i < doms.length; i++) {
doms[i].checked = true;
@@ -187,7 +195,9 @@ table td, .table .td {
}
function dechecked_all_node(btn) {
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
if (!visibleContainer) return;
var doms = visibleContainer.getElementsByClassName("nodes_select");
if (doms && doms.length > 0) {
for (var i = 0 ; i < doms.length; i++) {
doms[i].checked = false;
@@ -199,7 +209,9 @@ table td, .table .td {
function delete_select_nodes() {
var ids = [];
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
if (!visibleContainer) return;
var doms = visibleContainer.getElementsByClassName("nodes_select");
if (doms && doms.length > 0) {
for (var i = 0 ; i < doms.length; i++) {
if (doms[i].checked) {
@@ -555,8 +567,8 @@ table td, .table .td {
var group_nodes = {}
for (let i = 0; i < node_list.length; i++) {
let _node = node_list[i]
if (!_node.group) {
_node.group = "<%:default%>"
if (!_node.group || _node.group === "") {
_node.group = "default"
}
if (!group_nodes[_node.group]) {
group_nodes[_node.group] = []
@@ -618,10 +630,15 @@ table td, .table .td {
_html = _html.split("{{node-tr}}").join(node_tr_html);
table_html = _html;
}
var group_name = group
if (group === "default") {
group_name = "<%:default%>"
}
tab_ul_li_html +=
'<li id="tab.passwall.nodes.' + group + '" class="cbi-tab">' +
'<a onclick="this.blur(); return cbi_t_switch(\'passwall.nodes\', \'' + group + '\')" href="<%=REQUEST_URI%>?tab.passwall.nodes=' + group + '">' + group + " | " + "<font style='color: red'>" + group_nodes[group].length + '</font></a>' +
'<a onclick="this.blur(); return cbi_t_switch(\'passwall.nodes\', \'' + group + '\')" href="<%=REQUEST_URI%>?tab.passwall.nodes=' + group + '">' + group_name + " | " + "<font style='color: red'>" + group_nodes[group].length + '</font></a>' +
'</li>'
tab_content_html +=
'<div class="cbi-tabcontainer" id="container.passwall.nodes.' + group + '" style="display: none;">' +
@@ -990,6 +990,7 @@ add_firewall_rule() {
$ipt_m -N PSW
$ipt_m -A PSW $(dst $IPSET_LAN) -j RETURN
$ipt_m -A PSW $(dst $IPSET_VPS) -j RETURN
$ipt_m -A PSW -m conntrack --ctdir REPLY -j RETURN
[ ! -z "${WAN_IP}" ] && {
$ipt_m -A PSW $(comment "WAN_IP_RETURN") -d "${WAN_IP}" -j RETURN
@@ -1734,7 +1734,9 @@ local function update_node(manual)
if type(vvv) == "table" and next(vvv) ~= nil then
uci:set_list(appname, cfgid, kkk, vvv)
else
uci:set(appname, cfgid, kkk, vvv)
if kkk ~= "group" or vvv ~= "default" then
uci:set(appname, cfgid, kkk, vvv)
end
-- sing-box 域名解析策略
if kkk == "type" and vvv == "sing-box" then
uci:set(appname, cfgid, "domain_strategy", domain_strategy_node)
@@ -2031,7 +2033,7 @@ if arg[1] then
local f = assert(io.open("/tmp/links.conf", 'r'))
local raw = f:read('*all')
f:close()
parse_link(raw, "1", "导入")
parse_link(raw, "1", arg[2])
update_node(1)
luci.sys.call("rm -f /tmp/links.conf")
elseif arg[1] == "truncate" then
@@ -23,10 +23,12 @@ o.default = translate("Remarks")
o.rmempty = false
o = s:option(Value, "group", translate("Group Name"))
o.default = ""
o:value("", translate("default"))
local groups = {}
m.uci:foreach(appname, "nodes", function(s)
if s[".name"] ~= arg[1] then
if s.group then
if s.group and s.group ~= "" then
groups[s.group] = true
end
end
@@ -107,7 +107,7 @@ local api = require "luci.passwall.api"
<input class="btn cbi-button cbi-button-add" type="button" onclick="open_add_link_div()" value="<%:Add the node via the link%>" />
<input class="btn cbi-button cbi-button-remove" type="button" onclick="clear_all_nodes()" value="<%:Clear all nodes%>" />
<input class="btn cbi-button cbi-button-remove" type="button" onclick="delete_select_nodes()" value="<%:Delete select nodes%>" />
<input class="btn cbi-button" type="button" onclick="checked_all_node(this)" value="<%:Select all%>" />
<input class="btn cbi-button" type="button" id="select_all_btn" onclick="checked_all_node(this)" value="<%:Select all%>" />
<input class="btn cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:Save & Apply%>" />
<input class="btn cbi-button cbi-button-save" type="submit" name="cbi.save" value="<%:Save%>" />
<input class="btn cbi-button cbi-button-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" />
@@ -60,6 +60,12 @@ table td, .table .td {
function cbi_t_switch(section, tab) {
if( cbi_t[section] && cbi_t[section][tab] ) {
//在切换选项卡之前,先取消当前激活选项卡的全选状态
var btn = document.getElementById("select_all_btn");
if (btn) {
dechecked_all_node(btn);
}
var o = cbi_t[section][tab];
var h = document.getElementById('tab.' + section);
for( var tid in cbi_t[section] ) {
@@ -176,7 +182,9 @@ table td, .table .td {
}
function checked_all_node(btn) {
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
if (!visibleContainer) return;
var doms = visibleContainer.getElementsByClassName("nodes_select");
if (doms && doms.length > 0) {
for (var i = 0 ; i < doms.length; i++) {
doms[i].checked = true;
@@ -187,7 +195,9 @@ table td, .table .td {
}
function dechecked_all_node(btn) {
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
if (!visibleContainer) return;
var doms = visibleContainer.getElementsByClassName("nodes_select");
if (doms && doms.length > 0) {
for (var i = 0 ; i < doms.length; i++) {
doms[i].checked = false;
@@ -199,7 +209,9 @@ table td, .table .td {
function delete_select_nodes() {
var ids = [];
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
if (!visibleContainer) return;
var doms = visibleContainer.getElementsByClassName("nodes_select");
if (doms && doms.length > 0) {
for (var i = 0 ; i < doms.length; i++) {
if (doms[i].checked) {
@@ -555,7 +567,7 @@ table td, .table .td {
var group_nodes = {}
for (let i = 0; i < node_list.length; i++) {
let _node = node_list[i]
if (!_node.group) {
if (!_node.group || _node.group === "") {
_node.group = "<%:default%>"
}
if (!group_nodes[_node.group]) {
@@ -990,6 +990,7 @@ add_firewall_rule() {
$ipt_m -N PSW
$ipt_m -A PSW $(dst $IPSET_LAN) -j RETURN
$ipt_m -A PSW $(dst $IPSET_VPS) -j RETURN
$ipt_m -A PSW -m conntrack --ctdir REPLY -j RETURN
[ ! -z "${WAN_IP}" ] && {
$ipt_m -A PSW $(comment "WAN_IP_RETURN") -d "${WAN_IP}" -j RETURN
@@ -1052,8 +1053,8 @@ add_firewall_rule() {
$ip6t_m -N PSW_RULE
$ip6t_m -A PSW_RULE -j CONNMARK --restore-mark
$ip6t_m -A PSW_RULE -m mark --mark 1 -j RETURN
$ip6t_m -A PSW2_RULE -p tcp -m tcp --syn -j MARK --set-xmark 1
$ip6t_m -A PSW2_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark 1
$ip6t_m -A PSW_RULE -p tcp -m tcp --syn -j MARK --set-xmark 1
$ip6t_m -A PSW_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark 1
$ip6t_m -A PSW_RULE -j CONNMARK --save-mark
$ip6t_m -N PSW
+2 -2
View File
@@ -21,13 +21,13 @@ define Download/geoip
HASH:=2445b44d9ae3ab9a867c9d1e0e244646c4c378622e14b9afaf3658ecf46a40b9
endef
GEOSITE_VER:=20251101070148
GEOSITE_VER:=20251106100932
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
define Download/geosite
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
URL_FILE:=dlc.dat
FILE:=$(GEOSITE_FILE)
HASH:=434469c8a61ec36d2f3e1ddd6ff65c594bf76ebcb4e472705695b6d4ab51ba47
HASH:=1f18e36e19f6c08fd44de1744b8390a816b198dbab4fcf7d6815a934f415dceb
endef
GEOSITE_IRAN_VER:=202511030041
+3 -3
View File
@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=v2rayA
PKG_VERSION:=2.2.7.3
PKG_VERSION:=2.2.7.4
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/v2rayA/v2rayA/tar.gz/v$(PKG_VERSION)?
PKG_HASH:=4b36275dff287d8cf03ee8fa5331d731593f35020459a8ea0ff925e8496a52cf
PKG_HASH:=801a5488493cef8c2603d596e5982d226c07ad8f4a2969d942922be79169ec29
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)/service
PKG_LICENSE:=AGPL-3.0-only
@@ -60,7 +60,7 @@ define Download/v2raya-web
URL:=https://github.com/v2rayA/v2rayA/releases/download/v$(PKG_VERSION)/
URL_FILE:=web.tar.gz
FILE:=$(WEB_FILE)
HASH:=99e789fa7cbfe9f6bc49afa8365556dff6d6c664e6136b045dd7f43322d0de7f
HASH:=985b083a75b7b34ea9c5151cbc096f6f44fa369a807fea85b435fed5229dae65
endef
define Build/Prepare
+6 -4
View File
@@ -4,6 +4,7 @@ on:
inputs:
tag:
type: string
description: 'The tag to release'
required: true
jobs:
Build_v2rayA_Web:
@@ -595,15 +596,16 @@ jobs:
- name: Download v2rayA binary for checksum
run: |
mkdir v2raya_linux
for arch in x86 x64 longarch64 armv7 arm64; do
for arch in x86 x64 loongarch64 armv7 arm64; do
curl -L https://github.com/v2rayA/v2rayA/releases/download/v${VERSION}/v2raya_linux_${arch}_${VERSION} -o v2raya_linux/v2raya_linux_${arch}_${VERSION}
chmod +x v2raya_linux/v2raya_linux_${arch}_${VERSION}
done
- name: Set Path
- name: List Files and Install expect
run: |
sudo apt update -y && sudo apt install -y expect >/dev/null
ls -l v2raya_linux
echo "P_DIR=$(pwd)/v2raya_linux" >> $GITHUB_ENV
echo "P_DIR=$(pwd)/v2raya_linux" >> $GITHUB_OUTPUT
echo "P_DIR=$(pwd)" >> $GITHUB_ENV
echo "P_DIR=$(pwd)" >> $GITHUB_OUTPUT
id: set_path
- name: Release to AUR
env:
+39 -107
View File
@@ -3,66 +3,37 @@
<b-navbar ref="navs" fixed-top shadow type="is-light">
<template slot="brand">
<b-navbar-item href="/">
<img
src="@/assets/img/logo2.png"
alt="v2rayA"
class="logo no-select"
/>
<img src="@/assets/img/logo2.png" alt="v2rayA" class="logo no-select" />
</b-navbar-item>
<b-navbar-item tag="div">
<b-tag
id="statusTag"
class="pointerTag"
:type="statusMap[runningState.running]"
@mouseenter.native="handleOnStatusMouseEnter"
@mouseleave.native="handleOnStatusMouseLeave"
@click.native="handleClickStatus"
>{{ coverStatusText ? coverStatusText : runningState.running }}
<b-tag id="statusTag" class="pointerTag" :type="statusMap[runningState.running]"
@mouseenter.native="handleOnStatusMouseEnter" @mouseleave.native="handleOnStatusMouseLeave"
@click.native="handleClickStatus">{{ coverStatusText ? coverStatusText : runningState.running }}
</b-tag>
</b-navbar-item>
<b-navbar-item tag="div">
<b-dropdown
v-if="updateOutboundDropdown"
:triggers="isMobile ? ['click'] : ['click', 'hover']"
aria-role="list"
:close-on-click="false"
@mouseenter.native="handleOutboundDropdownActiveChange"
@active-change="handleOutboundDropdownActiveChange"
>
<b-dropdown v-if="updateOutboundDropdown" :triggers="isMobile ? ['click'] : ['click', 'hover']"
aria-role="list" :close-on-click="false" @mouseenter.native="handleOutboundDropdownActiveChange"
@active-change="handleOutboundDropdownActiveChange">
<template #trigger>
<b-tag class="pointerTag" type="is-info" icon-right="menu-down"
>{{ outboundName.toUpperCase() }}
<b-tag class="pointerTag" type="is-info" icon-right="menu-down">{{ outboundName.toUpperCase() }}
</b-tag>
</template>
<b-dropdown-item
v-for="outbound in outbounds"
:key="outbound"
aria-role="listitem"
<b-dropdown-item v-for="outbound in outbounds" :key="outbound" aria-role="listitem"
class="is-flex padding-right-1rem justify-content-space-between outbound-dropdown"
@mouseenter.native="handleOnOutboundMouseEnter(outbound)"
@mouseleave.native="handleOnOutboundMouseLeave"
@click="outboundName = outbound"
><p class="is-relative is-fullwidth">
@mouseenter.native="handleOnOutboundMouseEnter(outbound)" @mouseleave.native="handleOnOutboundMouseLeave"
@click="outboundName = outbound">
<p class="is-relative is-fullwidth">
<span>{{ outboundNameDecorator(outbound) }}</span>
<span>
<i
v-show="isMobile || outboundDropdownHover[outbound]"
class="iconfont icon-setting outbound-setting"
@click="handleClickOutboundSetting($event, outbound)"
></i
></span></p
></b-dropdown-item>
<b-dropdown-item
aria-role="listitem"
class="is-flex padding-right-1rem"
separator
></b-dropdown-item>
<b-dropdown-item
aria-role="listitem"
class="is-flex padding-right-1rem"
@click="handleAddOutbound"
>{{ $t("operations.addOutbound") }}
<i v-show="isMobile || outboundDropdownHover[outbound]" class="iconfont icon-setting outbound-setting"
@click="handleClickOutboundSetting($event, outbound)"></i></span>
</p>
</b-dropdown-item>
<b-dropdown-item aria-role="listitem" class="is-flex padding-right-1rem" separator></b-dropdown-item>
<b-dropdown-item aria-role="listitem" class="is-flex padding-right-1rem" @click="handleAddOutbound">{{
$t("operations.addOutbound") }}
</b-dropdown-item>
</b-dropdown>
</b-navbar-item>
@@ -86,74 +57,34 @@
<i class="iconfont icon-info" style="font-size: 1.25em"></i>
{{ $t("common.log") }}
</b-navbar-item>
<b-dropdown
position="is-bottom-left"
aria-role="menu"
style="margin-right: 10px"
class="menudropdown"
>
<b-dropdown position="is-bottom-left" aria-role="menu" style="margin-right: 10px" class="menudropdown">
<a slot="trigger" class="navbar-item" role="button">
<span class="no-select">{{ username }}</span>
<i
class="iconfont icon-caret-down"
style="position: relative; top: 1px; left: 2px"
></i>
<i class="iconfont icon-caret-down" style="position: relative; top: 1px; left: 2px"></i>
</a>
<b-dropdown-item
custom
aria-role="menuitem"
v-html="$t('common.loggedAs', { username })"
>
<b-dropdown-item custom aria-role="menuitem" v-html="$t('common.loggedAs', { username })">
</b-dropdown-item>
<b-dropdown-item
custom
aria-role="menuitem"
class="is-flex"
style="
<b-dropdown-item custom aria-role="menuitem" class="is-flex" style="
box-sizing: content-box;
height: 16px;
width: 60px;
justify-content: space-between;
"
>
<img
v-for="lang of langs"
:key="lang.flag"
:src="require(`@/assets/img/flags/flag_${lang.flag}.svg`)"
:alt="lang.alt"
style="height: 100%; flex-shrink: 0; cursor: pointer"
@click="handleClickLang(lang.flag)"
/>
">
<img v-for="lang of langs" :key="lang.flag" :src="require(`@/assets/img/flags/flag_${lang.flag}.svg`)"
:alt="lang.alt" style="height: 100%; flex-shrink: 0; cursor: pointer"
@click="handleClickLang(lang.flag)" />
</b-dropdown-item>
<hr class="dropdown-divider" />
<b-dropdown-item
value="logout"
aria-role="menuitem"
class="no-select"
@click="handleClickLogout"
>
<i
class="iconfont icon-logout"
style="position: relative; top: 1px"
></i>
<b-dropdown-item value="logout" aria-role="menuitem" class="no-select" @click="handleClickLogout">
<i class="iconfont icon-logout" style="position: relative; top: 1px"></i>
{{ $t("operations.logout") }}
</b-dropdown-item>
</b-dropdown>
</template>
</b-navbar>
<node
v-model="runningState"
:outbound="outboundName"
:observatory="observatory"
/>
<b-modal
:active.sync="showCustomPorts"
has-modal-card
trap-focus
aria-role="dialog"
aria-modal
class="modal-custom-ports"
>
<node v-model="runningState" :outbound="outboundName" :observatory="observatory" />
<b-modal :active.sync="showCustomPorts" has-modal-card trap-focus aria-role="dialog" aria-modal
class="modal-custom-ports">
<ModalCustomAddress @close="showCustomPorts = false" />
</b-modal>
<div id="login"></div>
@@ -297,9 +228,8 @@ export default {
if (u.protocol === "https") {
protocol = "wss";
}
url = `${protocol}://${u.host}:${
u.port
}/api/message?Authorization=${encodeURIComponent(localStorage["token"])}`;
url = `${protocol}://${u.host}:${u.port
}/api/message?Authorization=${encodeURIComponent(localStorage["token"])}`;
if (this.ws) {
// console.log("ws close");
this.ws.close();
@@ -343,9 +273,8 @@ export default {
if (
typeof this.runningState.outboundToServerName[outbound] === "number"
) {
return `${outbound} - ${this.$t("common.loadBalance")} (${
this.runningState.outboundToServerName[outbound]
})`;
return `${outbound} - ${this.$t("common.loadBalance")} (${this.runningState.outboundToServerName[outbound]
})`;
} else {
return `${outbound} - ${this.runningState.outboundToServerName[outbound]}`;
}
@@ -519,6 +448,7 @@ export default {
handleClickStatus() {
if (this.runningState.running === this.$t("common.notRunning")) {
let cancel;
let loading = this.$buefy.loading.open();
waitingConnected(
this.$axios({
url: apiRoot + "/v2ray",
@@ -541,6 +471,8 @@ export default {
queue: false,
});
}
}).finally(() => {
loading.close();
}),
3 * 1000,
cancel
+95 -199
View File
@@ -4,52 +4,26 @@
<p class="modal-card-title">{{ $t("common.setting") }}</p>
</header>
<section class="modal-card-body rules">
<b-field
label="GFWList"
horizontal
custom-class="modal-setting-label"
style="position: relative"
><span>{{ $t("common.latest") }}:</span>
<a
href="https://github.com/v2rayA/dist-v2ray-rules-dat/releases"
target="_blank"
class="is-link"
>{{ remoteGFWListVersion }}</a
><span>{{ $t("common.local") }}:</span>
<b-tooltip
v-if="dayjs(localGFWListVersion).isAfter(dayjs(remoteGFWListVersion))"
:label="$t('setting.messages.gfwlist')"
position="is-bottom"
type="is-danger"
dashed
multilined
animated
>
<b-field label="GFWList" horizontal custom-class="modal-setting-label" style="position: relative"><span>{{
$t("common.latest") }}:</span>
<a href="https://github.com/v2rayA/dist-v2ray-rules-dat/releases" target="_blank" class="is-link">{{
remoteGFWListVersion }}</a><span>{{ $t("common.local") }}:</span>
<b-tooltip v-if="dayjs(localGFWListVersion).isAfter(dayjs(remoteGFWListVersion))"
:label="$t('setting.messages.gfwlist')" position="is-bottom" type="is-danger" dashed multilined animated>
{{ localGFWListVersion ? localGFWListVersion : $t("common.none") }}
</b-tooltip>
<span v-else>{{ localGFWListVersion ? localGFWListVersion : $t("common.none") }}</span>
<b-button
size="is-small"
style="position: relative; top: -2px; text-decoration: none; font-weight: bold"
@click="handleClickUpdateGFWList"
>{{ $t("operations.update") }}
<b-button size="is-small" style="position: relative; top: -2px; text-decoration: none; font-weight: bold"
@click="handleClickUpdateGFWList">{{ $t("operations.update") }}
</b-button>
</b-field>
<hr class="dropdown-divider" style="margin: 1.25rem 0 1.25rem" />
<b-field label-position="on-border" class="with-icon-alert">
<template slot="label">
{{ $t("setting.transparentProxy") }}
<b-tooltip
type="is-dark"
:label="$t('setting.messages.transparentProxy')"
multilined
position="is-right"
>
<b-icon
size="is-small"
icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal"
/>
<b-tooltip type="is-dark" :label="$t('setting.messages.transparentProxy')" multilined position="is-right">
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
</b-tooltip>
</template>
<b-select v-model="transparent" expanded>
@@ -69,59 +43,48 @@
{{ $t("setting.options.sameAsPacMode") }}
</option>
</b-select>
<b-checkbox-button
v-show="!lite"
v-model="ipforward"
:native-value="true"
style="position: relative; left: -1px"
>{{ $t("setting.ipForwardOn") }}
<b-checkbox-button v-show="!lite" v-model="ipforward" :native-value="true"
style="position: relative; left: -1px">{{
$t("setting.ipForwardOn") }}
</b-checkbox-button>
<b-checkbox-button
v-model="portSharing"
:native-value="true"
style="position: relative; left: -1px"
>{{ $t("setting.portSharingOn") }}
<b-checkbox-button v-model="portSharing" :native-value="true" style="position: relative; left: -1px">{{
$t("setting.portSharingOn") }}
</b-checkbox-button>
</b-field>
<b-field v-show="transparent !== 'close'" label-position="on-border">
<template slot="label">
{{ $t("setting.transparentType") }}
<b-tooltip
type="is-dark"
multilined
:label="$t('setting.messages.transparentType')"
position="is-right"
>
<b-icon
size="is-small"
icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal"
/>
<b-tooltip type="is-dark" multilined :label="$t('setting.messages.transparentType')" position="is-right">
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
</b-tooltip>
</template>
<b-select v-model="transparentType" expanded class="left-border">
<b-select v-model="transparentType" expanded>
<option v-show="!lite" value="redirect">redirect</option>
<option v-show="!lite" value="tproxy">tproxy</option>
<option v-show="!lite" value="gvisor_tun">gvisor tun</option>
<option v-show="!lite" value="system_tun">system tun</option>
<option value="system_proxy">system proxy</option>
</b-select>
<template v-if="transparentType == 'tproxy'">
<b-button style="
margin-left: 0;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
color: rgba(0, 0, 0, 0.75);
" outlined @click="handleClickTproxyWhiteIpGroups">{{ $t("operations.tproxyWhiteIpGroups") }}
</b-button>
</template>
</b-field>
<b-field label-position="on-border">
<template slot="label">
{{ $t("setting.pacMode") }}
<b-tooltip
type="is-dark"
:label="$t('setting.messages.pacMode')"
multilined
position="is-right"
>
<b-icon
size="is-small"
icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal"
/>
<b-tooltip type="is-dark" :label="$t('setting.messages.pacMode')" multilined position="is-right">
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
</b-tooltip>
</template>
<b-select v-model="pacMode" expanded style="flex-shrink: 0">
@@ -135,30 +98,21 @@
<option value="routingA">RoutingA</option>
</b-select>
<template v-if="pacMode === 'custom'">
<b-button
type="is-primary"
style="
<b-button type="is-primary" style="
margin-left: 0;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
color: rgba(0, 0, 0, 0.75);
"
outlined
@click="handleClickConfigurePac"
>{{ $t("operations.configure") }}
" outlined @click="handleClickConfigurePac">{{ $t("operations.configure") }}
</b-button>
</template>
<template v-if="pacMode === 'routingA'">
<b-button
style="
<b-button style="
margin-left: 0;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
color: rgba(0, 0, 0, 0.75);
"
outlined
@click="handleClickConfigureRoutingA"
>{{ $t("operations.configure") }}
" outlined @click="handleClickConfigureRoutingA">{{ $t("operations.configure") }}
</b-button>
</template>
<p></p>
@@ -166,17 +120,9 @@
<b-field label-position="on-border">
<template slot="label">
{{ $t("setting.preventDnsSpoofing") }}
<b-tooltip
type="is-dark"
:label="$t('setting.messages.preventDnsSpoofing')"
multilined
position="is-right"
>
<b-icon
size="is-small"
icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal"
/>
<b-tooltip type="is-dark" :label="$t('setting.messages.preventDnsSpoofing')" multilined position="is-right">
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
</b-tooltip>
</template>
<b-select v-model="antipollution" expanded class="left-border">
@@ -190,14 +136,10 @@
<option value="doh">{{ $t("setting.options.doh") }}</option>
<option value="advanced">{{ $t("setting.options.advanced") }}</option>
</b-select>
<b-button
v-if="antipollution === 'advanced'"
:class="{
'right-extra-button': antipollution === 'closed',
'no-border-radius': antipollution !== 'closed',
}"
@click="handleClickDnsSetting"
>
<b-button v-if="antipollution === 'advanced'" :class="{
'right-extra-button': antipollution === 'closed',
'no-border-radius': antipollution !== 'closed',
}" @click="handleClickDnsSetting">
{{ $t("operations.configure") }}
</b-button>
<p></p>
@@ -205,17 +147,9 @@
<b-field v-show="showSpecialMode" label-position="on-border">
<template slot="label">
{{ $t("setting.specialMode") }}
<b-tooltip
type="is-dark"
multilined
:label="$t('setting.messages.specialMode')"
position="is-right"
>
<b-icon
size="is-small"
icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal"
/>
<b-tooltip type="is-dark" multilined :label="$t('setting.messages.specialMode')" position="is-right">
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
</b-tooltip>
</template>
<b-select v-model="specialMode" expanded class="left-border">
@@ -227,17 +161,9 @@
<b-field label-position="on-border">
<template slot="label">
TCPFastOpen
<b-tooltip
type="is-dark"
:label="$t('setting.messages.tcpFastOpen')"
multilined
position="is-right"
>
<b-icon
size="is-small"
icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal"
/>
<b-tooltip type="is-dark" :label="$t('setting.messages.tcpFastOpen')" multilined position="is-right">
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
</b-tooltip>
</template>
<b-select v-model="tcpFastOpen" expanded>
@@ -246,20 +172,13 @@
<option value="no">{{ $t("setting.options.off") }}</option>
</b-select>
</b-field>
<b-field label-position="on-border">
<template slot="label">
{{ $t("setting.inboundSniffing") }}
<b-tooltip
type="is-dark"
:label="$t('setting.messages.inboundSniffing')"
multilined
position="is-right"
>
<b-icon
size="is-small"
icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal"
/>
<b-tooltip type="is-dark" :label="$t('setting.messages.inboundSniffing')" multilined position="is-right">
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
</b-tooltip>
</template>
<b-select v-model="inboundSniffing" expanded>
@@ -268,58 +187,36 @@
<option value="http,tls,quic">Http + TLS + Quic</option>
</b-select>
<template v-if="inboundSniffing != 'disable'">
<b-button
type="is-primary"
style="
<b-button style="
margin-left: 0;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
border-radius: 0px;
color: rgba(0, 0, 0, 0.75);
"
outlined
@click="handleClickDomainsExcluded"
>{{ $t("operations.domainsExcluded") }}
" outlined @click="handleClickDomainsExcluded">{{ $t("operations.domainsExcluded") }}
</b-button>
<b-checkbox-button v-model="routeOnly" :native-value="true" style="position: relative; left: -1px;">
RouteOnly
</b-checkbox-button>
</template>
</b-field>
<b-field label-position="on-border" class="with-icon-alert">
<template slot="label">
{{ $t("setting.mux") }}
<b-tooltip
type="is-dark"
:label="$t('setting.messages.mux')"
multilined
position="is-right"
>
<b-icon
size="is-small"
icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal"
/>
<b-tooltip type="is-dark" :label="$t('setting.messages.mux')" multilined position="is-right">
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
</b-tooltip>
</template>
<b-select v-model="muxOn" expanded style="flex: 1">
<option value="no">{{ $t("setting.options.off") }}</option>
<option value="yes">{{ $t("setting.options.on") }}</option>
</b-select>
<cus-b-input
v-if="muxOn === 'yes'"
ref="muxinput"
v-model="mux"
:placeholder="$t('setting.concurrency')"
custom-class="no-shadow"
type="number"
min="1"
max="1024"
validation-icon=" iconfont icon-alert"
style="flex: 1"
/>
<cus-b-input v-if="muxOn === 'yes'" ref="muxinput" v-model="mux" :placeholder="$t('setting.concurrency')"
custom-class="no-shadow" type="number" min="1" max="1024" validation-icon=" iconfont icon-alert"
style="flex: 1" />
</b-field>
<b-field
v-show="pacMode === 'gfwlist' || transparent === 'gfwlist'"
:label="$t('setting.autoUpdateGfwlist')"
label-position="on-border"
>
<b-field v-show="pacMode === 'gfwlist' || transparent === 'gfwlist'" :label="$t('setting.autoUpdateGfwlist')"
label-position="on-border">
<b-select v-model="pacAutoUpdateMode" expanded>
<option value="none">{{ $t("setting.options.off") }}</option>
<option value="auto_update">
@@ -329,16 +226,9 @@
{{ $t("setting.options.updateGfwlistAtIntervals") }}
</option>
</b-select>
<cus-b-input
v-if="pacAutoUpdateMode === 'auto_update_at_intervals'"
ref="autoUpdatePacInput"
v-model="pacAutoUpdateIntervalHour"
custom-class="no-shadow"
type="number"
min="1"
validation-icon=" iconfont icon-alert"
style="flex: 1"
/>
<cus-b-input v-if="pacAutoUpdateMode === 'auto_update_at_intervals'" ref="autoUpdatePacInput"
v-model="pacAutoUpdateIntervalHour" custom-class="no-shadow" type="number" min="1"
validation-icon=" iconfont icon-alert" style="flex: 1" />
</b-field>
<b-field :label="$t('setting.autoUpdateSub')" label-position="on-border">
<b-select v-model="subscriptionAutoUpdateMode" expanded>
@@ -350,16 +240,9 @@
{{ $t("setting.options.updateSubAtIntervals") }}
</option>
</b-select>
<cus-b-input
v-if="subscriptionAutoUpdateMode === 'auto_update_at_intervals'"
ref="autoUpdateSubInput"
v-model="subscriptionAutoUpdateIntervalHour"
custom-class="no-shadow"
type="number"
min="1"
validation-icon=" iconfont icon-alert"
style="flex: 1"
/>
<cus-b-input v-if="subscriptionAutoUpdateMode === 'auto_update_at_intervals'" ref="autoUpdateSubInput"
v-model="subscriptionAutoUpdateIntervalHour" custom-class="no-shadow" type="number" min="1"
validation-icon=" iconfont icon-alert" style="flex: 1" />
</b-field>
<b-field :label="$t('setting.preferModeWhenUpdate')" label-position="on-border">
<b-select v-model="proxyModeWhenSubscribe" expanded>
@@ -376,11 +259,7 @@
</b-field>
</section>
<footer class="modal-card-foot flex-end">
<button
class="button footer-absolute-left"
type="button"
@click="$emit('clickPorts')"
>
<button class="button footer-absolute-left" type="button" @click="$emit('clickPorts')">
{{ $t("customAddressPort.title") }}
</button>
<button class="button" type="button" @click="$parent.close()">
@@ -399,6 +278,7 @@ import dayjs from "dayjs";
import ModalCustomRouting from "@/components/modalCustomRouting";
import ModalCustomRoutingA from "@/components/modalCustomRoutingA";
import modalDomainsExcluded from "@/components/modalDomainsExcluded";
import modalTproxyWhiteIpGroups from "@/components/modalTproxyWhiteIpGroups";
import modalUpdateGfwList from "@/components/modalUpdateGfwList";
import CusBInput from "./input/Input.vue";
import { parseURL, toInt } from "@/assets/js/utils";
@@ -418,12 +298,13 @@ export default {
muxOn: "no",
mux: "8",
transparent: "close",
transparentType: "redirect",
transparentType: "tproxy",
ipforward: false,
portSharing: false,
dnsForceMode: false,
dnsforward: "no",
antipollution: "none",
routeOnly: false,
specialMode: "none",
pacAutoUpdateMode: "none",
pacAutoUpdateIntervalHour: 0,
@@ -493,6 +374,7 @@ export default {
});
},
requestUpdateSetting() {
let loading = this.$buefy.loading.open();
let cancel;
waitingConnected(
this.$axios({
@@ -515,6 +397,7 @@ export default {
transparentType: this.transparentType,
ipforward: this.ipforward,
portSharing: this.portSharing,
routeOnly: this.routeOnly,
dnsforward: this.antipollution === "dnsforward" ? "yes" : "no", //
antipollution: this.antipollution,
specialMode: this.specialMode,
@@ -539,6 +422,7 @@ export default {
// FIXME: tricky
this.$parent.$parent.runningState.running = this.$t("common.notRunning");
}
loading.close();
}),
3 * 1000,
cancel
@@ -592,6 +476,14 @@ export default {
canCancel: true,
});
},
handleClickTproxyWhiteIpGroups() {
this.$buefy.modal.open({
parent: this,
component: modalTproxyWhiteIpGroups,
hasModalCard: true,
canCancel: true,
});
},
handleClickDomainsExcluded() {
this.$buefy.modal.open({
parent: this,
@@ -673,15 +565,19 @@ export default {
position: absolute;
left: 20px;
}
.left-border select {
border-radius: 4px 0 0 4px !important;
}
.right-extra-button {
border-radius: 0 4px 4px 0;
}
.no-border-radius {
border-radius: 0;
}
.modal-setting {
.b-checkbox.checkbox {
margin-right: 0;
@@ -0,0 +1,98 @@
<template>
<div class="modal-card" style="max-width: 450px; margin: auto">
<header class="modal-card-head">
<p class="modal-card-title">
{{ $t("tproxyWhiteIpGroups.title") }}
</p>
</header>
<section class="modal-card-body">
<b-message type="is-info" class="after-line-dot5">
<p>{{ $t("tproxyWhiteIpGroups.messages.0") }}</p>
</b-message>
<b-field :label="$t('tproxyWhiteIpGroups.formName1')">
<b-select multiple v-model="countryCodes" expanded>
<option value="CN">{{ $t("tproxyWhiteIpGroups.cn") }}</option>
<option value="PRIVATE">{{ $t("tproxyWhiteIpGroups.private") }}</option>
<option value="US">{{ $t("tproxyWhiteIpGroups.us") }}</option>
<option value="CLOUDFLARE">{{ $t("tproxyWhiteIpGroups.cloudflare") }}</option>
</b-select>
</b-field>
<b-field :label="$t('tproxyWhiteIpGroups.formName2')">
<b-input v-model="customIps" type="textarea" :placeholder="$t('tproxyWhiteIpGroups.formPlaceholder2')"
custom-class="full-min-height horizon-scroll code-font" />
</b-field>
<b-message type="is-warning" class="after-line-dot5">
<p>{{ $t("tproxyWhiteIpGroups.messages.1") }}</p>
</b-message>
</section>
<footer class="modal-card-foot flex-end">
<button class="button" @click="$emit('close')">
{{ $t("operations.cancel") }}
</button>
<button class="button is-primary" @click="handleClickSubmit">
{{ $t("operations.save") }}
</button>
</footer>
</div>
</template>
<script>
import { handleResponse } from "@/assets/js/utils";
export default {
name: "modalTproxyWhiteIpGroups",
data: () => ({
countryCodes: [],
customIps: "",
}),
created() {
this.$axios({
url: apiRoot + "/tproxyWhiteIpGroups",
}).then((res) => {
handleResponse(res, this, () => {
if (res.data.data.countryCodes) {
this.countryCodes = res.data.data.countryCodes;
}
if (res.data.data.customIps) {
this.customIps = res.data.data.customIps.join("\n");
}
});
});
},
methods: {
validateCIDRArray(arr) {
const ipv4Cidr = /^(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}\/(?:[0-9]|[12]\d|3[0-2])$/;
const ipv6Cidr = /^(?:(?:[A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}|(?:[A-Fa-f0-9]{1,4}:){1,7}:|(?:[A-Fa-f0-9]{1,4}:){1,6}:[A-Fa-f0-9]{1,4}|(?:[A-Fa-f0-9]{1,4}:){1,5}(?::[A-Fa-f0-9]{1,4}){1,2}|(?:[A-Fa-f0-9]{1,4}:){1,4}(?::[A-Fa-f0-9]{1,4}){1,3}|(?:[A-Fa-f0-9]{1,4}:){1,3}(?::[A-Fa-f0-9]{1,4}){1,4}|(?:[A-Fa-f0-9]{1,4}:){1,2}(?::[A-Fa-f0-9]{1,4}){1,5}|[A-Fa-f0-9]{1,4}:(?:(?::[A-Fa-f0-9]{1,4}){1,6})|:(?:(?::[A-Fa-f0-9]{1,4}){1,7}|:))\/(?:12[0-8]|1[01]\d|[1-9]?\d)$/;
const invalid = arr
.map(s => (typeof s === 'string' ? s.trim() : ''))
.filter(s => s.length === 0 || !(ipv4Cidr.test(s) || ipv6Cidr.test(s)));
return invalid.length === 0;
},
handleClickSubmit() {
if (!this.validateCIDRArray(this.customIps.split("\n").filter(line => line.trim() !== ''))) {
this.$buefy.toast.open({
message: this.$t("tproxyWhiteIpGroups.invalidCustomIps"),
type: "is-danger",
position: "is-top",
queue: false,
duration: 10000,
});
return
}
this.$axios({
url: apiRoot + "/tproxyWhiteIpGroups",
method: "put",
data: {
countryCodes: this.countryCodes.length ? this.countryCodes : ['NONE'],
customIps: this.customIps.split("\n").filter(line => line.trim() !== ''),
},
}).then((res) => {
handleResponse(res, this, () => {
this.$emit("close");
});
});
},
},
};
</script>
+17 -1
View File
@@ -64,6 +64,7 @@ export default {
},
operations: {
name: "Operations",
tproxyWhiteIpGroups: "Direct Whitelist IP Groups",
update: "Update",
autoUpdate: "Auto Update",
manualUpdate: "Manual Update",
@@ -91,7 +92,7 @@ export default {
no: "No",
switchSite: "Switch to alternate site",
addOutbound: "Add an outbound",
domainsExcluded:"Domains Excluded"
domainsExcluded: "Domains Excluded"
},
register: {
title: "Create an admin account first",
@@ -328,6 +329,21 @@ export default {
seconds: "seconds",
autoScoll: "Auto Scroll",
},
tproxyWhiteIpGroups: {
title: "White IP Groups",
messages: [
"The selected IP group will bypass the XRay/V2Ray core and go directly outbound (through Nftables/Iptables). Please ensure your DNS server is reliable and free of contamination so that clients can resolve the correct IPs.",
"It's best to use this feature when your system is using Nftables, as iptables may experience performance issues when adding a large number of IPs."
],
formName1: "Hold down Ctrl to select multiple items.",
formName2: "Custom IPs (one per line, standard CIDR format)",
formPlaceholder2: "172.30.0.0/16\nfd00:aaaa:bbbb::/48",
invalidCustomIps:"Invalid Custom IPs",
cn: 'China Mainland',
private: 'Private',
us: 'United States',
cloudflare: 'Cloudflare',
},
domainsExcluded: {
title: "Domains Excluded",
messages: [
+17
View File
@@ -62,6 +62,7 @@ export default {
subscription: "订阅",
},
operations: {
tproxyWhiteIpGroups: "直通白名单IP组",
name: "操作",
update: "更新",
autoUpdate: "自动更新",
@@ -330,6 +331,22 @@ export default {
seconds: "秒",
autoScoll: "自动滚动",
},
tproxyWhiteIpGroups: {
title: "直通白名单IP组",
messages: [
"选中的IP组将会不经过XRay/V2Ray核心直接出站(通过Nftables/Iptables直接转发),请确保你的DNS服务器足够可靠无污染能使客户端能解析到正确的IP",
"最好系统使用Nftables时使用此功能,Iptables可能在添加大量IP时存在性能问题"
],
formName1: "按住Ctrl可以多选",
formName2: "自定义IP(一行一个,标准CIDR格式)",
formPlaceholder2: "172.30.0.0/16\nfd00:dead:beef::/48",
invalidCustomIps:"自定义IP格式错误",
cn: '中国大陆',
private: '私网网段',
us: '美国',
cloudflare: 'Cloudflare',
},
domainsExcluded: {
title: "排除域名",
messages: [
+2
View File
@@ -1294,6 +1294,7 @@ export default {
let cancel;
if (!row.connected) {
//
let loading = this.$buefy.loading.open();
waitingConnected(
this.$axios({
url: apiRoot + "/connection",
@@ -1308,6 +1309,7 @@ export default {
cancel = c;
}),
}).then((res) => {
loading.close();
if (res.data.code === "SUCCESS") {
Object.assign(this.runningState, {
running: res.data.data.running
@@ -0,0 +1,238 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v3.21.12
// source: service/common/parseGeoIP/geoip.proto
package parseGeoIP
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type CIDR struct {
state protoimpl.MessageState `protogen:"open.v1"`
// IP address, should be either 4 or 16 bytes.
Ip []byte `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"`
// Number of leading ones in the network mask.
Prefix uint32 `protobuf:"varint,2,opt,name=prefix,proto3" json:"prefix,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CIDR) Reset() {
*x = CIDR{}
mi := &file_service_common_parseGeoIP_geoip_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CIDR) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CIDR) ProtoMessage() {}
func (x *CIDR) ProtoReflect() protoreflect.Message {
mi := &file_service_common_parseGeoIP_geoip_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CIDR.ProtoReflect.Descriptor instead.
func (*CIDR) Descriptor() ([]byte, []int) {
return file_service_common_parseGeoIP_geoip_proto_rawDescGZIP(), []int{0}
}
func (x *CIDR) GetIp() []byte {
if x != nil {
return x.Ip
}
return nil
}
func (x *CIDR) GetPrefix() uint32 {
if x != nil {
return x.Prefix
}
return 0
}
type GeoIP struct {
state protoimpl.MessageState `protogen:"open.v1"`
CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
Cidr []*CIDR `protobuf:"bytes,2,rep,name=cidr,proto3" json:"cidr,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GeoIP) Reset() {
*x = GeoIP{}
mi := &file_service_common_parseGeoIP_geoip_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GeoIP) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoIP) ProtoMessage() {}
func (x *GeoIP) ProtoReflect() protoreflect.Message {
mi := &file_service_common_parseGeoIP_geoip_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoIP.ProtoReflect.Descriptor instead.
func (*GeoIP) Descriptor() ([]byte, []int) {
return file_service_common_parseGeoIP_geoip_proto_rawDescGZIP(), []int{1}
}
func (x *GeoIP) GetCountryCode() string {
if x != nil {
return x.CountryCode
}
return ""
}
func (x *GeoIP) GetCidr() []*CIDR {
if x != nil {
return x.Cidr
}
return nil
}
type GeoIPList struct {
state protoimpl.MessageState `protogen:"open.v1"`
Entry []*GeoIP `protobuf:"bytes,1,rep,name=entry,proto3" json:"entry,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GeoIPList) Reset() {
*x = GeoIPList{}
mi := &file_service_common_parseGeoIP_geoip_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GeoIPList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoIPList) ProtoMessage() {}
func (x *GeoIPList) ProtoReflect() protoreflect.Message {
mi := &file_service_common_parseGeoIP_geoip_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoIPList.ProtoReflect.Descriptor instead.
func (*GeoIPList) Descriptor() ([]byte, []int) {
return file_service_common_parseGeoIP_geoip_proto_rawDescGZIP(), []int{2}
}
func (x *GeoIPList) GetEntry() []*GeoIP {
if x != nil {
return x.Entry
}
return nil
}
var File_service_common_parseGeoIP_geoip_proto protoreflect.FileDescriptor
const file_service_common_parseGeoIP_geoip_proto_rawDesc = "" +
"\n" +
"%service/common/parseGeoIP/geoip.proto\".\n" +
"\x04CIDR\x12\x0e\n" +
"\x02ip\x18\x01 \x01(\fR\x02ip\x12\x16\n" +
"\x06prefix\x18\x02 \x01(\rR\x06prefix\"E\n" +
"\x05GeoIP\x12!\n" +
"\fcountry_code\x18\x01 \x01(\tR\vcountryCode\x12\x19\n" +
"\x04cidr\x18\x02 \x03(\v2\x05.CIDRR\x04cidr\")\n" +
"\tGeoIPList\x12\x1c\n" +
"\x05entry\x18\x01 \x03(\v2\x06.GeoIPR\x05entryB\x1dZ\x1b./service/common/parseGeoIPb\x06proto3"
var (
file_service_common_parseGeoIP_geoip_proto_rawDescOnce sync.Once
file_service_common_parseGeoIP_geoip_proto_rawDescData []byte
)
func file_service_common_parseGeoIP_geoip_proto_rawDescGZIP() []byte {
file_service_common_parseGeoIP_geoip_proto_rawDescOnce.Do(func() {
file_service_common_parseGeoIP_geoip_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_service_common_parseGeoIP_geoip_proto_rawDesc), len(file_service_common_parseGeoIP_geoip_proto_rawDesc)))
})
return file_service_common_parseGeoIP_geoip_proto_rawDescData
}
var file_service_common_parseGeoIP_geoip_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_service_common_parseGeoIP_geoip_proto_goTypes = []any{
(*CIDR)(nil), // 0: CIDR
(*GeoIP)(nil), // 1: GeoIP
(*GeoIPList)(nil), // 2: GeoIPList
}
var file_service_common_parseGeoIP_geoip_proto_depIdxs = []int32{
0, // 0: GeoIP.cidr:type_name -> CIDR
1, // 1: GeoIPList.entry:type_name -> GeoIP
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_service_common_parseGeoIP_geoip_proto_init() }
func file_service_common_parseGeoIP_geoip_proto_init() {
if File_service_common_parseGeoIP_geoip_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_service_common_parseGeoIP_geoip_proto_rawDesc), len(file_service_common_parseGeoIP_geoip_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_service_common_parseGeoIP_geoip_proto_goTypes,
DependencyIndexes: file_service_common_parseGeoIP_geoip_proto_depIdxs,
MessageInfos: file_service_common_parseGeoIP_geoip_proto_msgTypes,
}.Build()
File_service_common_parseGeoIP_geoip_proto = out.File
file_service_common_parseGeoIP_geoip_proto_goTypes = nil
file_service_common_parseGeoIP_geoip_proto_depIdxs = nil
}
@@ -0,0 +1,20 @@
syntax = "proto3";
option go_package = "./service/common/parseGeoIP";
message CIDR {
// IP address, should be either 4 or 16 bytes.
bytes ip = 1;
// Number of leading ones in the network mask.
uint32 prefix = 2;
}
message GeoIP {
string country_code = 1;
repeated CIDR cidr = 2;
}
message GeoIPList {
repeated GeoIP entry = 1;
}
@@ -0,0 +1,49 @@
package parseGeoIP
import (
"fmt"
"net"
"os"
"strings"
"github.com/v2rayA/v2rayA/core/v2ray/asset"
"google.golang.org/protobuf/proto"
)
func Parser(filename string, countryCode string) ([]string, []string, error) {
var ipv4List []string
var ipv6List []string
var geoIpProto GeoIPList
realpath, err := asset.GetV2rayLocationAsset(filename)
if err != nil {
return ipv4List, ipv6List, err
}
data, err := os.ReadFile(realpath)
if err != nil {
return ipv4List, ipv6List, err
}
if err := proto.Unmarshal(data, &geoIpProto); err != nil {
return ipv4List, ipv6List, err
}
for _, geo := range geoIpProto.Entry {
if geo.CountryCode == countryCode {
for _, c := range geo.Cidr {
ip := net.IP(c.Ip)
if strings.Contains(ip.String(), ":") {
ipv6List = append(ipv6List, fmt.Sprintf("%s/%d", ip.String(), c.Prefix))
} else {
if strings.Contains(ip.String(), "198.18.0.0") {
// 跳过fakeip
continue
}
ipv4List = append(ipv4List, fmt.Sprintf("%s/%d", ip.String(), c.Prefix))
}
}
break
}
}
return ipv4List, ipv6List, nil
}
+1
View File
@@ -56,6 +56,7 @@ type Sniffing struct {
DestOverride []string `json:"destOverride,omitempty"`
MetadataOnly bool `json:"metadataOnly"`
DomainsExcluded []string `json:"domainsExcluded"`
RouteOnly bool `json:"routeOnly"`
}
type Inbound struct {
Port int `json:"port"`
+40 -52
View File
@@ -2,12 +2,13 @@ package iptables
import (
"fmt"
"github.com/v2rayA/v2rayA/common/cmds"
"github.com/v2rayA/v2rayA/core/v2ray/asset"
"github.com/v2rayA/v2rayA/db/configure"
"os"
"strconv"
"strings"
"github.com/v2rayA/v2rayA/common/cmds"
"github.com/v2rayA/v2rayA/core/v2ray/asset"
"github.com/v2rayA/v2rayA/db/configure"
)
var (
@@ -106,23 +107,14 @@ iptables -w 2 -t mangle -A TP_RULE -p tcp --dport 53 -j TP_MARK
iptables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN
`
}
if IsEnabledTproxyWhiteIpGroups() {
whiteIpv4List, _ := GetWhiteListIPs()
for _, v := range whiteIpv4List {
commands += fmt.Sprintf("iptables -w 2 -t mangle -A TP_RULE -d %s -j RETURN\n", v)
}
}
commands += `
iptables -w 2 -t mangle -A TP_RULE -d 0.0.0.0/32 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 10.0.0.0/8 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 100.64.0.0/10 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 127.0.0.0/8 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 169.254.0.0/16 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 172.16.0.0/12 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 192.0.0.0/24 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 192.0.2.0/24 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 192.88.99.0/24 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 192.168.0.0/16 -j RETURN
# fakedns
# iptables -w 2 -t mangle -A TP_RULE -d 198.18.0.0/15 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 198.51.100.0/24 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 203.0.113.0/24 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 224.0.0.0/4 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -d 240.0.0.0/4 -j RETURN
iptables -w 2 -t mangle -A TP_RULE -j TP_MARK
iptables -w 2 -t mangle -A TP_MARK -p tcp -m tcp --syn -j MARK --set-xmark 0x40/0x40
@@ -170,15 +162,13 @@ ip6tables -w 2 -t mangle -A TP_RULE -p tcp --dport 53 -j TP_MARK
ip6tables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN
`
}
if IsEnabledTproxyWhiteIpGroups() {
_, whiteIpv6List := GetWhiteListIPs()
for _, v := range whiteIpv6List {
commands += fmt.Sprintf("ip6tables -w 2 -t mangle -A TP_RULE -d %s -j RETURN\n", v)
}
}
commands += `
ip6tables -w 2 -t mangle -A TP_RULE -d ::/128 -j RETURN
ip6tables -w 2 -t mangle -A TP_RULE -d ::1/128 -j RETURN
ip6tables -w 2 -t mangle -A TP_RULE -d 64:ff9b::/96 -j RETURN
ip6tables -w 2 -t mangle -A TP_RULE -d 100::/64 -j RETURN
ip6tables -w 2 -t mangle -A TP_RULE -d 2001::/32 -j RETURN
ip6tables -w 2 -t mangle -A TP_RULE -d 2001:20::/28 -j RETURN
ip6tables -w 2 -t mangle -A TP_RULE -d fe80::/10 -j RETURN
ip6tables -w 2 -t mangle -A TP_RULE -d ff00::/8 -j RETURN
ip6tables -w 2 -t mangle -A TP_RULE -j TP_MARK
ip6tables -w 2 -t mangle -A TP_MARK -p tcp -m tcp --syn -j MARK --set-xmark 0x40/0x40
@@ -246,28 +236,20 @@ func (t *nftTproxy) RemoveIPWhitelist(cidr string) {
}
func (t *nftTproxy) GetSetupCommands() Setter {
// 198.18.0.0/15 and fc00::/7 are reserved for private use but used by fakedns
table := `
table inet v2raya {
table inet v2raya {
`
if IsEnabledTproxyWhiteIpGroups() {
whiteIpv4List, whiteIpv6List := GetWhiteListIPs()
table += `
set whitelist {
type ipv4_addr
flags interval
auto-merge
elements = {
0.0.0.0/32,
10.0.0.0/8,
100.64.0.0/10,
127.0.0.0/8,
169.254.0.0/16,
172.16.0.0/12,
192.0.0.0/24,
192.0.2.0/24,
192.88.99.0/24,
192.168.0.0/16,
198.51.100.0/24,
203.0.113.0/24,
224.0.0.0/4,
240.0.0.0/4
`
table += strings.Join(whiteIpv4List, ",")
table += `
}
}
@@ -276,17 +258,17 @@ table inet v2raya {
flags interval
auto-merge
elements = {
::/128,
::1/128,
64:ff9b::/96,
100::/64,
2001::/32,
2001:20::/28,
fe80::/10,
ff00::/8
`
table += strings.Join(whiteIpv6List, ",")
table += `
}
}
`
}
// 198.18.0.0/15 and fc00::/7 are reserved for private use but used by fakedns
table += `
set interface {
type ipv4_addr
flags interval
@@ -335,9 +317,15 @@ table inet v2raya {
iifname "ppp*" return
# anti-pollution
ip daddr @interface return
`
if IsEnabledTproxyWhiteIpGroups() {
table += `
ip daddr @whitelist return
ip6 daddr @interface6 return
ip6 daddr @whitelist6 return
`
}
table += `
ip6 daddr @interface6 return
jump tp_mark
}
+27
View File
@@ -9,7 +9,9 @@ import (
"github.com/v2rayA/v2rayA/common"
"github.com/v2rayA/v2rayA/common/cmds"
"github.com/v2rayA/v2rayA/common/parseGeoIP"
"github.com/v2rayA/v2rayA/conf"
"github.com/v2rayA/v2rayA/db/configure"
"golang.org/x/net/nettest"
)
@@ -89,3 +91,28 @@ func IsNftablesSupported() bool {
}
return strings.Contains(string(out), "nf_tables")
}
func GetWhiteListIPs() ([]string, []string) {
dataModal := configure.GetTproxyWhiteIpGroups()
var ipv4List []string
var ipv6List []string
for _, cc := range dataModal.CountryCodes {
ipv4s, ipv6s, _ := parseGeoIP.Parser("geoip.dat", cc)
ipv4List = append(ipv4List, ipv4s...)
ipv6List = append(ipv6List, ipv6s...)
}
for _, v := range dataModal.CustomIps {
if strings.Contains(v, ":") {
ipv6List = append(ipv6List, v)
} else {
ipv4List = append(ipv4List, v)
}
}
return ipv4List, ipv6List
}
func IsEnabledTproxyWhiteIpGroups() bool {
ipv4List, ipv6List := GetWhiteListIPs()
return len(ipv4List) > 0 && len(ipv6List) > 0
}
+4
View File
@@ -668,6 +668,7 @@ func parseRoutingA(t *Template, routingInboundTags []string) error {
Sniffing: coreObj.Sniffing{
Enabled: false,
DestOverride: []string{"http", "tls"},
RouteOnly: false,
},
}
if sniffing := proto.NamedParams["sniffing"]; len(sniffing) > 0 {
@@ -1117,6 +1118,7 @@ func (t *Template) setInbound(setting *configure.Setting) error {
// 设置域名嗅探
if setting.InboundSniffing != configure.InboundSniffingDisable && setting.InboundSniffing != "" {
enableSniffingRouteOnly := configure.GetSettingNotNil().RouteOnly
domainsExcludedText := configure.GetDomainsExcluded()
for i := len(t.Inbounds) - 1; i >= 0; i-- {
if setting.InboundSniffing == configure.InboundSniffingHttpTLS {
@@ -1126,7 +1128,9 @@ func (t *Template) setInbound(setting *configure.Setting) error {
}
t.Inbounds[i].Sniffing.DomainsExcluded = strings.Split(domainsExcludedText, "\n")
t.Inbounds[i].Sniffing.Enabled = true
t.Inbounds[i].Sniffing.RouteOnly = enableSniffingRouteOnly
}
}
return nil
}
+21 -10
View File
@@ -16,16 +16,17 @@ import (
)
type Configure struct {
Servers []*ServerRaw `json:"servers"`
Subscriptions []*SubscriptionRaw `json:"subscriptions"`
ConnectedServers []*Which `json:"connectedServers"`
Setting *Setting `json:"setting"`
Accounts map[string]string `json:"accounts"`
Ports Ports `json:"ports"`
InternalDnsList *string `json:"internalDnsList"`
ExternalDnsList *string `json:"externalDnsList"`
RoutingA *string `json:"routingA"`
DomainsExcluded *string `json:"domainsExcluded"`
Servers []*ServerRaw `json:"servers"`
Subscriptions []*SubscriptionRaw `json:"subscriptions"`
ConnectedServers []*Which `json:"connectedServers"`
Setting *Setting `json:"setting"`
Accounts map[string]string `json:"accounts"`
Ports Ports `json:"ports"`
InternalDnsList *string `json:"internalDnsList"`
ExternalDnsList *string `json:"externalDnsList"`
RoutingA *string `json:"routingA"`
DomainsExcluded *string `json:"domainsExcluded"`
TproxyWhiteIpGroups TproxyWhiteIpGroups `json:"tproxyWhiteIpGroups"`
}
func New() *Configure {
@@ -275,10 +276,20 @@ func GetRoutingA() (r string) {
func SetDomainsExcluded(domains string) (err error) {
return db.Set("system", "domainsExcluded", domains)
}
func SetTproxyWhiteIpGroups(countryCodes []string, customIps []string) (err error) {
return db.Set("system", "tproxyWhiteIpGroups", TproxyWhiteIpGroups{
CountryCodes: countryCodes,
CustomIps: customIps,
})
}
func GetDomainsExcluded() (r string) {
db.Get("system", "domainsExcluded", &r)
return r
}
func GetTproxyWhiteIpGroups() (r TproxyWhiteIpGroups) {
db.Get("system", "tproxyWhiteIpGroups", &r)
return r
}
func GetConnectedServers() (wts *Whiches) {
outbounds := GetOutbounds()
for _, outbound := range outbounds {
+1
View File
@@ -19,6 +19,7 @@ type Setting struct {
InboundSniffing InboundSniffing `json:"inboundSniffing"`
Transparent TransparentMode `json:"transparent"`
IpForward bool `json:"ipforward"`
RouteOnly bool `json:"routeOnly"`
PortSharing bool `json:"portSharing"`
SpecialMode SpecialMode `json:"specialMode"`
TransparentType TransparentType `json:"transparentType"`
@@ -0,0 +1,6 @@
package configure
type TproxyWhiteIpGroups struct {
CountryCodes []string `json:"countryCodes"`
CustomIps []string `json:"customIps"`
}
+6
View File
@@ -157,11 +157,17 @@ func initConfigure() {
}
}
}
log.Warn("Migration is done")
} else {
initDBValue()
}
}
if len(configure.GetTproxyWhiteIpGroups().CountryCodes) == 0 {
configure.SetTproxyWhiteIpGroups([]string{"PRIVATE"}, []string{})
}
//检查config.json是否存在
if _, err := os.Stat(asset.GetV2rayConfigPath()); err != nil {
//不存在就建一个。多数情况发生于docker模式挂载volume时覆盖了/etc/v2ray
@@ -0,0 +1,29 @@
package controller
import (
"github.com/gin-gonic/gin"
"github.com/v2rayA/v2rayA/common"
"github.com/v2rayA/v2rayA/db/configure"
)
func GetTproxyWhiteIpGroups(ctx *gin.Context) {
resp := configure.GetTproxyWhiteIpGroups()
common.ResponseSuccess(ctx, gin.H{
"countryCodes": resp.CountryCodes,
"customIps": resp.CustomIps,
})
}
func PutTproxyWhiteIpGroups(ctx *gin.Context) {
var data struct {
CountryCodes []string `json:"countryCodes"`
CustomIps []string `json:"customIps"`
}
err := ctx.ShouldBindJSON(&data)
if err != nil {
common.ResponseError(ctx, logError("bad request"))
return
}
configure.SetTproxyWhiteIpGroups(data.CountryCodes, data.CustomIps)
common.ResponseSuccess(ctx, nil)
}
+2
View File
@@ -197,7 +197,9 @@ func Run() error {
auth.GET("message", controller.WsMessage)
auth.GET("logger", controller.GetLogger)
auth.GET("domainsExcluded", controller.GetDomainsExcluded)
auth.GET("tproxyWhiteIpGroups", controller.GetTproxyWhiteIpGroups)
auth.PUT("domainsExcluded", controller.PutDomainsExcluded)
auth.PUT("tproxyWhiteIpGroups", controller.PutTproxyWhiteIpGroups)
}
ServeGUI(engine)
+2 -2
View File
@@ -12,8 +12,8 @@ android {
applicationId = "com.v2ray.ang"
minSdk = 21
targetSdk = 35
versionCode = 677
versionName = "1.10.26"
versionCode = 678
versionName = "1.10.27"
multiDexEnabled = true
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
+7
View File
@@ -560,6 +560,13 @@ class FFmpegFD(ExternalFD):
elif isinstance(conn, str):
args += ['-rtmp_conn', conn]
elif protocol == 'http_dash_segments' and info_dict.get('is_live'):
# ffmpeg may try to read past the latest available segments for
# live DASH streams unless we pass `-re`. In modern ffmpeg, this
# is an alias of `-readrate 1`, but `-readrate` was not added
# until ffmpeg 5.0, so we must stick to using `-re`
args += ['-re']
url = fmt['url']
if self.params.get('enable_file_urls') and url.startswith('file:'):
# The default protocol_whitelist is 'file,crypto,data' when reading local m3u8 URLs,
+3 -2
View File
@@ -340,8 +340,9 @@ class YoutubeTabBaseInfoExtractor(YoutubeBaseInfoExtractor):
thumbnails=self._extract_thumbnails(view_model, (
'contentImage', *thumb_keys, 'thumbnailViewModel', 'image'), final_key='sources'),
duration=traverse_obj(view_model, (
'contentImage', 'thumbnailViewModel', 'overlays', ..., 'thumbnailOverlayBadgeViewModel',
'thumbnailBadges', ..., 'thumbnailBadgeViewModel', 'text', {parse_duration}, any)),
'contentImage', 'thumbnailViewModel', 'overlays', ...,
(('thumbnailBottomOverlayViewModel', 'badges'), ('thumbnailOverlayBadgeViewModel', 'thumbnailBadges')),
..., 'thumbnailBadgeViewModel', 'text', {parse_duration}, any)),
timestamp=(traverse_obj(view_model, (
'metadata', 'lockupMetadataViewModel', 'metadata', 'contentMetadataViewModel', 'metadataRows',
..., 'metadataParts', ..., 'text', 'content', {lambda t: self._parse_time_text(t, report_failure=False)}, any))
+82 -28
View File
@@ -1556,6 +1556,46 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
'view_count': int,
},
'params': {'skip_download': True},
}, {
# Youtube Music Auto-generated description with dot in artist name
'url': 'https://music.youtube.com/watch?v=DbCvuSGfR3Y',
'info_dict': {
'id': 'DbCvuSGfR3Y',
'ext': 'mp4',
'title': 'Back Around',
'artists': ['half·alive'],
'track': 'Back Around',
'album': 'Conditions Of A Punk',
'release_date': '20221202',
'release_year': 2021,
'alt_title': 'Back Around',
'description': 'md5:bfc0e2b3cc903a608d8a85a13cb50f95',
'media_type': 'video',
'uploader': 'half•alive',
'channel': 'half•alive',
'channel_id': 'UCYQrYophdVI3nVDPOnXyIng',
'channel_url': 'https://www.youtube.com/channel/UCYQrYophdVI3nVDPOnXyIng',
'channel_is_verified': True,
'channel_follower_count': int,
'comment_count': int,
'view_count': int,
'like_count': int,
'age_limit': 0,
'duration': 223,
'thumbnail': 'https://i.ytimg.com/vi_webp/DbCvuSGfR3Y/maxresdefault.webp',
'heatmap': 'count:100',
'categories': ['Music'],
'tags': ['half·alive', 'Conditions Of A Punk', 'Back Around'],
'creators': ['half·alive'],
'timestamp': 1669889281,
'upload_date': '20221201',
'playable_in_embed': True,
'availability': 'public',
'live_status': 'not_live',
},
'params': {
'skip_download': True,
},
}]
_WEBPAGE_TESTS = [{
# <object>
@@ -3023,8 +3063,12 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
def _extract_formats_and_subtitles(self, video_id, player_responses, player_url, live_status, duration):
CHUNK_SIZE = 10 << 20
PREFERRED_LANG_VALUE = 10
original_language = None
ORIGINAL_LANG_VALUE = 10
DEFAULT_LANG_VALUE = 5
language_map = {
ORIGINAL_LANG_VALUE: None,
DEFAULT_LANG_VALUE: None,
}
itags, stream_ids = collections.defaultdict(set), []
itag_qualities, res_qualities = {}, {0: None}
subtitles = {}
@@ -3064,6 +3108,22 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
# For handling potential pre-playback required waiting period
playback_wait = int_or_none(self._configuration_arg('playback_wait', [None])[0], default=6)
def get_language_code_and_preference(fmt_stream):
audio_track = fmt_stream.get('audioTrack') or {}
display_name = audio_track.get('displayName') or ''
language_code = audio_track.get('id', '').split('.')[0] or None
if 'descriptive' in display_name.lower():
return join_nonempty(language_code, 'desc'), -10
if 'original' in display_name.lower():
if language_code and not language_map.get(ORIGINAL_LANG_VALUE):
language_map[ORIGINAL_LANG_VALUE] = language_code
return language_code, ORIGINAL_LANG_VALUE
if audio_track.get('audioIsDefault'):
if language_code and not language_map.get(DEFAULT_LANG_VALUE):
language_map[DEFAULT_LANG_VALUE] = language_code
return language_code, DEFAULT_LANG_VALUE
return language_code, -1
for pr in player_responses:
streaming_data = traverse_obj(pr, 'streamingData')
if not streaming_data:
@@ -3079,7 +3139,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
return str_or_none(fmt_stream.get('itag')), traverse_obj(fmt_stream, 'audioTrack', 'id'), fmt_stream.get('isDrc')
def process_format_stream(fmt_stream, proto, missing_pot):
nonlocal original_language
itag = str_or_none(fmt_stream.get('itag'))
audio_track = fmt_stream.get('audioTrack') or {}
quality = fmt_stream.get('quality')
@@ -3096,13 +3155,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
if height:
res_qualities[height] = quality
display_name = audio_track.get('displayName') or ''
is_original = 'original' in display_name.lower()
is_descriptive = 'descriptive' in display_name.lower()
is_default = audio_track.get('audioIsDefault')
language_code = audio_track.get('id', '').split('.')[0]
if language_code and (is_original or (is_default and not original_language)):
original_language = language_code
language_code, language_preference = get_language_code_and_preference(fmt_stream)
has_drm = bool(fmt_stream.get('drmFamilies'))
@@ -3138,7 +3191,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
'filesize': int_or_none(fmt_stream.get('contentLength')),
'format_id': f'{itag}{"-drc" if fmt_stream.get("isDrc") else ""}',
'format_note': join_nonempty(
join_nonempty(display_name, is_default and ' (default)', delim=''),
join_nonempty(audio_track.get('displayName'), audio_track.get('audioIsDefault') and '(default)', delim=' '),
name, fmt_stream.get('isDrc') and 'DRC',
try_get(fmt_stream, lambda x: x['projectionType'].replace('RECTANGULAR', '').lower()),
try_get(fmt_stream, lambda x: x['spatialAudioType'].replace('SPATIAL_AUDIO_TYPE_', '').lower()),
@@ -3155,8 +3208,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
'tbr': tbr,
'filesize_approx': filesize_from_tbr(tbr, format_duration),
'width': int_or_none(fmt_stream.get('width')),
'language': join_nonempty(language_code, 'desc' if is_descriptive else '') or None,
'language_preference': PREFERRED_LANG_VALUE if is_original else 5 if is_default else -10 if is_descriptive else -1,
'language': language_code,
'language_preference': language_preference,
# Strictly de-prioritize damaged and 3gp formats
'preference': -10 if is_damaged else -2 if itag == '17' else None,
}
@@ -3206,6 +3259,9 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
fmt_url = fmt_stream.get('url')
encrypted_sig, sc = None, None
if not fmt_url:
# We still need to register original/default language information
# See: https://github.com/yt-dlp/yt-dlp/issues/14883
get_language_code_and_preference(fmt_stream)
sc = urllib.parse.parse_qs(fmt_stream.get('signatureCipher'))
fmt_url = url_or_none(try_get(sc, lambda x: x['url'][0]))
encrypted_sig = try_get(sc, lambda x: x['s'][0])
@@ -3391,9 +3447,13 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
elif itag:
f['format_id'] = itag
if original_language and f.get('language') == original_language:
lang_code = f.get('language')
if lang_code and lang_code == language_map[ORIGINAL_LANG_VALUE]:
f['format_note'] = join_nonempty(f.get('format_note'), '(original)', delim=' ')
f['language_preference'] = ORIGINAL_LANG_VALUE
elif lang_code and lang_code == language_map[DEFAULT_LANG_VALUE]:
f['format_note'] = join_nonempty(f.get('format_note'), '(default)', delim=' ')
f['language_preference'] = PREFERRED_LANG_VALUE
f['language_preference'] = DEFAULT_LANG_VALUE
if itag in ('616', '235'):
f['format_note'] = join_nonempty(f.get('format_note'), 'Premium', delim=' ')
@@ -3988,20 +4048,14 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
# Youtube Music Auto-generated description
if (video_description or '').strip().endswith('\nAuto-generated by YouTube.'):
# XXX: Causes catastrophic backtracking if description has "·"
# E.g. https://www.youtube.com/watch?v=DoPaAxMQoiI
# Simulating atomic groups: (?P<a>[^xy]+)x => (?=(?P<a>[^xy]+))(?P=a)x
# reduces it, but does not fully fix it. https://regex101.com/r/8Ssf2h/2
mobj = re.search(
r'''(?xs)
(?=(?P<track>[^\n·]+))(?P=track)·
(?=(?P<artist>[^\n]+))(?P=artist)\n+
(?=(?P<album>[^\n]+))(?P=album)\n
(?:.+?\s*(?P<release_year>\d{4})(?!\d))?
(?:.+?Released\ on\s*:\s*(?P<release_date>\d{4}-\d{2}-\d{2}))?
(.+?\nArtist\s*:\s*
(?=(?P<clean_artist>[^\n]+))(?P=clean_artist)\n
)?.+\nAuto-generated\ by\ YouTube\.\s*$
(?:\n|^)(?P<track>[^\n·]+)\ ·\ (?P<artist>[^\n]+)\n+
(?P<album>[^\n]+)\n+
(?:\s*(?P<release_year>\d{4}))?
(?:.+?\nReleased\ on\s*:\s*(?P<release_date>\d{4}-\d{2}-\d{2}))?
(?:.+?\nArtist\s*:\s*(?P<clean_artist>[^\n]+)\n)?
.+\nAuto-generated\ by\ YouTube\.\s*$
''', video_description)
if mobj:
release_year = mobj.group('release_year')
@@ -4013,7 +4067,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
info.update({
'album': mobj.group('album'.strip()),
'artists': ([a] if (a := mobj.group('clean_artist'))
else [a.strip() for a in mobj.group('artist').split('·')]),
else [a.strip() for a in mobj.group('artist').split(' · ')]),
'track': mobj.group('track').strip(),
'release_date': release_date,
'release_year': int_or_none(release_year),