lib.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. package main
  2. /*
  3. #include "stdint.h"
  4. */
  5. import "C"
  6. import (
  7. "context"
  8. "encoding/json"
  9. "fmt"
  10. "os"
  11. "strconv"
  12. "time"
  13. "unsafe"
  14. "github.com/Dreamacro/clash/adapter"
  15. "github.com/Dreamacro/clash/adapter/outboundgroup"
  16. "github.com/Dreamacro/clash/common/observable"
  17. "github.com/Dreamacro/clash/common/utils"
  18. "github.com/Dreamacro/clash/component/profile/cachefile"
  19. "github.com/Dreamacro/clash/component/resolver"
  20. "github.com/Dreamacro/clash/config"
  21. "github.com/Dreamacro/clash/constant"
  22. "github.com/Dreamacro/clash/hub"
  23. "github.com/Dreamacro/clash/hub/executor"
  24. P "github.com/Dreamacro/clash/listener"
  25. "github.com/Dreamacro/clash/log"
  26. "github.com/Dreamacro/clash/tunnel"
  27. "github.com/Dreamacro/clash/tunnel/statistic"
  28. fclashgobridge "github.com/kingtous/fclash-go-bridge"
  29. )
  30. var (
  31. options []hub.Option
  32. log_subscriber observable.Subscription[log.Event]
  33. )
  34. //export clash_init
  35. func clash_init(home_dir *C.char) int {
  36. home := C.GoString(home_dir)
  37. // constant.
  38. err := config.Init(home)
  39. if err != nil {
  40. return -1
  41. }
  42. return 0
  43. }
  44. //export set_config
  45. func set_config(config_path *C.char) int {
  46. file := C.GoString(config_path)
  47. if _, err := executor.ParseWithPath(file); err != nil {
  48. fmt.Println("config validate failed:", err)
  49. return -1
  50. }
  51. constant.SetConfig(file)
  52. return 0
  53. }
  54. //export set_home_dir
  55. func set_home_dir(home *C.char) int {
  56. home_gostr := C.GoString(home)
  57. info, err := os.Stat(home_gostr)
  58. if err == nil && info.IsDir() {
  59. fmt.Println("GO: set home dir to", home_gostr)
  60. constant.SetHomeDir(home_gostr)
  61. return 0
  62. } else {
  63. if err != nil {
  64. fmt.Println("error:", err)
  65. }
  66. }
  67. return -1
  68. }
  69. //export get_config
  70. func get_config() *C.char {
  71. return C.CString(constant.Path.Config())
  72. }
  73. //export set_ext_controller
  74. func set_ext_controller(port uint64) int {
  75. url := "127.0.0.1:" + strconv.FormatUint(port, 10)
  76. options = append(options, hub.WithExternalController(url))
  77. return 0
  78. }
  79. //export clear_ext_options
  80. func clear_ext_options() {
  81. options = options[:0]
  82. }
  83. //export is_config_valid
  84. func is_config_valid(config_path *C.char) int {
  85. if _, err := executor.ParseWithPath(C.GoString(config_path)); err != nil {
  86. fmt.Println("error reading config:", err)
  87. return -1
  88. }
  89. return 0
  90. }
  91. //export get_all_connections
  92. func get_all_connections() *C.char {
  93. snapshot := statistic.DefaultManager.Snapshot()
  94. data, err := json.Marshal(snapshot)
  95. if err != nil {
  96. fmt.Println("Error:", err)
  97. return C.CString("")
  98. }
  99. return C.CString(string(data))
  100. }
  101. //export close_all_connections
  102. func close_all_connections() {
  103. statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
  104. c.Close()
  105. return true
  106. })
  107. }
  108. //export close_connection
  109. func close_connection(id *C.char) bool {
  110. connection_id := C.GoString(id)
  111. statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
  112. if c.ID() == connection_id {
  113. c.Close()
  114. return false
  115. }
  116. return true
  117. })
  118. return false
  119. }
  120. //export parse_options
  121. func parse_options() bool {
  122. err := hub.Parse(options...)
  123. if err != nil {
  124. return true
  125. }
  126. return false
  127. }
  128. //export get_traffic
  129. func get_traffic() *C.char {
  130. up, down := statistic.DefaultManager.Now()
  131. traffic := map[string]int64{
  132. "Up": up,
  133. "Down": down,
  134. }
  135. data, err := json.Marshal(traffic)
  136. if err != nil {
  137. fmt.Println("Error:", err)
  138. return C.CString("")
  139. }
  140. return C.CString(string(data))
  141. }
  142. //export init_native_api_bridge
  143. func init_native_api_bridge(api unsafe.Pointer) {
  144. fclashgobridge.InitDartApi(api)
  145. }
  146. //export start_log
  147. func start_log(port C.longlong) {
  148. if log_subscriber != nil {
  149. log.UnSubscribe(log_subscriber)
  150. log_subscriber = nil
  151. }
  152. log_subscriber = log.Subscribe()
  153. go func() {
  154. for elem := range log_subscriber {
  155. lg := elem
  156. data, err := json.Marshal(lg)
  157. if err != nil {
  158. fmt.Println("Error:", err)
  159. }
  160. ret_str := string(data)
  161. fclashgobridge.SendToPort(int64(port), ret_str)
  162. }
  163. }()
  164. fmt.Println("[GO] subscribe logger on dart bridge port", int64(port))
  165. }
  166. //export stop_log
  167. func stop_log() {
  168. if log_subscriber != nil {
  169. log.UnSubscribe(log_subscriber)
  170. fmt.Println("Logger stopped")
  171. log_subscriber = nil
  172. }
  173. }
  174. //export change_proxy
  175. func change_proxy(selector_name *C.char, proxy_name *C.char) C.long {
  176. proxies := tunnel.Proxies()
  177. proxy := proxies[C.GoString(selector_name)]
  178. if proxy == nil {
  179. return C.long(-1)
  180. }
  181. adapter_proxy := proxy.(*adapter.Proxy)
  182. selector, ok := adapter_proxy.ProxyAdapter.(*outboundgroup.Selector)
  183. if !ok {
  184. // not selector
  185. return C.long(-1)
  186. }
  187. if err := selector.Set(C.GoString(proxy_name)); err != nil {
  188. fmt.Println("", err)
  189. return C.long(-1)
  190. }
  191. cachefile.Cache().SetSelected(string(C.GoString(selector_name)), string(C.GoString(proxy_name)))
  192. return C.long(0)
  193. }
  194. type configSchema struct {
  195. Port *int `json:"port"`
  196. SocksPort *int `json:"socks-port"`
  197. RedirPort *int `json:"redir-port"`
  198. TProxyPort *int `json:"tproxy-port"`
  199. MixedPort *int `json:"mixed-port"`
  200. AllowLan *bool `json:"allow-lan"`
  201. BindAddress *string `json:"bind-address"`
  202. Mode *tunnel.TunnelMode `json:"mode"`
  203. LogLevel *log.LogLevel `json:"log-level"`
  204. IPv6 *bool `json:"ipv6"`
  205. }
  206. func pointerOrDefault(p *int, def int) int {
  207. if p != nil {
  208. return *p
  209. }
  210. return def
  211. }
  212. //export change_config_field
  213. func change_config_field(s *C.char) C.long {
  214. // todo
  215. general := &configSchema{}
  216. json_str := C.GoString(s)
  217. if err := json.Unmarshal([]byte(json_str), general); err != nil {
  218. fmt.Println(err)
  219. return C.long(-1)
  220. }
  221. // copy from clash source code
  222. if general.AllowLan != nil {
  223. P.SetAllowLan(*general.AllowLan)
  224. }
  225. if general.BindAddress != nil {
  226. P.SetBindAddress(*general.BindAddress)
  227. }
  228. ports := P.GetPorts()
  229. ports.Port = pointerOrDefault(general.Port, ports.Port)
  230. ports.MixedPort = pointerOrDefault(general.MixedPort, ports.MixedPort)
  231. ports.SocksPort = pointerOrDefault(general.SocksPort, ports.SocksPort)
  232. ports.RedirPort = pointerOrDefault(general.RedirPort, ports.RedirPort)
  233. ports.TProxyPort = pointerOrDefault(general.TProxyPort, ports.TProxyPort)
  234. tcpIn := tunnel.TCPIn()
  235. udpIn := tunnel.UDPIn()
  236. natTable := tunnel.NatTable()
  237. // P.ReCreate(*ports, tcpIn, udpIn)
  238. P.ReCreateHTTP(ports.Port, tcpIn)
  239. P.ReCreateMixed(ports.Port, tcpIn, udpIn)
  240. P.ReCreateSocks(ports.SocksPort, tcpIn, udpIn)
  241. P.ReCreateRedir(ports.RedirPort, tcpIn, udpIn, natTable)
  242. P.ReCreateTProxy(ports.TProxyPort, tcpIn, udpIn, natTable)
  243. if general.Mode != nil {
  244. tunnel.SetMode(*general.Mode)
  245. }
  246. if general.LogLevel != nil {
  247. log.SetLevel(*general.LogLevel)
  248. }
  249. if general.IPv6 != nil {
  250. resolver.DisableIPv6 = !*general.IPv6
  251. }
  252. return C.long(0)
  253. }
  254. //export async_test_delay
  255. func async_test_delay(proxy_name *C.char, url *C.char, timeout C.long, port C.longlong) {
  256. go func() {
  257. ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(int64(timeout)))
  258. defer cancel()
  259. proxies := tunnel.Proxies()
  260. proxy := proxies[C.GoString(proxy_name)]
  261. if proxy == nil {
  262. data, err := json.Marshal(map[string]int64{
  263. "delay": -1,
  264. })
  265. if err != nil {
  266. return
  267. }
  268. fclashgobridge.SendToPort(int64(port), string(data))
  269. return
  270. }
  271. rg := make(utils.IntRanges[uint16], 1)
  272. rg[0] = utils.NewRange[uint16](200, 400)
  273. delay, err := proxy.URLTest(ctx, C.GoString(url), rg, constant.ExtraHistory)
  274. if err != nil || delay == 0 {
  275. data, err := json.Marshal(map[string]int64{
  276. "delay": -1,
  277. })
  278. if err != nil {
  279. return
  280. }
  281. fclashgobridge.SendToPort(int64(port), string(data))
  282. return
  283. }
  284. data, err := json.Marshal(map[string]uint16{
  285. "delay": delay,
  286. })
  287. if err != nil {
  288. fmt.Println("err: ", err)
  289. }
  290. fclashgobridge.SendToPort(int64(port), string(data))
  291. }()
  292. }
  293. //export get_proxies
  294. func get_proxies() *C.char {
  295. proxies := tunnel.Proxies()
  296. for _, provider := range tunnel.Providers() {
  297. for _, proxy := range provider.Proxies() {
  298. proxies[proxy.Name()] = proxy
  299. }
  300. }
  301. data, err := json.Marshal(map[string]map[string]constant.Proxy{
  302. "proxies": proxies,
  303. })
  304. if err != nil {
  305. return C.CString("")
  306. }
  307. return C.CString(string(data))
  308. }
  309. //export get_configs
  310. func get_configs() *C.char {
  311. general := executor.GetGeneral()
  312. data, err := json.Marshal(general)
  313. if err != nil {
  314. return C.CString("")
  315. }
  316. return C.CString(string(data))
  317. }
  318. func main() {
  319. fmt.Println("hello fclash")
  320. }