Optimize provider page

Optimize delay test

Support local backup and recovery
This commit is contained in:
chen08209
2024-08-04 08:21:14 +08:00
parent 6cfcaa4edc
commit bee2f8aa4f
53 changed files with 1993 additions and 1128 deletions

View File

@@ -2,19 +2,23 @@ package main
import "C"
import (
"context"
"github.com/metacubex/mihomo/adapter"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/adapter/outboundgroup"
ap "github.com/metacubex/mihomo/adapter/provider"
"github.com/metacubex/mihomo/adapter/provider"
"github.com/metacubex/mihomo/common/batch"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/config"
"github.com/metacubex/mihomo/constant"
cp "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/hub"
"github.com/metacubex/mihomo/hub/executor"
"github.com/metacubex/mihomo/hub/route"
"github.com/metacubex/mihomo/listener"
"github.com/metacubex/mihomo/log"
rp "github.com/metacubex/mihomo/rules/provider"
"github.com/metacubex/mihomo/tunnel"
"os"
"os/exec"
@@ -26,40 +30,40 @@ import (
"time"
)
type healthCheckSchema struct {
Enable bool `provider:"enable"`
URL string `provider:"url"`
Interval int `provider:"interval"`
TestTimeout int `provider:"timeout,omitempty"`
Lazy bool `provider:"lazy,omitempty"`
ExpectedStatus string `provider:"expected-status,omitempty"`
}
//type healthCheckSchema struct {
// Enable bool `provider:"enable"`
// URL string `provider:"url"`
// Interval int `provider:"interval"`
// TestTimeout int `provider:"timeout,omitempty"`
// Lazy bool `provider:"lazy,omitempty"`
// ExpectedStatus string `provider:"expected-status,omitempty"`
//}
type proxyProviderSchema struct {
Type string `provider:"type"`
Path string `provider:"path,omitempty"`
URL string `provider:"url,omitempty"`
Proxy string `provider:"proxy,omitempty"`
Interval int `provider:"interval,omitempty"`
Filter string `provider:"filter,omitempty"`
ExcludeFilter string `provider:"exclude-filter,omitempty"`
ExcludeType string `provider:"exclude-type,omitempty"`
DialerProxy string `provider:"dialer-proxy,omitempty"`
HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
Override ap.OverrideSchema `provider:"override,omitempty"`
Header map[string][]string `provider:"header,omitempty"`
}
type ruleProviderSchema struct {
Type string `provider:"type"`
Behavior string `provider:"behavior"`
Path string `provider:"path,omitempty"`
URL string `provider:"url,omitempty"`
Proxy string `provider:"proxy,omitempty"`
Format string `provider:"format,omitempty"`
Interval int `provider:"interval,omitempty"`
}
//type proxyProviderSchema struct {
// Type string `provider:"type"`
// Path string `provider:"path,omitempty"`
// URL string `provider:"url,omitempty"`
// Proxy string `provider:"proxy,omitempty"`
// Interval int `provider:"interval,omitempty"`
// Filter string `provider:"filter,omitempty"`
// ExcludeFilter string `provider:"exclude-filter,omitempty"`
// ExcludeType string `provider:"exclude-type,omitempty"`
// DialerProxy string `provider:"dialer-proxy,omitempty"`
//
// HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
// Override ap.OverrideSchema `provider:"override,omitempty"`
// Header map[string][]string `provider:"header,omitempty"`
//}
//
//type ruleProviderSchema struct {
// Type string `provider:"type"`
// Behavior string `provider:"behavior"`
// Path string `provider:"path,omitempty"`
// URL string `provider:"url,omitempty"`
// Proxy string `provider:"proxy,omitempty"`
// Format string `provider:"format,omitempty"`
// Interval int `provider:"interval,omitempty"`
//}
type ConfigExtendedParams struct {
IsPatch bool `json:"is-patch"`
@@ -69,9 +73,9 @@ type ConfigExtendedParams struct {
}
type GenerateConfigParams struct {
ProfilePath *string `json:"profile-path"`
Config config.RawConfig `json:"config" `
Params ConfigExtendedParams `json:"params"`
ProfileId string `json:"profile-id"`
Config config.RawConfig `json:"config" `
Params ConfigExtendedParams `json:"params"`
}
type ChangeProxyParams struct {
@@ -93,9 +97,13 @@ type ExternalProvider struct {
Name string `json:"name"`
Type string `json:"type"`
VehicleType string `json:"vehicle-type"`
Count int `json:"count"`
Path string `json:"path"`
UpdateAt time.Time `json:"update-at"`
}
var b, _ = batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](50))
func restartExecutable(execPath string) {
var err error
executor.Shutdown()
@@ -145,26 +153,76 @@ func removeFile(path string) error {
return nil
}
func getRawConfigWithPath(path *string) *config.RawConfig {
if path == nil {
return config.DefaultRawConfig()
} else {
bytes, err := readFile(*path)
if err != nil {
log.Errorln("getProfile readFile error %v", err)
return config.DefaultRawConfig()
}
prof, err := config.UnmarshalRawConfig(bytes)
if err != nil {
log.Errorln("getProfile UnmarshalRawConfig error %v", err)
return config.DefaultRawConfig()
}
return prof
}
func getProfilePath(id string) string {
return filepath.Join(constant.Path.HomeDir(), "profiles", id+".yaml")
}
func decorationConfig(profilePath *string, cfg config.RawConfig) *config.RawConfig {
prof := getRawConfigWithPath(profilePath)
func getProfileProvidersPath(id string) string {
return filepath.Join(constant.Path.HomeDir(), "providers", id)
}
func getRawConfigWithId(id string) *config.RawConfig {
path := getProfilePath(id)
bytes, err := readFile(path)
if err != nil {
log.Errorln("profile is not exist")
return config.DefaultRawConfig()
}
prof, err := config.UnmarshalRawConfig(bytes)
if err != nil {
log.Errorln("unmarshalRawConfig error %v", err)
return config.DefaultRawConfig()
}
for _, mapping := range prof.ProxyProvider {
value, exist := mapping["path"].(string)
if !exist {
continue
}
mapping["path"] = filepath.Join(getProfileProvidersPath(id), value)
}
for _, mapping := range prof.RuleProvider {
value, exist := mapping["path"].(string)
if !exist {
continue
}
mapping["path"] = filepath.Join(getProfileProvidersPath(id), value)
}
return prof
}
func getExternalProvidersRaw() map[string]ExternalProvider {
externalProviders := make(map[string]ExternalProvider)
for n, p := range tunnel.Providers() {
if p.VehicleType() != cp.Compatible {
p := p.(*provider.ProxySetProvider)
externalProviders[n] = ExternalProvider{
Name: n,
Type: p.Type().String(),
VehicleType: p.VehicleType().String(),
Count: p.Count(),
Path: p.Vehicle().Path(),
UpdateAt: p.UpdatedAt,
}
}
}
for n, p := range tunnel.RuleProviders() {
if p.VehicleType() != cp.Compatible {
p := p.(*rp.RuleSetProvider)
externalProviders[n] = ExternalProvider{
Name: n,
Type: p.Type().String(),
VehicleType: p.VehicleType().String(),
Count: p.Count(),
Path: p.Vehicle().Path(),
UpdateAt: p.UpdatedAt,
}
}
}
return externalProviders
}
func decorationConfig(profileId string, cfg config.RawConfig) *config.RawConfig {
prof := getRawConfigWithId(profileId)
overwriteConfig(prof, cfg)
return prof
}
@@ -327,6 +385,7 @@ func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfi
targetConfig.LogLevel = patchConfig.LogLevel
targetConfig.Port = 0
targetConfig.SocksPort = 0
targetConfig.KeepAliveInterval = patchConfig.KeepAliveInterval
targetConfig.MixedPort = patchConfig.MixedPort
targetConfig.FindProcessMode = patchConfig.FindProcessMode
targetConfig.AllowLan = patchConfig.AllowLan

View File

@@ -11,7 +11,6 @@ import (
"github.com/metacubex/mihomo/adapter"
"github.com/metacubex/mihomo/adapter/outboundgroup"
"github.com/metacubex/mihomo/adapter/provider"
"github.com/metacubex/mihomo/common/structure"
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/updater"
"github.com/metacubex/mihomo/config"
@@ -35,8 +34,6 @@ var configParams = ConfigExtendedParams{}
var isInit = false
var currentProfileName = ""
//export initClash
func initClash(homeDirStr *C.char) bool {
if !isInit {
@@ -75,16 +72,6 @@ func forceGc() {
}()
}
//export setCurrentProfileName
func setCurrentProfileName(s *C.char) {
currentProfileName = C.GoString(s)
}
//export getCurrentProfileName
func getCurrentProfileName() *C.char {
return C.CString(currentProfileName)
}
//export validateConfig
func validateConfig(s *C.char, port C.longlong) {
i := int64(port)
@@ -111,7 +98,7 @@ func updateConfig(s *C.char, port C.longlong) {
return
}
configParams = params.Params
prof := decorationConfig(params.ProfilePath, params.Config)
prof := decorationConfig(params.ProfileId, params.Config)
currentConfig = prof
err = applyConfig()
if err != nil {
@@ -124,34 +111,10 @@ func updateConfig(s *C.char, port C.longlong) {
//export clearEffect
func clearEffect(s *C.char) {
path := C.GoString(s)
id := C.GoString(s)
go func() {
rawCfg := getRawConfigWithPath(&path)
for _, mapping := range rawCfg.RuleProvider {
schema := &ruleProviderSchema{}
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
if err := decoder.Decode(mapping, schema); err != nil {
return
}
if schema.Type == "http" {
_ = removeFile(constant.Path.Resolve(schema.Path))
}
}
for _, mapping := range rawCfg.ProxyProvider {
schema := &proxyProviderSchema{
HealthCheck: healthCheckSchema{
Lazy: true,
},
}
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
if err := decoder.Decode(mapping, schema); err != nil {
return
}
if schema.Type == "http" {
_ = removeFile(constant.Path.Resolve(schema.Path))
}
}
_ = removeFile(path)
_ = removeFile(getProfilePath(id))
_ = removeFile(getProfileProvidersPath(id))
}()
}
@@ -184,10 +147,13 @@ func changeProxy(s *C.char) {
if !ok {
return
}
err = selector.Set(proxyName)
if proxyName == "" {
selector.ForceSet(proxyName)
} else {
err = selector.Set(proxyName)
}
if err == nil {
log.Infoln("[Selector] %s selected %s", groupName, proxyName)
log.Infoln("[SelectAble] %s selected %s", groupName, proxyName)
}
}
@@ -230,16 +196,16 @@ func resetTraffic() {
func asyncTestDelay(s *C.char, port C.longlong) {
i := int64(port)
paramsString := C.GoString(s)
go func() {
b.Go(paramsString, func() (bool, error) {
var params = &TestDelayParams{}
err := json.Unmarshal([]byte(paramsString), params)
if err != nil {
return
return false, nil
}
expectedStatus, err := utils.NewUnsignedRanges[uint16]("")
if err != nil {
return
return false, nil
}
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(params.Timeout))
@@ -256,7 +222,7 @@ func asyncTestDelay(s *C.char, port C.longlong) {
delayData.Value = -1
data, _ := json.Marshal(delayData)
bridge.SendToPort(i, string(data))
return
return false, nil
}
delay, err := proxy.URLTest(ctx, constant.DefaultTestURL, expectedStatus)
@@ -264,14 +230,14 @@ func asyncTestDelay(s *C.char, port C.longlong) {
delayData.Value = -1
data, _ := json.Marshal(delayData)
bridge.SendToPort(i, string(data))
return
return false, nil
}
delayData.Value = int32(delay)
data, _ := json.Marshal(delayData)
bridge.SendToPort(i, string(data))
return
}()
return false, nil
})
}
//export getVersionInfo
@@ -345,28 +311,31 @@ func getProvider(name *C.char) *C.char {
//export getExternalProviders
func getExternalProviders() *C.char {
externalProviders := make([]ExternalProvider, 0)
providers := tunnel.Providers()
for n, p := range providers {
externalProviders := make(map[string]ExternalProvider)
for n, p := range tunnel.Providers() {
if p.VehicleType() != cp.Compatible {
p := p.(*provider.ProxySetProvider)
externalProviders = append(externalProviders, ExternalProvider{
externalProviders[n] = ExternalProvider{
Name: n,
Type: p.Type().String(),
VehicleType: p.VehicleType().String(),
Count: p.Count(),
Path: p.Vehicle().Path(),
UpdateAt: p.UpdatedAt,
})
}
}
}
for n, p := range tunnel.RuleProviders() {
if p.VehicleType() != cp.Compatible {
p := p.(*rp.RuleSetProvider)
externalProviders = append(externalProviders, ExternalProvider{
externalProviders[n] = ExternalProvider{
Name: n,
Type: p.Type().String(),
VehicleType: p.VehicleType().String(),
Count: p.Count(),
Path: p.Vehicle().Path(),
UpdateAt: p.UpdatedAt,
})
}
}
}
data, err := json.Marshal(externalProviders)
@@ -376,6 +345,21 @@ func getExternalProviders() *C.char {
return C.CString(string(data))
}
//export getExternalProvider
func getExternalProvider(name *C.char) *C.char {
externalProviderName := C.GoString(name)
externalProviders := getExternalProvidersRaw()
externalProvider, exist := externalProviders[externalProviderName]
if !exist {
return C.CString("")
}
data, err := json.Marshal(externalProvider)
if err != nil {
return C.CString("")
}
return C.CString(string(data))
}
//export updateExternalProvider
func updateExternalProvider(providerName *C.char, providerType *C.char, port C.longlong) {
i := int64(port)
@@ -385,14 +369,24 @@ func updateExternalProvider(providerName *C.char, providerType *C.char, port C.l
switch providerTypeString {
case "Proxy":
providers := tunnel.Providers()
err := providers[providerNameString].Update()
proxyProvider, exist := providers[providerNameString].(*provider.ProxySetProvider)
if !exist {
bridge.SendToPort(i, "proxy provider is not exist")
return
}
err := proxyProvider.Update()
if err != nil {
bridge.SendToPort(i, err.Error())
return
}
case "Rule":
providers := tunnel.RuleProviders()
err := providers[providerNameString].Update()
ruleProvider, exist := providers[providerNameString].(*rp.RuleSetProvider)
if !exist {
bridge.SendToPort(i, "rule provider is not exist")
return
}
err := ruleProvider.Update()
if err != nil {
bridge.SendToPort(i, err.Error())
return
@@ -426,6 +420,66 @@ func updateExternalProvider(providerName *C.char, providerType *C.char, port C.l
}()
}
//func sideLoadExternalProvider(providerName *C.char, providerType *C.char, data *C.char, port C.longlong) {
// i := int64(port)
// bytes := []byte(C.GoString(data))
// providerNameString := C.GoString(providerName)
// providerTypeString := C.GoString(providerType)
// go func() {
// switch providerTypeString {
// case "Proxy":
// providers := tunnel.Providers()
// proxyProvider, exist := providers[providerNameString].(*provider.ProxySetProvider)
// if exist {
// bridge.SendToPort(i, "proxy provider is not exist")
// return
// }
// err := proxyProvider.Update()
// if err != nil {
// bridge.SendToPort(i, err.Error())
// return
// }
// case "Rule":
// providers := tunnel.RuleProviders()
// ruleProvider, exist := providers[providerNameString].(*rp.RuleSetProvider)
// if exist {
// bridge.SendToPort(i, "proxy provider is not exist")
// return
// }
// err := ruleProvider.Update()
// if err != nil {
// bridge.SendToPort(i, err.Error())
// return
// }
// case "MMDB":
// err := updater.UpdateMMDB(constant.Path.Resolve(providerNameString))
// if err != nil {
// bridge.SendToPort(i, err.Error())
// return
// }
// case "ASN":
// err := updater.UpdateASN(constant.Path.Resolve(providerNameString))
// if err != nil {
// bridge.SendToPort(i, err.Error())
// return
// }
// case "GeoIp":
// err := updater.UpdateGeoIp(constant.Path.Resolve(providerNameString))
// if err != nil {
// bridge.SendToPort(i, err.Error())
// return
// }
// case "GeoSite":
// err := updater.UpdateGeoSite(constant.Path.Resolve(providerNameString))
// if err != nil {
// bridge.SendToPort(i, err.Error())
// return
// }
// }
// bridge.SendToPort(i, "")
// }()
//}
//export initNativeApiBridge
func initNativeApiBridge(api unsafe.Pointer) {
bridge.InitDartApi(api)
@@ -463,7 +517,7 @@ func init() {
Data: c,
})
}
executor.DefaultProxyProviderLoadedHook = func(providerName string) {
executor.DefaultProviderLoadedHook = func(providerName string) {
SendMessage(Message{
Type: LoadedMessage,
Data: providerName,

View File

@@ -21,8 +21,9 @@ type AndroidProps struct {
type State struct {
AndroidProps
MixedPort int `json:"mixedPort"`
OnlyProxy bool `json:"onlyProxy"`
CurrentProfileName string `json:"currentProfileName"`
MixedPort int `json:"mixedPort"`
OnlyProxy bool `json:"onlyProxy"`
}
var state State