123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- package main
- /*
- #include "stdint.h"
- */
- import "C"
- import (
- "context"
- "encoding/json"
- "fmt"
- "os"
- "strconv"
- "time"
- "unsafe"
- "github.com/Dreamacro/clash/adapter"
- "github.com/Dreamacro/clash/adapter/outboundgroup"
- "github.com/Dreamacro/clash/common/observable"
- "github.com/Dreamacro/clash/common/utils"
- "github.com/Dreamacro/clash/component/profile/cachefile"
- "github.com/Dreamacro/clash/component/resolver"
- "github.com/Dreamacro/clash/config"
- "github.com/Dreamacro/clash/constant"
- "github.com/Dreamacro/clash/hub"
- "github.com/Dreamacro/clash/hub/executor"
- P "github.com/Dreamacro/clash/listener"
- "github.com/Dreamacro/clash/log"
- "github.com/Dreamacro/clash/tunnel"
- "github.com/Dreamacro/clash/tunnel/statistic"
- fclashgobridge "github.com/kingtous/fclash-go-bridge"
- )
- var (
- options []hub.Option
- log_subscriber observable.Subscription[log.Event]
- )
- //export clash_init
- func clash_init(home_dir *C.char) int {
- home := C.GoString(home_dir)
- // constant.
- err := config.Init(home)
- if err != nil {
- return -1
- }
- return 0
- }
- //export set_config
- func set_config(config_path *C.char) int {
- file := C.GoString(config_path)
- if _, err := executor.ParseWithPath(file); err != nil {
- fmt.Println("config validate failed:", err)
- return -1
- }
- constant.SetConfig(file)
- return 0
- }
- //export set_home_dir
- func set_home_dir(home *C.char) int {
- home_gostr := C.GoString(home)
- info, err := os.Stat(home_gostr)
- if err == nil && info.IsDir() {
- fmt.Println("GO: set home dir to", home_gostr)
- constant.SetHomeDir(home_gostr)
- return 0
- } else {
- if err != nil {
- fmt.Println("error:", err)
- }
- }
- return -1
- }
- //export get_config
- func get_config() *C.char {
- return C.CString(constant.Path.Config())
- }
- //export set_ext_controller
- func set_ext_controller(port uint64) int {
- url := "127.0.0.1:" + strconv.FormatUint(port, 10)
- options = append(options, hub.WithExternalController(url))
- return 0
- }
- //export clear_ext_options
- func clear_ext_options() {
- options = options[:0]
- }
- //export is_config_valid
- func is_config_valid(config_path *C.char) int {
- if _, err := executor.ParseWithPath(C.GoString(config_path)); err != nil {
- fmt.Println("error reading config:", err)
- return -1
- }
- return 0
- }
- //export get_all_connections
- func get_all_connections() *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 close_all_connections
- func close_all_connections() {
- statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
- c.Close()
- return true
- })
- }
- //export close_connection
- func close_connection(id *C.char) bool {
- connection_id := C.GoString(id)
- statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
- if c.ID() == connection_id {
- c.Close()
- return false
- }
- return true
- })
- return false
- }
- //export parse_options
- func parse_options() bool {
- err := hub.Parse(options...)
- if err != nil {
- return true
- }
- return false
- }
- //export get_traffic
- func get_traffic() *C.char {
- up, down := statistic.DefaultManager.Now()
- 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 init_native_api_bridge
- func init_native_api_bridge(api unsafe.Pointer) {
- fclashgobridge.InitDartApi(api)
- }
- //export start_log
- func start_log(port C.longlong) {
- if log_subscriber != nil {
- log.UnSubscribe(log_subscriber)
- log_subscriber = nil
- }
- log_subscriber = log.Subscribe()
- go func() {
- for elem := range log_subscriber {
- lg := elem
- data, err := json.Marshal(lg)
- if err != nil {
- fmt.Println("Error:", err)
- }
- ret_str := string(data)
- fclashgobridge.SendToPort(int64(port), ret_str)
- }
- }()
- fmt.Println("[GO] subscribe logger on dart bridge port", int64(port))
- }
- //export stop_log
- func stop_log() {
- if log_subscriber != nil {
- log.UnSubscribe(log_subscriber)
- fmt.Println("Logger stopped")
- log_subscriber = nil
- }
- }
- //export change_proxy
- func change_proxy(selector_name *C.char, proxy_name *C.char) C.long {
- proxies := tunnel.Proxies()
- proxy := proxies[C.GoString(selector_name)]
- if proxy == nil {
- return C.long(-1)
- }
- adapter_proxy := proxy.(*adapter.Proxy)
- selector, ok := adapter_proxy.ProxyAdapter.(*outboundgroup.Selector)
- if !ok {
- // not selector
- return C.long(-1)
- }
- if err := selector.Set(C.GoString(proxy_name)); err != nil {
- fmt.Println("", err)
- return C.long(-1)
- }
- cachefile.Cache().SetSelected(string(C.GoString(selector_name)), string(C.GoString(proxy_name)))
- return C.long(0)
- }
- type configSchema struct {
- Port *int `json:"port"`
- SocksPort *int `json:"socks-port"`
- RedirPort *int `json:"redir-port"`
- TProxyPort *int `json:"tproxy-port"`
- MixedPort *int `json:"mixed-port"`
- AllowLan *bool `json:"allow-lan"`
- BindAddress *string `json:"bind-address"`
- Mode *tunnel.TunnelMode `json:"mode"`
- LogLevel *log.LogLevel `json:"log-level"`
- IPv6 *bool `json:"ipv6"`
- }
- func pointerOrDefault(p *int, def int) int {
- if p != nil {
- return *p
- }
- return def
- }
- //export change_config_field
- func change_config_field(s *C.char) C.long {
- // todo
- general := &configSchema{}
- json_str := C.GoString(s)
- if err := json.Unmarshal([]byte(json_str), general); err != nil {
- fmt.Println(err)
- return C.long(-1)
- }
- // copy from clash source code
- if general.AllowLan != nil {
- P.SetAllowLan(*general.AllowLan)
- }
- if general.BindAddress != nil {
- P.SetBindAddress(*general.BindAddress)
- }
- ports := P.GetPorts()
- ports.Port = pointerOrDefault(general.Port, ports.Port)
- ports.MixedPort = pointerOrDefault(general.MixedPort, ports.MixedPort)
- ports.SocksPort = pointerOrDefault(general.SocksPort, ports.SocksPort)
- ports.RedirPort = pointerOrDefault(general.RedirPort, ports.RedirPort)
- ports.TProxyPort = pointerOrDefault(general.TProxyPort, ports.TProxyPort)
- tcpIn := tunnel.TCPIn()
- udpIn := tunnel.UDPIn()
- natTable := tunnel.NatTable()
- // P.ReCreate(*ports, tcpIn, udpIn)
- P.ReCreateHTTP(ports.Port, tcpIn)
- P.ReCreateMixed(ports.Port, tcpIn, udpIn)
- P.ReCreateSocks(ports.SocksPort, tcpIn, udpIn)
- P.ReCreateRedir(ports.RedirPort, tcpIn, udpIn, natTable)
- P.ReCreateTProxy(ports.TProxyPort, tcpIn, udpIn, natTable)
- if general.Mode != nil {
- tunnel.SetMode(*general.Mode)
- }
- if general.LogLevel != nil {
- log.SetLevel(*general.LogLevel)
- }
- if general.IPv6 != nil {
- resolver.DisableIPv6 = !*general.IPv6
- }
- return C.long(0)
- }
- //export async_test_delay
- func async_test_delay(proxy_name *C.char, url *C.char, timeout C.long, port C.longlong) {
- go func() {
- ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(int64(timeout)))
- defer cancel()
- proxies := tunnel.Proxies()
- proxy := proxies[C.GoString(proxy_name)]
- if proxy == nil {
- data, err := json.Marshal(map[string]int64{
- "delay": -1,
- })
- if err != nil {
- return
- }
- fclashgobridge.SendToPort(int64(port), string(data))
- return
- }
- rg := make(utils.IntRanges[uint16], 1)
- rg[0] = utils.NewRange[uint16](200, 400)
- delay, err := proxy.URLTest(ctx, C.GoString(url), rg, constant.ExtraHistory)
- if err != nil || delay == 0 {
- data, err := json.Marshal(map[string]int64{
- "delay": -1,
- })
- if err != nil {
- return
- }
- fclashgobridge.SendToPort(int64(port), string(data))
- return
- }
- data, err := json.Marshal(map[string]uint16{
- "delay": delay,
- })
- if err != nil {
- fmt.Println("err: ", err)
- }
- fclashgobridge.SendToPort(int64(port), string(data))
- }()
- }
- //export get_proxies
- func get_proxies() *C.char {
- proxies := tunnel.Proxies()
- for _, provider := range tunnel.Providers() {
- for _, proxy := range provider.Proxies() {
- proxies[proxy.Name()] = proxy
- }
- }
- data, err := json.Marshal(map[string]map[string]constant.Proxy{
- "proxies": proxies,
- })
- if err != nil {
- return C.CString("")
- }
- return C.CString(string(data))
- }
- //export get_configs
- func get_configs() *C.char {
- general := executor.GetGeneral()
- data, err := json.Marshal(general)
- if err != nil {
- return C.CString("")
- }
- return C.CString(string(data))
- }
- func main() {
- fmt.Println("hello fclash")
- }
|