123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- package main
- /*
- #include <stdlib.h>
- */
- import "C"
- import (
- bridge "core/dart-bridge"
- "encoding/json"
- "fmt"
- "os"
- "runtime"
- "sort"
- "sync"
- "time"
- "unsafe"
- "github.com/metacubex/mihomo/adapter"
- "github.com/metacubex/mihomo/adapter/outboundgroup"
- "github.com/metacubex/mihomo/adapter/provider"
- "github.com/metacubex/mihomo/common/utils"
- "github.com/metacubex/mihomo/component/updater"
- "github.com/metacubex/mihomo/config"
- "github.com/metacubex/mihomo/constant"
- cp "github.com/metacubex/mihomo/constant/provider"
- "github.com/metacubex/mihomo/hub/executor"
- "github.com/metacubex/mihomo/log"
- "github.com/metacubex/mihomo/tunnel"
- "github.com/metacubex/mihomo/tunnel/statistic"
- "golang.org/x/net/context"
- )
- var currentRawConfig = config.DefaultRawConfig()
- var configParams = ConfigExtendedParams{}
- var externalProviders = map[string]cp.Provider{}
- var isInit = false
- //export start
- func start() {
- runLock.Lock()
- defer runLock.Unlock()
- isRunning = true
- }
- //export stop
- func stop() {
- runLock.Lock()
- defer runLock.Unlock()
- isRunning = false
- stopListeners()
- }
- //export initClash
- func initClash(homeDirStr *C.char) bool {
- if !isInit {
- constant.SetHomeDir(C.GoString(homeDirStr))
- isInit = true
- }
- return isInit
- }
- //export getIsInit
- func getIsInit() bool {
- return isInit
- }
- //export restartClash
- func restartClash() bool {
- execPath, _ := os.Executable()
- go restartExecutable(execPath)
- return true
- }
- //export shutdownClash
- func shutdownClash() bool {
- stopListeners()
- executor.Shutdown()
- runtime.GC()
- isInit = false
- return true
- }
- //export forceGc
- func forceGc() {
- go func() {
- log.Infoln("[APP] request force GC")
- runtime.GC()
- }()
- }
- //export validateConfig
- func validateConfig(s *C.char, port C.longlong) {
- i := int64(port)
- bytes := []byte(C.GoString(s))
- go func() {
- _, err := config.UnmarshalRawConfig(bytes)
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- bridge.SendToPort(i, "")
- }()
- }
- var updateLock sync.Mutex
- //export updateConfig
- func updateConfig(s *C.char, port C.longlong) {
- i := int64(port)
- paramsString := C.GoString(s)
- go func() {
- updateLock.Lock()
- defer updateLock.Unlock()
- var params = &GenerateConfigParams{}
- err := json.Unmarshal([]byte(paramsString), params)
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- configParams = params.Params
- prof := decorationConfig(params.ProfileId, params.Config)
- currentRawConfig = prof
- err = applyConfig()
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- bridge.SendToPort(i, "")
- }()
- }
- //export clearEffect
- func clearEffect(s *C.char) {
- id := C.GoString(s)
- go func() {
- _ = removeFile(getProfilePath(id))
- _ = removeFile(getProfileProvidersPath(id))
- }()
- }
- //export getProxies
- func getProxies() *C.char {
- data, err := json.Marshal(tunnel.ProxiesWithProviders())
- if err != nil {
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export changeProxy
- func changeProxy(s *C.char) {
- paramsString := C.GoString(s)
- var params = &ChangeProxyParams{}
- err := json.Unmarshal([]byte(paramsString), params)
- if err != nil {
- log.Infoln("Unmarshal ChangeProxyParams %v", err)
- }
- groupName := *params.GroupName
- proxyName := *params.ProxyName
- proxies := tunnel.ProxiesWithProviders()
- group, ok := proxies[groupName]
- if !ok {
- return
- }
- adapterProxy := group.(*adapter.Proxy)
- selector, ok := adapterProxy.ProxyAdapter.(outboundgroup.SelectAble)
- if !ok {
- return
- }
- if proxyName == "" {
- selector.ForceSet(proxyName)
- } else {
- err = selector.Set(proxyName)
- }
- if err == nil {
- log.Infoln("[SelectAble] %s selected %s", groupName, proxyName)
- }
- }
- //export getTraffic
- func getTraffic() *C.char {
- up, down := statistic.DefaultManager.Current(state.OnlyProxy)
- traffic := map[string]int64{
- "up": up,
- "down": down,
- }
- data, err := json.Marshal(traffic)
- if err != nil {
- fmt.Println("Error:", err)
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export getTotalTraffic
- func getTotalTraffic() *C.char {
- up, down := statistic.DefaultManager.Total(state.OnlyProxy)
- traffic := map[string]int64{
- "up": up,
- "down": down,
- }
- data, err := json.Marshal(traffic)
- if err != nil {
- fmt.Println("Error:", err)
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export resetTraffic
- func resetTraffic() {
- statistic.DefaultManager.ResetStatistic()
- }
- //export asyncTestDelay
- func asyncTestDelay(s *C.char, port C.longlong) {
- i := int64(port)
- paramsString := C.GoString(s)
- b.Go(paramsString, func() (bool, error) {
- var params = &TestDelayParams{}
- err := json.Unmarshal([]byte(paramsString), params)
- if err != nil {
- return false, nil
- }
- expectedStatus, err := utils.NewUnsignedRanges[uint16]("")
- if err != nil {
- return false, nil
- }
- ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(params.Timeout))
- defer cancel()
- proxies := tunnel.ProxiesWithProviders()
- proxy := proxies[params.ProxyName]
- delayData := &Delay{
- Name: params.ProxyName,
- }
- if proxy == nil {
- delayData.Value = -1
- data, _ := json.Marshal(delayData)
- bridge.SendToPort(i, string(data))
- return false, nil
- }
- delay, err := proxy.URLTest(ctx, constant.DefaultTestURL, expectedStatus)
- if err != nil || delay == 0 {
- delayData.Value = -1
- data, _ := json.Marshal(delayData)
- bridge.SendToPort(i, string(data))
- return false, nil
- }
- delayData.Value = int32(delay)
- data, _ := json.Marshal(delayData)
- bridge.SendToPort(i, string(data))
- return false, nil
- })
- }
- //export getVersionInfo
- func getVersionInfo() *C.char {
- versionInfo := map[string]string{
- "clashName": constant.Name,
- "version": "1.18.5",
- }
- data, err := json.Marshal(versionInfo)
- if err != nil {
- fmt.Println("Error:", err)
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export getConnections
- func getConnections() *C.char {
- snapshot := statistic.DefaultManager.Snapshot()
- data, err := json.Marshal(snapshot)
- if err != nil {
- fmt.Println("Error:", err)
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export closeConnections
- func closeConnections() {
- statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
- err := c.Close()
- if err != nil {
- return false
- }
- return true
- })
- }
- //export closeConnection
- func closeConnection(id *C.char) {
- connectionId := C.GoString(id)
- c := statistic.DefaultManager.Get(connectionId)
- if c == nil {
- return
- }
- _ = c.Close()
- }
- //export getProviders
- func getProviders() *C.char {
- data, err := json.Marshal(tunnel.Providers())
- var msg *C.char
- if err != nil {
- msg = C.CString("")
- return msg
- }
- msg = C.CString(string(data))
- return msg
- }
- //export getProvider
- func getProvider(name *C.char) *C.char {
- providerName := C.GoString(name)
- providers := tunnel.Providers()
- data, err := json.Marshal(providers[providerName])
- if err != nil {
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export getExternalProviders
- func getExternalProviders() *C.char {
- eps := make([]ExternalProvider, 0)
- for _, p := range externalProviders {
- externalProvider, err := toExternalProvider(p)
- if err != nil {
- continue
- }
- eps = append(eps, *externalProvider)
- }
- sort.Sort(ExternalProviders(eps))
- data, err := json.Marshal(eps)
- if err != nil {
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export getExternalProvider
- func getExternalProvider(name *C.char) *C.char {
- externalProviderName := C.GoString(name)
- externalProvider, exist := externalProviders[externalProviderName]
- if !exist {
- return C.CString("")
- }
- e, err := toExternalProvider(externalProvider)
- if err != nil {
- return C.CString("")
- }
- data, err := json.Marshal(e)
- if err != nil {
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export updateGeoData
- func updateGeoData(geoType *C.char, geoName *C.char, port C.longlong) {
- i := int64(port)
- geoTypeString := C.GoString(geoType)
- geoNameString := C.GoString(geoName)
- go func() {
- switch geoTypeString {
- case "MMDB":
- err := updater.UpdateMMDB(constant.Path.Resolve(geoNameString))
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- case "ASN":
- err := updater.UpdateASN(constant.Path.Resolve(geoNameString))
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- case "GeoIp":
- err := updater.UpdateGeoIp(constant.Path.Resolve(geoNameString))
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- case "GeoSite":
- err := updater.UpdateGeoSite(constant.Path.Resolve(geoNameString))
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- }
- bridge.SendToPort(i, "")
- }()
- }
- //export updateExternalProvider
- func updateExternalProvider(providerName *C.char, port C.longlong) {
- i := int64(port)
- providerNameString := C.GoString(providerName)
- go func() {
- externalProvider, exist := externalProviders[providerNameString]
- if !exist {
- bridge.SendToPort(i, "external provider is not exist")
- return
- }
- err := externalProvider.Update()
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- bridge.SendToPort(i, "")
- }()
- }
- //export sideLoadExternalProvider
- func sideLoadExternalProvider(providerName *C.char, data *C.char, port C.longlong) {
- i := int64(port)
- bytes := []byte(C.GoString(data))
- providerNameString := C.GoString(providerName)
- go func() {
- externalProvider, exist := externalProviders[providerNameString]
- if !exist {
- bridge.SendToPort(i, "external provider is not exist")
- return
- }
- err := sideUpdateExternalProvider(externalProvider, bytes)
- if err != nil {
- bridge.SendToPort(i, err.Error())
- return
- }
- bridge.SendToPort(i, "")
- }()
- }
- //export initNativeApiBridge
- func initNativeApiBridge(api unsafe.Pointer) {
- bridge.InitDartApi(api)
- }
- //export initMessage
- func initMessage(port C.longlong) {
- i := int64(port)
- Port = i
- }
- //export freeCString
- func freeCString(s *C.char) {
- C.free(unsafe.Pointer(s))
- }
- func init() {
- provider.HealthcheckHook = func(name string, delay uint16) {
- delayData := &Delay{
- Name: name,
- }
- if delay == 0 {
- delayData.Value = -1
- } else {
- delayData.Value = int32(delay)
- }
- SendMessage(Message{
- Type: DelayMessage,
- Data: delayData,
- })
- }
- statistic.DefaultRequestNotify = func(c statistic.Tracker) {
- SendMessage(Message{
- Type: RequestMessage,
- Data: c,
- })
- }
- executor.DefaultProviderLoadedHook = func(providerName string) {
- SendMessage(Message{
- Type: LoadedMessage,
- Data: providerName,
- })
- }
- }
|