big refactor. make compatible v2 and v1 interface
This commit is contained in:
@@ -6,12 +6,11 @@ import (
|
||||
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing/common/observable"
|
||||
)
|
||||
|
||||
var systemInfoObserver = observable.Observer[pb.SystemInfo]{}
|
||||
var outboundsInfoObserver = observable.Observer[pb.OutboundGroupList]{}
|
||||
var mainOutboundsInfoObserver = observable.Observer[pb.OutboundGroupList]{}
|
||||
var systemInfoObserver = NewObserver[pb.SystemInfo](10)
|
||||
var outboundsInfoObserver = NewObserver[pb.OutboundGroupList](10)
|
||||
var mainOutboundsInfoObserver = NewObserver[pb.OutboundGroupList](10)
|
||||
|
||||
var (
|
||||
statusClient *libbox.CommandClient
|
||||
@@ -19,7 +18,7 @@ var (
|
||||
groupInfoOnlyClient *libbox.CommandClient
|
||||
)
|
||||
|
||||
func (s *server) GetSystemInfo(stream pb.Hiddify_GetSystemInfoServer) error {
|
||||
func (s *CoreService) GetSystemInfo(stream pb.Core_GetSystemInfoServer) error {
|
||||
if statusClient == nil {
|
||||
statusClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{},
|
||||
@@ -55,7 +54,7 @@ func (s *server) GetSystemInfo(stream pb.Hiddify_GetSystemInfoServer) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) OutboundsInfo(stream pb.Hiddify_OutboundsInfoServer) error {
|
||||
func (s *CoreService) OutboundsInfo(stream pb.Core_OutboundsInfoServer) error {
|
||||
if groupClient == nil {
|
||||
groupClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{},
|
||||
@@ -91,7 +90,7 @@ func (s *server) OutboundsInfo(stream pb.Hiddify_OutboundsInfoServer) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) MainOutboundsInfo(stream pb.Hiddify_MainOutboundsInfoServer) error {
|
||||
func (s *CoreService) MainOutboundsInfo(stream pb.Core_MainOutboundsInfoServer) error {
|
||||
if groupInfoOnlyClient == nil {
|
||||
groupInfoOnlyClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{},
|
||||
@@ -127,8 +126,10 @@ func (s *server) MainOutboundsInfo(stream pb.Hiddify_MainOutboundsInfoServer) er
|
||||
}
|
||||
}
|
||||
|
||||
// Implement the SelectOutbound method
|
||||
func (s *server) SelectOutbound(ctx context.Context, in *pb.SelectOutboundRequest) (*pb.Response, error) {
|
||||
func (s *CoreService) SelectOutbound(ctx context.Context, in *pb.SelectOutboundRequest) (*pb.Response, error) {
|
||||
return SelectOutbound(in)
|
||||
}
|
||||
func SelectOutbound(in *pb.SelectOutboundRequest) (*pb.Response, error) {
|
||||
err := libbox.NewStandaloneCommandClient().SelectOutbound(in.GroupTag, in.OutboundTag)
|
||||
|
||||
if err != nil {
|
||||
@@ -144,8 +145,10 @@ func (s *server) SelectOutbound(ctx context.Context, in *pb.SelectOutboundReques
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Implement the UrlTest method
|
||||
func (s *server) UrlTest(ctx context.Context, in *pb.UrlTestRequest) (*pb.Response, error) {
|
||||
func (s *CoreService) UrlTest(ctx context.Context, in *pb.UrlTestRequest) (*pb.Response, error) {
|
||||
return UrlTest(in)
|
||||
}
|
||||
func UrlTest(in *pb.UrlTestRequest) (*pb.Response, error) {
|
||||
err := libbox.NewStandaloneCommandClient().URLTest(in.GroupTag)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/hiddify/libcore/bridge"
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
"github.com/sagernet/sing/common/observable"
|
||||
)
|
||||
|
||||
var coreInfoObserver = observable.Observer[pb.CoreInfoResponse]{}
|
||||
var coreInfoObserver = NewObserver[pb.CoreInfoResponse](10)
|
||||
var CoreState = pb.CoreState_STOPPED
|
||||
|
||||
func SetCoreStatus(state pb.CoreState, msgType pb.MessageType, message string) pb.CoreInfoResponse {
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, message)
|
||||
CoreState = state
|
||||
info := pb.CoreInfoResponse{
|
||||
CoreState: state,
|
||||
@@ -18,11 +20,13 @@ func SetCoreStatus(state pb.CoreState, msgType pb.MessageType, message string) p
|
||||
Message: message,
|
||||
}
|
||||
coreInfoObserver.Emit(info)
|
||||
msg, _ := json.Marshal(StatusMessage{Status: convert2OldState(CoreState)})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
return info
|
||||
|
||||
}
|
||||
|
||||
func (s *server) CoreInfoListener(stream pb.Hiddify_CoreInfoListenerServer) error {
|
||||
func (s *CoreService) CoreInfoListener(stream pb.Core_CoreInfoListenerServer) error {
|
||||
coreSub, _, _ := coreInfoObserver.Subscribe()
|
||||
defer coreInfoObserver.UnSubscribe(coreSub)
|
||||
stopch := make(chan int)
|
||||
|
||||
195
v2/custom.go
195
v2/custom.go
@@ -2,11 +2,13 @@ package v2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/hiddify/libcore/bridge"
|
||||
"github.com/hiddify/libcore/config"
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
@@ -22,19 +24,26 @@ var logFactory *log.Factory
|
||||
func StopAndAlert(msgType pb.MessageType, message string) {
|
||||
SetCoreStatus(pb.CoreState_STOPPED, msgType, message)
|
||||
config.DeactivateTunnelService()
|
||||
// if commandServer != nil {
|
||||
// commandServer.SetService(nil)
|
||||
// }
|
||||
if commandServer != nil {
|
||||
commandServer.SetService(nil)
|
||||
}
|
||||
if Box != nil {
|
||||
Box.Close()
|
||||
Box = nil
|
||||
}
|
||||
// if commandServer != nil {
|
||||
// commandServer.Close()
|
||||
// }
|
||||
if commandServer != nil {
|
||||
commandServer.Close()
|
||||
}
|
||||
alert := msgType.String()
|
||||
msg, _ := json.Marshal(StatusMessage{Status: convert2OldState(CoreState), Alert: &alert, Message: &message})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
}
|
||||
|
||||
func (s *server) Start(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
func (s *CoreService) Start(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
return Start(in)
|
||||
}
|
||||
|
||||
func Start(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
defer config.DeferPanicToError("start", func(err error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
@@ -49,17 +58,23 @@ func (s *server) Start(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoRe
|
||||
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
|
||||
|
||||
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
|
||||
resp, err := s.StartService(ctx, in)
|
||||
resp, err := StartService(in)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Implement the StartService method
|
||||
func (s *server) StartService(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
func (s *CoreService) StartService(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
return StartService(in)
|
||||
}
|
||||
func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
|
||||
content := in.ConfigContent
|
||||
if content != "" {
|
||||
if content == "" {
|
||||
|
||||
if in.ConfigPath != "" {
|
||||
activeConfigPath = &in.ConfigPath
|
||||
}
|
||||
fileContent, err := os.ReadFile(*activeConfigPath)
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_READING_CONFIG, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
@@ -68,26 +83,31 @@ func (s *server) StartService(ctx context.Context, in *pb.StartRequest) (*pb.Cor
|
||||
|
||||
parsedContent, err := parseConfig(content)
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_PARSING_CONFIG, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
var patchedOptions *option.Options
|
||||
patchedOptions, err = config.BuildConfig(*configOptions, parsedContent)
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_BUILDING_CONFIG, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
|
||||
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "current-config.json"), *patchedOptions)
|
||||
|
||||
// err = startCommandServer(*logFactory)
|
||||
// if err != nil {
|
||||
// resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_COMMAND_SERVER, err.Error())
|
||||
// return &resp, err
|
||||
// }
|
||||
if in.EnableOldCommandServer {
|
||||
err = startCommandServer(*logFactory)
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_COMMAND_SERVER, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
}
|
||||
|
||||
instance, err := NewService(*patchedOptions)
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_CREATE_SERVICE, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
@@ -98,30 +118,55 @@ func (s *server) StartService(ctx context.Context, in *pb.StartRequest) (*pb.Cor
|
||||
|
||||
err = instance.Start()
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_SERVICE, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
Box = instance
|
||||
// commandServer.SetService(box)
|
||||
if in.EnableOldCommandServer {
|
||||
commandServer.SetService(Box)
|
||||
}
|
||||
|
||||
resp := SetCoreStatus(pb.CoreState_STARTED, pb.MessageType_EMPTY, "")
|
||||
return &resp, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *server) Parse(ctx context.Context, in *pb.ParseRequest) (*pb.ParseResponse, error) {
|
||||
func (s *CoreService) Parse(ctx context.Context, in *pb.ParseRequest) (*pb.ParseResponse, error) {
|
||||
return Parse(in)
|
||||
}
|
||||
func Parse(in *pb.ParseRequest) (*pb.ParseResponse, error) {
|
||||
defer config.DeferPanicToError("parse", func(err error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CONFIG, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
})
|
||||
content := in.Content
|
||||
if in.TempPath != "" {
|
||||
contentBytes, err := os.ReadFile(in.TempPath)
|
||||
content = string(contentBytes)
|
||||
os.Chdir(filepath.Dir(in.ConfigPath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config, err := config.ParseConfigContent(in.Content, true)
|
||||
}
|
||||
|
||||
config, err := config.ParseConfigContent(content, true)
|
||||
if err != nil {
|
||||
return &pb.ParseResponse{
|
||||
ResponseCode: pb.ResponseCode_FAILED,
|
||||
Message: err.Error(),
|
||||
}, err
|
||||
}
|
||||
if in.ConfigPath != "" {
|
||||
err = os.WriteFile(in.ConfigPath, config, 0644)
|
||||
if err != nil {
|
||||
return &pb.ParseResponse{
|
||||
ResponseCode: pb.ResponseCode_FAILED,
|
||||
Message: err.Error(),
|
||||
}, err
|
||||
}
|
||||
}
|
||||
return &pb.ParseResponse{
|
||||
ResponseCode: pb.ResponseCode_OK,
|
||||
Content: string(config),
|
||||
@@ -129,31 +174,67 @@ func (s *server) Parse(ctx context.Context, in *pb.ParseRequest) (*pb.ParseRespo
|
||||
}, err
|
||||
}
|
||||
|
||||
// func (s *server) ChangeConfigOptions(ctx context.Context, in *pb.ChangeConfigOptionsRequest) (*pb.CoreInfoResponse, error) {
|
||||
// // Implement your change config options logic
|
||||
// // Return a CoreInfoResponse
|
||||
// }
|
||||
func (s *CoreService) ChangeConfigOptions(ctx context.Context, in *pb.ChangeConfigOptionsRequest) (*pb.CoreInfoResponse, error) {
|
||||
return ChangeConfigOptions(in)
|
||||
}
|
||||
|
||||
// func (s *server) GenerateConfig(ctx context.Context, in *pb.GenerateConfigRequest) (*pb.GenerateConfigResponse, error) {
|
||||
// defer config.DeferPanicToError("generateConfig", func(err error) {
|
||||
// Log(pb.LogLevel_FATAL, pb.LogType_CONFIG, err.Error())
|
||||
// StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
// })
|
||||
func ChangeConfigOptions(in *pb.ChangeConfigOptionsRequest) (*pb.CoreInfoResponse, error) {
|
||||
configOptions = &config.ConfigOptions{}
|
||||
err := json.Unmarshal([]byte(in.ConfigOptionsJson), configOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if configOptions.Warp.WireguardConfigStr != "" {
|
||||
err := json.Unmarshal([]byte(configOptions.Warp.WireguardConfigStr), &configOptions.Warp.WireguardConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &pb.CoreInfoResponse{}, nil
|
||||
}
|
||||
func (s *CoreService) GenerateConfig(ctx context.Context, in *pb.GenerateConfigRequest) (*pb.GenerateConfigResponse, error) {
|
||||
return GenerateConfig(in)
|
||||
}
|
||||
func GenerateConfig(in *pb.GenerateConfigRequest) (*pb.GenerateConfigResponse, error) {
|
||||
defer config.DeferPanicToError("generateConfig", func(err error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CONFIG, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
})
|
||||
|
||||
// config, err := generateConfigFromFile(C.GoString(path), *configOptions)
|
||||
// if err != nil {
|
||||
// return C.CString("error" + err.Error())
|
||||
// }
|
||||
// return C.CString(config)
|
||||
// }
|
||||
config, err := generateConfigFromFile(in.Path, *configOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.GenerateConfigResponse{
|
||||
ConfigContent: config,
|
||||
}, nil
|
||||
}
|
||||
func generateConfigFromFile(path string, configOpt config.ConfigOptions) (string, error) {
|
||||
os.Chdir(filepath.Dir(path))
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options, err := parseConfig(string(content))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
config, err := config.BuildConfigJson(configOpt, options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// Implement the Stop method
|
||||
func (s *server) Stop(ctx context.Context, empty *pb.Empty) (*pb.CoreInfoResponse, error) {
|
||||
func (s *CoreService) Stop(ctx context.Context, empty *pb.Empty) (*pb.CoreInfoResponse, error) {
|
||||
return Stop()
|
||||
}
|
||||
func Stop() (*pb.CoreInfoResponse, error) {
|
||||
defer config.DeferPanicToError("stop", func(err error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
})
|
||||
config.DeactivateTunnelService()
|
||||
|
||||
if CoreState != pb.CoreState_STARTED {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, "Core is not started")
|
||||
return &pb.CoreInfoResponse{
|
||||
@@ -170,7 +251,10 @@ func (s *server) Stop(ctx context.Context, empty *pb.Empty) (*pb.CoreInfoRespons
|
||||
}, fmt.Errorf("instance not found")
|
||||
}
|
||||
SetCoreStatus(pb.CoreState_STOPPING, pb.MessageType_EMPTY, "")
|
||||
// commandServer.SetService(nil)
|
||||
config.DeactivateTunnelService()
|
||||
if commandServer != nil {
|
||||
commandServer.SetService(nil)
|
||||
}
|
||||
|
||||
err := Box.Close()
|
||||
if err != nil {
|
||||
@@ -181,22 +265,25 @@ func (s *server) Stop(ctx context.Context, empty *pb.Empty) (*pb.CoreInfoRespons
|
||||
}, fmt.Errorf("Error while stopping the service.")
|
||||
}
|
||||
Box = nil
|
||||
// err = commandServer.Close()
|
||||
// if err != nil {
|
||||
// return &pb.CoreInfoResponse{
|
||||
// CoreState: CoreState,
|
||||
// MessageType: pb.MessageType_UNEXPECTED_ERROR,
|
||||
// Message: "Error while Closing the comand server.",
|
||||
// }, fmt.Errorf("Error while Closing the comand server.")
|
||||
|
||||
// }
|
||||
// commandServer = nil
|
||||
if commandServer != nil {
|
||||
err = commandServer.Close()
|
||||
if err != nil {
|
||||
return &pb.CoreInfoResponse{
|
||||
CoreState: CoreState,
|
||||
MessageType: pb.MessageType_UNEXPECTED_ERROR,
|
||||
Message: "Error while Closing the comand server.",
|
||||
}, fmt.Errorf("Error while Closing the comand server.")
|
||||
}
|
||||
commandServer = nil
|
||||
}
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_EMPTY, "")
|
||||
return &resp, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *server) Restart(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
func (s *CoreService) Restart(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
return Restart(in)
|
||||
}
|
||||
func Restart(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
defer config.DeferPanicToError("restart", func(err error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
@@ -218,7 +305,7 @@ func (s *server) Restart(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfo
|
||||
}, fmt.Errorf("instance not found")
|
||||
}
|
||||
|
||||
resp, err := s.Stop(ctx, &pb.Empty{})
|
||||
resp, err := Stop()
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
@@ -227,6 +314,6 @@ func (s *server) Restart(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfo
|
||||
<-time.After(250 * time.Millisecond)
|
||||
|
||||
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
|
||||
resp, gErr := s.StartService(ctx, in)
|
||||
resp, gErr := StartService(in)
|
||||
return resp, gErr
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func main() {
|
||||
log.Fatalf("did not connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
c := pb.NewHiddifyClient(conn)
|
||||
c := pb.NewHelloClient(conn)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func main() {
|
||||
|
||||
// defer C.free(unsafe.Pointer(port))
|
||||
v2.StartGrpcServerGo("127.0.0.1:50051")
|
||||
v2.StartGrpcServer("127.0.0.1:50051")
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||
<-sigChan
|
||||
|
||||
@@ -13,24 +13,18 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
pb.UnimplementedHiddifyServer
|
||||
type HelloService struct {
|
||||
pb.UnimplementedHelloServer
|
||||
}
|
||||
type CoreService struct {
|
||||
pb.UnimplementedCoreServer
|
||||
}
|
||||
|
||||
//export StartGrpcServer
|
||||
func StartGrpcServer(listenAddress *C.char) (CErr *C.char) {
|
||||
//Example Listen Address: "127.0.0.1:50051"
|
||||
err := StartGrpcServerGo(C.GoString(listenAddress))
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return nil
|
||||
type TunnelService struct {
|
||||
pb.UnimplementedTunnelServiceServer
|
||||
}
|
||||
|
||||
func StartGrpcServerGo(listenAddressG string) error {
|
||||
//Example Listen Address: "127.0.0.1:50051"
|
||||
// defer C.free(unsafe.Pointer(CErr)) // free the C string when it's no longer needed
|
||||
// defer C.free(unsafe.Pointer(listenAddress)) // free the C string when it's no longer needed
|
||||
func StartGrpcServer(listenAddressG string, service string) error {
|
||||
|
||||
lis, err := net.Listen("tcp", listenAddressG)
|
||||
if err != nil {
|
||||
@@ -38,7 +32,13 @@ func StartGrpcServerGo(listenAddressG string) error {
|
||||
return err
|
||||
}
|
||||
s := grpc.NewServer()
|
||||
pb.RegisterHiddifyServer(s, &server{})
|
||||
if service == "core" {
|
||||
pb.RegisterCoreServer(s, &CoreService{})
|
||||
} else if service == "hello" {
|
||||
pb.RegisterHelloServer(s, &HelloService{})
|
||||
} else if service == "tunnel" {
|
||||
pb.RegisterTunnelServiceServer(s, &TunnelService{})
|
||||
}
|
||||
log.Printf("Server listening on %s", listenAddressG)
|
||||
go func() {
|
||||
if err := s.Serve(lis); err != nil {
|
||||
@@ -47,3 +47,14 @@ func StartGrpcServerGo(listenAddressG string) error {
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
func StartCoreGrpcServer(listenAddressG string) error {
|
||||
return StartGrpcServer(listenAddressG, "core")
|
||||
}
|
||||
|
||||
func StartHelloGrpcServer(listenAddressG string) error {
|
||||
return StartGrpcServer(listenAddressG, "hello")
|
||||
}
|
||||
|
||||
func StartTunnelGrpcServer(listenAddressG string) error {
|
||||
return StartGrpcServer(listenAddressG, "tunnel")
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
)
|
||||
|
||||
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
|
||||
func (s *HelloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
|
||||
return &pb.HelloResponse{Message: "Hello, " + in.Name}, nil
|
||||
}
|
||||
func (s *server) SayHelloStream(stream pb.Hiddify_SayHelloStreamServer) error {
|
||||
func (s *HelloService) SayHelloStream(stream pb.Hello_SayHelloStreamServer) error {
|
||||
|
||||
for {
|
||||
req, err := stream.Recv()
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
"github.com/sagernet/sing/common/observable"
|
||||
)
|
||||
|
||||
var logObserver = observable.Observer[pb.LogMessage]{}
|
||||
func NewObserver[T any](listenerBufferSize int) *observable.Observer[T] {
|
||||
return observable.NewObserver[T](&observable.Subscriber[T]{}, listenerBufferSize)
|
||||
}
|
||||
|
||||
var logObserver = NewObserver[pb.LogMessage](10)
|
||||
|
||||
func Log(level pb.LogLevel, typ pb.LogType, message string) {
|
||||
fmt.Printf("%s %s %s\n", level, typ, message)
|
||||
logObserver.Emit(pb.LogMessage{
|
||||
Level: level,
|
||||
Type: typ,
|
||||
@@ -18,7 +24,7 @@ func Log(level pb.LogLevel, typ pb.LogType, message string) {
|
||||
|
||||
}
|
||||
|
||||
func (s *server) LogListener(stream pb.Hiddify_LogListenerServer) error {
|
||||
func (s *CoreService) LogListener(stream pb.Core_LogListenerServer) error {
|
||||
logSub, _, _ := logObserver.Subscribe()
|
||||
defer logObserver.UnSubscribe(logSub)
|
||||
|
||||
@@ -30,9 +36,7 @@ func (s *server) LogListener(stream pb.Hiddify_LogListenerServer) error {
|
||||
for {
|
||||
select {
|
||||
case <-stream.Context().Done():
|
||||
break
|
||||
case <-stopch:
|
||||
break
|
||||
return nil
|
||||
case info := <-logSub:
|
||||
stream.Send(&info)
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
|
||||
105
v2/old_command_client.go
Normal file
105
v2/old_command_client.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/hiddify/libcore/bridge"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
)
|
||||
|
||||
var (
|
||||
_ libbox.CommandClientHandler = (*OldCommandClientHandler)(nil)
|
||||
)
|
||||
|
||||
type OldCommandClientHandler struct {
|
||||
port int64
|
||||
// logger log.Logger
|
||||
}
|
||||
|
||||
func (cch *OldCommandClientHandler) Connected() {
|
||||
// cch.logger.Debug("CONNECTED")
|
||||
}
|
||||
|
||||
func (cch *OldCommandClientHandler) Disconnected(message string) {
|
||||
// cch.logger.Debug("DISCONNECTED: ", message)
|
||||
}
|
||||
|
||||
func (cch *OldCommandClientHandler) ClearLog() {
|
||||
// cch.logger.Debug("clear log")
|
||||
}
|
||||
|
||||
func (cch *OldCommandClientHandler) WriteLog(message string) {
|
||||
// cch.logger.Debug("log: ", message)
|
||||
}
|
||||
|
||||
func (cch *OldCommandClientHandler) 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,
|
||||
},
|
||||
)
|
||||
// cch.logger.Debug("Memory: ", libbox.FormatBytes(message.Memory), ", Goroutines: ", message.Goroutines)
|
||||
if err != nil {
|
||||
bridge.SendStringToPort(cch.port, fmt.Sprintf("error: %e", err))
|
||||
} else {
|
||||
bridge.SendStringToPort(cch.port, string(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func (cch *OldCommandClientHandler) WriteGroups(message libbox.OutboundGroupIterator) {
|
||||
if message == nil {
|
||||
return
|
||||
}
|
||||
groups := []*OutboundGroup{}
|
||||
for message.HasNext() {
|
||||
group := message.Next()
|
||||
items := group.GetItems()
|
||||
groupItems := []*OutboundGroupItem{}
|
||||
for items.HasNext() {
|
||||
item := items.Next()
|
||||
groupItems = append(groupItems,
|
||||
&OutboundGroupItem{
|
||||
Tag: item.Tag,
|
||||
Type: item.Type,
|
||||
URLTestTime: item.URLTestTime,
|
||||
URLTestDelay: item.URLTestDelay,
|
||||
},
|
||||
)
|
||||
}
|
||||
groups = append(groups, &OutboundGroup{Tag: group.Tag, Type: group.Type, Selected: group.Selected, Items: groupItems})
|
||||
}
|
||||
response, err := json.Marshal(groups)
|
||||
if err != nil {
|
||||
bridge.SendStringToPort(cch.port, fmt.Sprintf("error: %e", err))
|
||||
} else {
|
||||
bridge.SendStringToPort(cch.port, string(response))
|
||||
}
|
||||
}
|
||||
|
||||
func (cch *OldCommandClientHandler) InitializeClashMode(modeList libbox.StringIterator, currentMode string) {
|
||||
// cch.logger.Debug("initial clash mode: ", currentMode)
|
||||
}
|
||||
|
||||
func (cch *OldCommandClientHandler) UpdateClashMode(newMode string) {
|
||||
// cch.logger.Debug("update clash mode: ", newMode)
|
||||
}
|
||||
|
||||
type OutboundGroup struct {
|
||||
Tag string `json:"tag"`
|
||||
Type string `json:"type"`
|
||||
Selected string `json:"selected"`
|
||||
Items []*OutboundGroupItem `json:"items"`
|
||||
}
|
||||
|
||||
type OutboundGroupItem struct {
|
||||
Tag string `json:"tag"`
|
||||
Type string `json:"type"`
|
||||
URLTestTime int64 `json:"url-test-time"`
|
||||
URLTestDelay int32 `json:"url-test-delay"`
|
||||
}
|
||||
50
v2/old_command_server.go
Normal file
50
v2/old_command_server.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
)
|
||||
|
||||
var commandServer *libbox.CommandServer
|
||||
|
||||
type CommandServerHandler struct {
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) ServiceReload() error {
|
||||
csh.logger.Trace("Reloading service")
|
||||
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
|
||||
|
||||
if commandServer != nil {
|
||||
commandServer.SetService(nil)
|
||||
commandServer = nil
|
||||
}
|
||||
if Box != nil {
|
||||
Box.Close()
|
||||
Box = nil
|
||||
}
|
||||
_, err := StartService(&pb.StartRequest{
|
||||
EnableOldCommandServer: true,
|
||||
DelayStart: true,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) GetSystemProxyStatus() *libbox.SystemProxyStatus {
|
||||
csh.logger.Trace("Getting system proxy status")
|
||||
return &libbox.SystemProxyStatus{Available: true, Enabled: false}
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) SetSystemProxyEnabled(isEnabled bool) error {
|
||||
csh.logger.Trace("Setting system proxy status, enabled? ", isEnabled)
|
||||
return csh.ServiceReload()
|
||||
}
|
||||
|
||||
func startCommandServer(logFactory log.Factory) error {
|
||||
logger := logFactory.NewLogger("[Command Server Handler]")
|
||||
logger.Trace("Starting command server")
|
||||
commandServer = libbox.NewCommandServer(&CommandServerHandler{logger: logger}, 300)
|
||||
return commandServer.Start()
|
||||
}
|
||||
71
v2/old_commands.go
Normal file
71
v2/old_commands.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
)
|
||||
|
||||
var (
|
||||
oldStatusClient *libbox.CommandClient
|
||||
oldGroupClient *libbox.CommandClient
|
||||
oldGroupInfoOnlyClient *libbox.CommandClient
|
||||
)
|
||||
|
||||
func StartCommand(command int32, port int64) error {
|
||||
switch command {
|
||||
case libbox.CommandStatus:
|
||||
oldStatusClient = libbox.NewCommandClient(
|
||||
&OldCommandClientHandler{
|
||||
port: port,
|
||||
// logger: logFactory.NewLogger("[Status Command Client]"),
|
||||
},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandStatus,
|
||||
StatusInterval: 1000000000, //1000ms debounce
|
||||
},
|
||||
)
|
||||
return oldStatusClient.Connect()
|
||||
case libbox.CommandGroup:
|
||||
oldGroupClient = libbox.NewCommandClient(
|
||||
&OldCommandClientHandler{
|
||||
port: port,
|
||||
// logger: logFactory.NewLogger("[Group Command Client]"),
|
||||
},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandGroup,
|
||||
StatusInterval: 300000000, //300ms debounce
|
||||
},
|
||||
)
|
||||
return oldGroupClient.Connect()
|
||||
case libbox.CommandGroupInfoOnly:
|
||||
oldGroupInfoOnlyClient = libbox.NewCommandClient(
|
||||
&OldCommandClientHandler{
|
||||
port: port,
|
||||
// logger: logFactory.NewLogger("[GroupInfoOnly Command Client]"),
|
||||
},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandGroupInfoOnly,
|
||||
StatusInterval: 300000000, //300ms debounce
|
||||
},
|
||||
)
|
||||
return oldGroupInfoOnlyClient.Connect()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func StopCommand(command int32) error {
|
||||
switch command {
|
||||
case libbox.CommandStatus:
|
||||
err := oldStatusClient.Disconnect()
|
||||
oldStatusClient = nil
|
||||
return err
|
||||
case libbox.CommandGroup:
|
||||
err := oldGroupClient.Disconnect()
|
||||
oldGroupClient = nil
|
||||
return err
|
||||
case libbox.CommandGroupInfoOnly:
|
||||
err := oldGroupInfoOnlyClient.Disconnect()
|
||||
oldGroupInfoOnlyClient = nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
38
v2/old_constant.go
Normal file
38
v2/old_constant.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package v2
|
||||
|
||||
import pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
|
||||
const (
|
||||
Stopped = "Stopped"
|
||||
Starting = "Starting"
|
||||
Started = "Started"
|
||||
Stopping = "Stopping"
|
||||
)
|
||||
|
||||
const (
|
||||
EmptyConfiguration = "EmptyConfiguration"
|
||||
StartCommandServer = "StartCommandServer"
|
||||
CreateService = "CreateService"
|
||||
)
|
||||
|
||||
func convert2OldState(newStatus pb.CoreState) string {
|
||||
if newStatus == pb.CoreState_STOPPED {
|
||||
return Stopped
|
||||
}
|
||||
if newStatus == pb.CoreState_STARTED {
|
||||
return Started
|
||||
}
|
||||
if newStatus == pb.CoreState_STARTING {
|
||||
return Starting
|
||||
}
|
||||
if newStatus == pb.CoreState_STOPPING {
|
||||
return Stopping
|
||||
}
|
||||
return "Invalid"
|
||||
}
|
||||
|
||||
type StatusMessage struct {
|
||||
Status string `json:"status"`
|
||||
Alert *string `json:"alert"`
|
||||
Message *string `json:"message"`
|
||||
}
|
||||
@@ -2,13 +2,16 @@ package v2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
runtimeDebug "runtime/debug"
|
||||
"time"
|
||||
|
||||
B "github.com/sagernet/sing-box"
|
||||
"github.com/sagernet/sing-box/common/urltest"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/service"
|
||||
@@ -17,13 +20,15 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
sWorkingPath string
|
||||
sTempPath string
|
||||
sUserID int
|
||||
sGroupID int
|
||||
sWorkingPath string
|
||||
sTempPath string
|
||||
sUserID int
|
||||
sGroupID int
|
||||
statusPropagationPort int64
|
||||
)
|
||||
|
||||
func Setup(basePath string, workingPath string, tempPath string) {
|
||||
func Setup(basePath string, workingPath string, tempPath string, statusPort int64, debug bool) error {
|
||||
statusPropagationPort = int64(statusPort)
|
||||
tcpConn := runtime.GOOS == "windows" //TODO add TVOS
|
||||
libbox.Setup(basePath, workingPath, tempPath, tcpConn)
|
||||
sWorkingPath = workingPath
|
||||
@@ -31,6 +36,19 @@ func Setup(basePath string, workingPath string, tempPath string) {
|
||||
sTempPath = tempPath
|
||||
sUserID = os.Getuid()
|
||||
sGroupID = os.Getgid()
|
||||
|
||||
var defaultWriter io.Writer
|
||||
if !debug {
|
||||
defaultWriter = io.Discard
|
||||
}
|
||||
factory, err := log.New(
|
||||
log.Options{
|
||||
DefaultWriter: defaultWriter,
|
||||
BaseTime: time.Now(),
|
||||
Observable: false,
|
||||
})
|
||||
logFactory = &factory
|
||||
return err
|
||||
}
|
||||
|
||||
func NewService(options option.Options) (*libbox.BoxService, error) {
|
||||
|
||||
44
v2/system_proxy.go
Normal file
44
v2/system_proxy.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
)
|
||||
|
||||
func (s *CoreService) GetSystemProxyStatus(ctx context.Context, empty *pb.Empty) (*pb.SystemProxyStatus, error) {
|
||||
return GetSystemProxyStatus(ctx, empty)
|
||||
}
|
||||
func GetSystemProxyStatus(ctx context.Context, empty *pb.Empty) (*pb.SystemProxyStatus, error) {
|
||||
status, err := libbox.NewStandaloneCommandClient().GetSystemProxyStatus()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.SystemProxyStatus{
|
||||
Available: status.Available,
|
||||
Enabled: status.Enabled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *CoreService) SetSystemProxyEnabled(ctx context.Context, in *pb.SetSystemProxyEnabledRequest) (*pb.Response, error) {
|
||||
return SetSystemProxyEnabled(ctx, in)
|
||||
}
|
||||
func SetSystemProxyEnabled(ctx context.Context, in *pb.SetSystemProxyEnabledRequest) (*pb.Response, error) {
|
||||
err := libbox.NewStandaloneCommandClient().SetSystemProxyEnabled(in.IsEnabled)
|
||||
|
||||
if err != nil {
|
||||
return &pb.Response{
|
||||
ResponseCode: pb.ResponseCode_FAILED,
|
||||
Message: err.Error(),
|
||||
}, err
|
||||
}
|
||||
|
||||
return &pb.Response{
|
||||
ResponseCode: pb.ResponseCode_OK,
|
||||
Message: "",
|
||||
}, nil
|
||||
|
||||
}
|
||||
42
v2/warp.go
42
v2/warp.go
@@ -5,10 +5,12 @@ import (
|
||||
|
||||
"github.com/hiddify/libcore/config"
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
)
|
||||
|
||||
func (s *server) GenerateWarpConfig(ctx context.Context, in *pb.GenerateWarpConfigRequest) (*pb.WarpGenerationResponse, error) {
|
||||
func (s *CoreService) GenerateWarpConfig(ctx context.Context, in *pb.GenerateWarpConfigRequest) (*pb.WarpGenerationResponse, error) {
|
||||
return GenerateWarpConfig(in)
|
||||
}
|
||||
func GenerateWarpConfig(in *pb.GenerateWarpConfigRequest) (*pb.WarpGenerationResponse, error) {
|
||||
account, log, wg, err := config.GenerateWarpInfo(in.LicenseKey, in.AccountId, in.AccessToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -27,39 +29,3 @@ func (s *server) GenerateWarpConfig(ctx context.Context, in *pb.GenerateWarpConf
|
||||
Log: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Implement the GetSystemProxyStatus method
|
||||
func (s *server) GetSystemProxyStatus(ctx context.Context, empty *pb.Empty) (*pb.SystemProxyStatus, error) {
|
||||
status, err := libbox.NewStandaloneCommandClient().GetSystemProxyStatus()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.SystemProxyStatus{
|
||||
Available: status.Available,
|
||||
Enabled: status.Enabled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Implement the SetSystemProxyEnabled method
|
||||
func (s *server) SetSystemProxyEnabled(ctx context.Context, in *pb.SetSystemProxyEnabledRequest) (*pb.Response, error) {
|
||||
err := libbox.NewStandaloneCommandClient().SetSystemProxyEnabled(in.IsEnabled)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return &pb.Response{
|
||||
ResponseCode: pb.ResponseCode_FAILED,
|
||||
Message: err.Error(),
|
||||
}, err
|
||||
}
|
||||
|
||||
return &pb.Response{
|
||||
ResponseCode: pb.ResponseCode_OK,
|
||||
Message: "",
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user