hub.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. package main
  2. /*
  3. #include <stdlib.h>
  4. */
  5. import "C"
  6. import (
  7. bridge "core/dart-bridge"
  8. "encoding/json"
  9. "fmt"
  10. "os"
  11. "runtime"
  12. "sort"
  13. "sync"
  14. "time"
  15. "unsafe"
  16. "github.com/metacubex/mihomo/adapter"
  17. "github.com/metacubex/mihomo/adapter/outboundgroup"
  18. "github.com/metacubex/mihomo/adapter/provider"
  19. "github.com/metacubex/mihomo/common/utils"
  20. "github.com/metacubex/mihomo/component/updater"
  21. "github.com/metacubex/mihomo/config"
  22. "github.com/metacubex/mihomo/constant"
  23. cp "github.com/metacubex/mihomo/constant/provider"
  24. "github.com/metacubex/mihomo/hub/executor"
  25. "github.com/metacubex/mihomo/log"
  26. "github.com/metacubex/mihomo/tunnel"
  27. "github.com/metacubex/mihomo/tunnel/statistic"
  28. "golang.org/x/net/context"
  29. )
  30. var currentRawConfig = config.DefaultRawConfig()
  31. var configParams = ConfigExtendedParams{}
  32. var externalProviders = map[string]cp.Provider{}
  33. var isInit = false
  34. //export start
  35. func start() {
  36. runLock.Lock()
  37. defer runLock.Unlock()
  38. isRunning = true
  39. }
  40. //export stop
  41. func stop() {
  42. runLock.Lock()
  43. defer runLock.Unlock()
  44. isRunning = false
  45. stopListeners()
  46. }
  47. //export initClash
  48. func initClash(homeDirStr *C.char) bool {
  49. if !isInit {
  50. constant.SetHomeDir(C.GoString(homeDirStr))
  51. isInit = true
  52. }
  53. return isInit
  54. }
  55. //export getIsInit
  56. func getIsInit() bool {
  57. return isInit
  58. }
  59. //export restartClash
  60. func restartClash() bool {
  61. execPath, _ := os.Executable()
  62. go restartExecutable(execPath)
  63. return true
  64. }
  65. //export shutdownClash
  66. func shutdownClash() bool {
  67. stopListeners()
  68. executor.Shutdown()
  69. runtime.GC()
  70. isInit = false
  71. return true
  72. }
  73. //export forceGc
  74. func forceGc() {
  75. go func() {
  76. log.Infoln("[APP] request force GC")
  77. runtime.GC()
  78. }()
  79. }
  80. //export validateConfig
  81. func validateConfig(s *C.char, port C.longlong) {
  82. i := int64(port)
  83. bytes := []byte(C.GoString(s))
  84. go func() {
  85. _, err := config.UnmarshalRawConfig(bytes)
  86. if err != nil {
  87. bridge.SendToPort(i, err.Error())
  88. return
  89. }
  90. bridge.SendToPort(i, "")
  91. }()
  92. }
  93. var updateLock sync.Mutex
  94. //export updateConfig
  95. func updateConfig(s *C.char, port C.longlong) {
  96. i := int64(port)
  97. paramsString := C.GoString(s)
  98. go func() {
  99. updateLock.Lock()
  100. defer updateLock.Unlock()
  101. var params = &GenerateConfigParams{}
  102. err := json.Unmarshal([]byte(paramsString), params)
  103. if err != nil {
  104. bridge.SendToPort(i, err.Error())
  105. return
  106. }
  107. configParams = params.Params
  108. prof := decorationConfig(params.ProfileId, params.Config)
  109. currentRawConfig = prof
  110. err = applyConfig()
  111. if err != nil {
  112. bridge.SendToPort(i, err.Error())
  113. return
  114. }
  115. bridge.SendToPort(i, "")
  116. }()
  117. }
  118. //export clearEffect
  119. func clearEffect(s *C.char) {
  120. id := C.GoString(s)
  121. go func() {
  122. _ = removeFile(getProfilePath(id))
  123. _ = removeFile(getProfileProvidersPath(id))
  124. }()
  125. }
  126. //export getProxies
  127. func getProxies() *C.char {
  128. data, err := json.Marshal(tunnel.ProxiesWithProviders())
  129. if err != nil {
  130. return C.CString("")
  131. }
  132. return C.CString(string(data))
  133. }
  134. //export changeProxy
  135. func changeProxy(s *C.char) {
  136. paramsString := C.GoString(s)
  137. var params = &ChangeProxyParams{}
  138. err := json.Unmarshal([]byte(paramsString), params)
  139. if err != nil {
  140. log.Infoln("Unmarshal ChangeProxyParams %v", err)
  141. }
  142. groupName := *params.GroupName
  143. proxyName := *params.ProxyName
  144. proxies := tunnel.ProxiesWithProviders()
  145. group, ok := proxies[groupName]
  146. if !ok {
  147. return
  148. }
  149. adapterProxy := group.(*adapter.Proxy)
  150. selector, ok := adapterProxy.ProxyAdapter.(outboundgroup.SelectAble)
  151. if !ok {
  152. return
  153. }
  154. if proxyName == "" {
  155. selector.ForceSet(proxyName)
  156. } else {
  157. err = selector.Set(proxyName)
  158. }
  159. if err == nil {
  160. log.Infoln("[SelectAble] %s selected %s", groupName, proxyName)
  161. }
  162. }
  163. //export getTraffic
  164. func getTraffic() *C.char {
  165. up, down := statistic.DefaultManager.Current(state.OnlyProxy)
  166. traffic := map[string]int64{
  167. "up": up,
  168. "down": down,
  169. }
  170. data, err := json.Marshal(traffic)
  171. if err != nil {
  172. fmt.Println("Error:", err)
  173. return C.CString("")
  174. }
  175. return C.CString(string(data))
  176. }
  177. //export getTotalTraffic
  178. func getTotalTraffic() *C.char {
  179. up, down := statistic.DefaultManager.Total(state.OnlyProxy)
  180. traffic := map[string]int64{
  181. "up": up,
  182. "down": down,
  183. }
  184. data, err := json.Marshal(traffic)
  185. if err != nil {
  186. fmt.Println("Error:", err)
  187. return C.CString("")
  188. }
  189. return C.CString(string(data))
  190. }
  191. //export resetTraffic
  192. func resetTraffic() {
  193. statistic.DefaultManager.ResetStatistic()
  194. }
  195. //export asyncTestDelay
  196. func asyncTestDelay(s *C.char, port C.longlong) {
  197. i := int64(port)
  198. paramsString := C.GoString(s)
  199. b.Go(paramsString, func() (bool, error) {
  200. var params = &TestDelayParams{}
  201. err := json.Unmarshal([]byte(paramsString), params)
  202. if err != nil {
  203. return false, nil
  204. }
  205. expectedStatus, err := utils.NewUnsignedRanges[uint16]("")
  206. if err != nil {
  207. return false, nil
  208. }
  209. ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(params.Timeout))
  210. defer cancel()
  211. proxies := tunnel.ProxiesWithProviders()
  212. proxy := proxies[params.ProxyName]
  213. delayData := &Delay{
  214. Name: params.ProxyName,
  215. }
  216. if proxy == nil {
  217. delayData.Value = -1
  218. data, _ := json.Marshal(delayData)
  219. bridge.SendToPort(i, string(data))
  220. return false, nil
  221. }
  222. delay, err := proxy.URLTest(ctx, constant.DefaultTestURL, expectedStatus)
  223. if err != nil || delay == 0 {
  224. delayData.Value = -1
  225. data, _ := json.Marshal(delayData)
  226. bridge.SendToPort(i, string(data))
  227. return false, nil
  228. }
  229. delayData.Value = int32(delay)
  230. data, _ := json.Marshal(delayData)
  231. bridge.SendToPort(i, string(data))
  232. return false, nil
  233. })
  234. }
  235. //export getVersionInfo
  236. func getVersionInfo() *C.char {
  237. versionInfo := map[string]string{
  238. "clashName": constant.Name,
  239. "version": "1.18.5",
  240. }
  241. data, err := json.Marshal(versionInfo)
  242. if err != nil {
  243. fmt.Println("Error:", err)
  244. return C.CString("")
  245. }
  246. return C.CString(string(data))
  247. }
  248. //export getConnections
  249. func getConnections() *C.char {
  250. snapshot := statistic.DefaultManager.Snapshot()
  251. data, err := json.Marshal(snapshot)
  252. if err != nil {
  253. fmt.Println("Error:", err)
  254. return C.CString("")
  255. }
  256. return C.CString(string(data))
  257. }
  258. //export closeConnections
  259. func closeConnections() {
  260. statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
  261. err := c.Close()
  262. if err != nil {
  263. return false
  264. }
  265. return true
  266. })
  267. }
  268. //export closeConnection
  269. func closeConnection(id *C.char) {
  270. connectionId := C.GoString(id)
  271. c := statistic.DefaultManager.Get(connectionId)
  272. if c == nil {
  273. return
  274. }
  275. _ = c.Close()
  276. }
  277. //export getProviders
  278. func getProviders() *C.char {
  279. data, err := json.Marshal(tunnel.Providers())
  280. var msg *C.char
  281. if err != nil {
  282. msg = C.CString("")
  283. return msg
  284. }
  285. msg = C.CString(string(data))
  286. return msg
  287. }
  288. //export getProvider
  289. func getProvider(name *C.char) *C.char {
  290. providerName := C.GoString(name)
  291. providers := tunnel.Providers()
  292. data, err := json.Marshal(providers[providerName])
  293. if err != nil {
  294. return C.CString("")
  295. }
  296. return C.CString(string(data))
  297. }
  298. //export getExternalProviders
  299. func getExternalProviders() *C.char {
  300. eps := make([]ExternalProvider, 0)
  301. for _, p := range externalProviders {
  302. externalProvider, err := toExternalProvider(p)
  303. if err != nil {
  304. continue
  305. }
  306. eps = append(eps, *externalProvider)
  307. }
  308. sort.Sort(ExternalProviders(eps))
  309. data, err := json.Marshal(eps)
  310. if err != nil {
  311. return C.CString("")
  312. }
  313. return C.CString(string(data))
  314. }
  315. //export getExternalProvider
  316. func getExternalProvider(name *C.char) *C.char {
  317. externalProviderName := C.GoString(name)
  318. externalProvider, exist := externalProviders[externalProviderName]
  319. if !exist {
  320. return C.CString("")
  321. }
  322. e, err := toExternalProvider(externalProvider)
  323. if err != nil {
  324. return C.CString("")
  325. }
  326. data, err := json.Marshal(e)
  327. if err != nil {
  328. return C.CString("")
  329. }
  330. return C.CString(string(data))
  331. }
  332. //export updateGeoData
  333. func updateGeoData(geoType *C.char, geoName *C.char, port C.longlong) {
  334. i := int64(port)
  335. geoTypeString := C.GoString(geoType)
  336. geoNameString := C.GoString(geoName)
  337. go func() {
  338. switch geoTypeString {
  339. case "MMDB":
  340. err := updater.UpdateMMDB(constant.Path.Resolve(geoNameString))
  341. if err != nil {
  342. bridge.SendToPort(i, err.Error())
  343. return
  344. }
  345. case "ASN":
  346. err := updater.UpdateASN(constant.Path.Resolve(geoNameString))
  347. if err != nil {
  348. bridge.SendToPort(i, err.Error())
  349. return
  350. }
  351. case "GeoIp":
  352. err := updater.UpdateGeoIp(constant.Path.Resolve(geoNameString))
  353. if err != nil {
  354. bridge.SendToPort(i, err.Error())
  355. return
  356. }
  357. case "GeoSite":
  358. err := updater.UpdateGeoSite(constant.Path.Resolve(geoNameString))
  359. if err != nil {
  360. bridge.SendToPort(i, err.Error())
  361. return
  362. }
  363. }
  364. bridge.SendToPort(i, "")
  365. }()
  366. }
  367. //export updateExternalProvider
  368. func updateExternalProvider(providerName *C.char, port C.longlong) {
  369. i := int64(port)
  370. providerNameString := C.GoString(providerName)
  371. go func() {
  372. externalProvider, exist := externalProviders[providerNameString]
  373. if !exist {
  374. bridge.SendToPort(i, "external provider is not exist")
  375. return
  376. }
  377. err := externalProvider.Update()
  378. if err != nil {
  379. bridge.SendToPort(i, err.Error())
  380. return
  381. }
  382. bridge.SendToPort(i, "")
  383. }()
  384. }
  385. //export sideLoadExternalProvider
  386. func sideLoadExternalProvider(providerName *C.char, data *C.char, port C.longlong) {
  387. i := int64(port)
  388. bytes := []byte(C.GoString(data))
  389. providerNameString := C.GoString(providerName)
  390. go func() {
  391. externalProvider, exist := externalProviders[providerNameString]
  392. if !exist {
  393. bridge.SendToPort(i, "external provider is not exist")
  394. return
  395. }
  396. err := sideUpdateExternalProvider(externalProvider, bytes)
  397. if err != nil {
  398. bridge.SendToPort(i, err.Error())
  399. return
  400. }
  401. bridge.SendToPort(i, "")
  402. }()
  403. }
  404. //export initNativeApiBridge
  405. func initNativeApiBridge(api unsafe.Pointer) {
  406. bridge.InitDartApi(api)
  407. }
  408. //export initMessage
  409. func initMessage(port C.longlong) {
  410. i := int64(port)
  411. Port = i
  412. }
  413. //export freeCString
  414. func freeCString(s *C.char) {
  415. C.free(unsafe.Pointer(s))
  416. }
  417. func init() {
  418. provider.HealthcheckHook = func(name string, delay uint16) {
  419. delayData := &Delay{
  420. Name: name,
  421. }
  422. if delay == 0 {
  423. delayData.Value = -1
  424. } else {
  425. delayData.Value = int32(delay)
  426. }
  427. SendMessage(Message{
  428. Type: DelayMessage,
  429. Data: delayData,
  430. })
  431. }
  432. statistic.DefaultRequestNotify = func(c statistic.Tracker) {
  433. SendMessage(Message{
  434. Type: RequestMessage,
  435. Data: c,
  436. })
  437. }
  438. executor.DefaultProviderLoadedHook = func(providerName string) {
  439. SendMessage(Message{
  440. Type: LoadedMessage,
  441. Data: providerName,
  442. })
  443. }
  444. }