diff --git a/custom/command_client.go b/custom/command_client.go new file mode 100644 index 0000000..89e3f42 --- /dev/null +++ b/custom/command_client.go @@ -0,0 +1,50 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/hiddify/libcore/bridge" + "github.com/sagernet/sing-box/experimental/libbox" +) + +type CommandClientHandler struct { + port int64 +} + +func (cch *CommandClientHandler) Connected() { + fmt.Println("connected") +} + +func (cch *CommandClientHandler) Disconnected(message string) { + fmt.Printf("disconnected: %s\n", message) +} + +func (cch *CommandClientHandler) WriteLog(message string) { + fmt.Printf("new log: %s\n", message) +} + +func (cch *CommandClientHandler) WriteStatus(message *libbox.StatusMessage) { + msg, err := json.Marshal( + map[string]int64{ + "connections-in": int64(message.ConnectionsIn), + "connections-out": int64(message.ConnectionsOut), + "uplink": message.Uplink, + "downlink": message.Downlink, + "uplink-total": message.UplinkTotal, + "downlink-total": message.DownlinkTotal, + }, + ) + if err != nil { + bridge.SendStringToPort(cch.port, fmt.Sprintf("error: %e", err)) + } else { + bridge.SendStringToPort(cch.port, string(msg)) + } +} + +func (cch *CommandClientHandler) WriteGroups(message libbox.OutboundGroupIterator) {} + +func (cch *CommandClientHandler) InitializeClashMode(modeList libbox.StringIterator, currentMode string) { +} + +func (cch *CommandClientHandler) UpdateClashMode(newMode string) {} diff --git a/custom/commands.go b/custom/commands.go new file mode 100644 index 0000000..0f30ac5 --- /dev/null +++ b/custom/commands.go @@ -0,0 +1,32 @@ +package main + +import "github.com/sagernet/sing-box/experimental/libbox" + +var ( + statusCommand *libbox.CommandClient +) + +func StartCommand(command int32, port int64) error { + switch command { + case libbox.CommandStatus: + statusCommand = libbox.NewCommandClient( + &CommandClientHandler{port: port}, + &libbox.CommandClientOptions{ + Command: libbox.CommandStatus, + StatusInterval: 1000000000, + }, + ) + return statusCommand.Connect() + } + return nil +} + +func StopCommand(command int32) error { + switch command { + case libbox.CommandStatus: + err := statusCommand.Disconnect() + statusCommand = nil + return err + } + return nil +} diff --git a/custom/custom.go b/custom/custom.go index 95713b7..c65588b 100644 --- a/custom/custom.go +++ b/custom/custom.go @@ -6,13 +6,20 @@ package main import "C" import ( "os" + "unsafe" + "github.com/hiddify/libcore/bridge" "github.com/hiddify/libcore/shared" "github.com/sagernet/sing-box/experimental/libbox" ) var box *libbox.BoxService +//export setupOnce +func setupOnce(api unsafe.Pointer) { + bridge.InitializeDartApi(api) +} + //export setup func setup(baseDir *C.char, workingDir *C.char, tempDir *C.char) { Setup(C.GoString(baseDir), C.GoString(workingDir), C.GoString(tempDir)) @@ -48,12 +55,25 @@ func create(configPath *C.char) *C.char { shared.SaveCurrentConfig(sWorkingPath, options) + err = startCommandServer() + if err != nil { + return C.CString(err.Error()) + } + instance, err := NewService(options) if err != nil { return C.CString(err.Error()) } box = instance + commandServer.SetService(box) + + if err != nil { + instance.Close() + box = nil + return C.CString(err.Error()) + } + return C.CString("") } @@ -62,6 +82,7 @@ func start() *C.char { if box == nil { return C.CString("instance not found") } + err := box.Start() if err != nil { return C.CString(err.Error()) @@ -76,10 +97,37 @@ func stop() *C.char { return C.CString("instance not found") } + commandServer.SetService(nil) err := box.Close() if err != nil { return C.CString(err.Error()) } + box = nil + + err = commandServer.Close() + if err != nil { + return C.CString(err.Error()) + } + commandServer = nil + + return C.CString("") +} + +//export startCommandClient +func startCommandClient(command C.int, port C.longlong) *C.char { + err := StartCommand(int32(command), int64(port)) + if err != nil { + return C.CString(err.Error()) + } + return C.CString("") +} + +//export stopCommandClient +func stopCommandClient(command C.int) *C.char { + err := StopCommand(int32(command)) + if err != nil { + return C.CString(err.Error()) + } return C.CString("") }