Files
umbrix-libcore/v2/custom.go

358 lines
11 KiB
Go
Raw Normal View History

2024-03-10 19:45:03 +01:00
package v2
import (
"context"
"encoding/json"
2024-03-10 19:45:03 +01:00
"fmt"
"os"
"path/filepath"
"time"
2024-03-22 16:25:56 +00:00
"github.com/hiddify/hiddify-core/bridge"
"github.com/hiddify/hiddify-core/config"
pb "github.com/hiddify/hiddify-core/hiddifyrpc"
2024-03-10 19:45:03 +01:00
"github.com/sagernet/sing-box/experimental/libbox"
"github.com/sagernet/sing-box/log"
)
2024-03-18 20:38:09 +01:00
var (
Box *libbox.BoxService
2024-09-26 23:27:04 +02:00
HiddifyOptions *config.HiddifyOptions
2024-03-18 20:38:09 +01:00
activeConfigPath string
coreLogFactory log.Factory
useFlutterBridge bool = true
)
2024-03-10 19:45:03 +01:00
func StopAndAlert(msgType pb.MessageType, message string) {
SetCoreStatus(pb.CoreState_STOPPED, msgType, message)
config.DeactivateTunnelService()
2024-03-18 10:53:54 +01:00
if oldCommandServer != nil {
oldCommandServer.SetService(nil)
}
2024-03-10 19:45:03 +01:00
if Box != nil {
Box.Close()
Box = nil
}
2024-03-18 10:53:54 +01:00
if oldCommandServer != nil {
oldCommandServer.Close()
}
2024-03-18 20:38:09 +01:00
if useFlutterBridge {
alert := msgType.String()
msg, _ := json.Marshal(StatusMessage{Status: convert2OldState(CoreState), Alert: &alert, Message: &message})
bridge.SendStringToPort(statusPropagationPort, string(msg))
}
}
func (s *CoreService) Start(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
return Start(in)
2024-03-10 19:45:03 +01:00
}
func Start(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
2024-03-10 19:45:03 +01:00
defer config.DeferPanicToError("start", func(err error) {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
})
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Starting")
2024-03-10 19:45:03 +01:00
if CoreState != pb.CoreState_STOPPED {
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Starting0000")
Stop()
// return &pb.CoreInfoResponse{
// CoreState: CoreState,
// MessageType: pb.MessageType_INSTANCE_NOT_STOPPED,
// }, fmt.Errorf("instance not stopped")
2024-03-10 19:45:03 +01:00
}
2024-03-18 20:38:09 +01:00
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Starting Core")
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
2024-03-10 19:45:03 +01:00
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
resp, err := StartService(in)
2024-03-10 19:45:03 +01:00
return resp, err
}
2024-09-26 23:27:04 +02:00
func (s *CoreService) StartService(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
return StartService(in)
}
2024-09-26 23:27:04 +02:00
func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
2024-03-18 20:38:09 +01:00
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Starting Core Service")
2024-03-10 19:45:03 +01:00
content := in.ConfigContent
if content == "" {
2024-03-18 20:38:09 +01:00
activeConfigPath = in.ConfigPath
fileContent, err := os.ReadFile(activeConfigPath)
2024-03-10 19:45:03 +01:00
if err != nil {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
2024-03-10 19:45:03 +01:00
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_READING_CONFIG, err.Error())
2024-03-18 10:53:54 +01:00
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
return resp, err
2024-03-10 19:45:03 +01:00
}
content = string(fileContent)
}
2024-03-18 20:38:09 +01:00
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Parsing Config")
2024-08-06 22:45:01 -04:00
parsedContent, err := readOptions(content)
2024-03-18 20:38:09 +01:00
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Parsed")
2024-03-10 19:45:03 +01:00
if err != nil {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
2024-03-10 19:45:03 +01:00
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_PARSING_CONFIG, err.Error())
2024-03-18 10:53:54 +01:00
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
return resp, err
2024-03-10 19:45:03 +01:00
}
if !in.EnableRawConfig {
2024-03-18 20:38:09 +01:00
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Building config")
2024-09-26 23:27:04 +02:00
parsedContent_tmp, err := config.BuildConfig(*HiddifyOptions, 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())
2024-03-18 10:53:54 +01:00
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
return resp, err
}
2024-03-18 20:38:09 +01:00
parsedContent = *parsedContent_tmp
}
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Saving config")
currentBuildConfigPath := filepath.Join(sWorkingPath, "current-config.json")
config.SaveCurrentConfig(currentBuildConfigPath, parsedContent)
if activeConfigPath == "" {
activeConfigPath = currentBuildConfigPath
2024-03-10 19:45:03 +01:00
}
if in.EnableOldCommandServer {
2024-03-18 20:38:09 +01:00
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Starting Command Server")
2024-03-18 10:53:54 +01:00
err = startCommandServer()
if err != nil {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_COMMAND_SERVER, err.Error())
2024-03-18 10:53:54 +01:00
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
return resp, err
}
}
2024-03-10 19:45:03 +01:00
2024-03-18 20:38:09 +01:00
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Stating Service ")
instance, err := NewService(parsedContent)
2024-03-10 19:45:03 +01:00
if err != nil {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
2024-03-10 19:45:03 +01:00
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_CREATE_SERVICE, err.Error())
2024-03-18 10:53:54 +01:00
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
return resp, err
2024-03-10 19:45:03 +01:00
}
2024-03-18 20:38:09 +01:00
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Service.. started")
2024-03-10 19:45:03 +01:00
if in.DelayStart {
<-time.After(250 * time.Millisecond)
}
err = instance.Start()
if err != nil {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
2024-03-10 19:45:03 +01:00
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_SERVICE, err.Error())
2024-03-18 10:53:54 +01:00
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
return resp, err
2024-03-10 19:45:03 +01:00
}
Box = instance
if in.EnableOldCommandServer {
2024-03-18 10:53:54 +01:00
oldCommandServer.SetService(Box)
}
2024-03-10 19:45:03 +01:00
resp := SetCoreStatus(pb.CoreState_STARTED, pb.MessageType_EMPTY, "")
return resp, nil
2024-03-10 19:45:03 +01:00
}
func (s *CoreService) Parse(ctx context.Context, in *pb.ParseRequest) (*pb.ParseResponse, error) {
return Parse(in)
}
2024-09-26 23:27:04 +02:00
func Parse(in *pb.ParseRequest) (*pb.ParseResponse, error) {
2024-03-10 19:45:03 +01:00
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
}
}
2024-03-10 19:45:03 +01:00
2024-09-26 23:27:04 +02:00
config, err := config.ParseConfigContent(content, true, HiddifyOptions, false)
2024-03-10 19:45:03 +01:00
if err != nil {
return &pb.ParseResponse{
ResponseCode: pb.ResponseCode_FAILED,
Message: err.Error(),
}, err
}
if in.ConfigPath != "" {
2024-09-26 23:27:04 +02:00
err = os.WriteFile(in.ConfigPath, config, 0o644)
if err != nil {
return &pb.ParseResponse{
ResponseCode: pb.ResponseCode_FAILED,
Message: err.Error(),
}, err
}
}
2024-03-10 19:45:03 +01:00
return &pb.ParseResponse{
ResponseCode: pb.ResponseCode_OK,
Content: string(config),
Message: "",
}, err
}
func (s *CoreService) ChangeHiddifySettings(ctx context.Context, in *pb.ChangeHiddifySettingsRequest) (*pb.CoreInfoResponse, error) {
return ChangeHiddifySettings(in)
}
2024-03-10 19:45:03 +01:00
func ChangeHiddifySettings(in *pb.ChangeHiddifySettingsRequest) (*pb.CoreInfoResponse, error) {
HiddifyOptions = config.DefaultHiddifyOptions()
err := json.Unmarshal([]byte(in.HiddifySettingsJson), HiddifyOptions)
if err != nil {
return nil, err
}
2024-09-26 23:27:04 +02:00
if HiddifyOptions.Warp.WireguardConfigStr != "" {
err := json.Unmarshal([]byte(HiddifyOptions.Warp.WireguardConfigStr), &HiddifyOptions.Warp.WireguardConfig)
if err != nil {
return nil, err
}
}
2024-09-26 23:27:04 +02:00
if HiddifyOptions.Warp2.WireguardConfigStr != "" {
err := json.Unmarshal([]byte(HiddifyOptions.Warp2.WireguardConfigStr), &HiddifyOptions.Warp2.WireguardConfig)
if err != nil {
return nil, err
}
}
return &pb.CoreInfoResponse{}, nil
}
2024-09-26 23:27:04 +02:00
func (s *CoreService) GenerateConfig(ctx context.Context, in *pb.GenerateConfigRequest) (*pb.GenerateConfigResponse, error) {
return GenerateConfig(in)
}
2024-09-26 23:27:04 +02:00
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())
})
2024-09-26 23:27:04 +02:00
if HiddifyOptions == nil {
HiddifyOptions = config.DefaultHiddifyOptions()
2024-07-30 08:04:59 +02:00
}
2024-09-26 23:27:04 +02:00
config, err := generateConfigFromFile(in.Path, *HiddifyOptions)
if err != nil {
return nil, err
}
return &pb.GenerateConfigResponse{
ConfigContent: config,
}, nil
}
2024-09-26 23:27:04 +02:00
func generateConfigFromFile(path string, configOpt config.HiddifyOptions) (string, error) {
os.Chdir(filepath.Dir(path))
content, err := os.ReadFile(path)
if err != nil {
return "", err
}
2024-08-06 22:45:01 -04:00
options, err := readOptions(string(content))
if err != nil {
return "", err
}
config, err := config.BuildConfigJson(configOpt, options)
if err != nil {
return "", err
}
return config, nil
}
2024-03-10 19:45:03 +01:00
func (s *CoreService) Stop(ctx context.Context, empty *pb.Empty) (*pb.CoreInfoResponse, error) {
return Stop()
}
2024-09-26 23:27:04 +02:00
func Stop() (*pb.CoreInfoResponse, error) {
2024-03-10 19:45:03 +01:00
defer config.DeferPanicToError("stop", func(err error) {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
})
2024-03-10 19:45:03 +01:00
if CoreState != pb.CoreState_STARTED {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, "Core is not started")
return &pb.CoreInfoResponse{
CoreState: CoreState,
MessageType: pb.MessageType_INSTANCE_NOT_STARTED,
Message: "instance is not started",
}, fmt.Errorf("instance not started")
}
if Box == nil {
return &pb.CoreInfoResponse{
CoreState: CoreState,
MessageType: pb.MessageType_INSTANCE_NOT_FOUND,
Message: "instance is not found",
}, fmt.Errorf("instance not found")
}
SetCoreStatus(pb.CoreState_STOPPING, pb.MessageType_EMPTY, "")
config.DeactivateTunnelService()
2024-03-18 10:53:54 +01:00
if oldCommandServer != nil {
oldCommandServer.SetService(nil)
}
2024-03-10 19:45:03 +01:00
err := Box.Close()
if err != nil {
return &pb.CoreInfoResponse{
CoreState: CoreState,
MessageType: pb.MessageType_UNEXPECTED_ERROR,
Message: "Error while stopping the service.",
}, fmt.Errorf("Error while stopping the service.")
}
Box = nil
2024-03-18 10:53:54 +01:00
if oldCommandServer != nil {
err = oldCommandServer.Close()
if err != nil {
return &pb.CoreInfoResponse{
CoreState: CoreState,
MessageType: pb.MessageType_UNEXPECTED_ERROR,
Message: "Error while Closing the comand server.",
2024-03-18 10:53:54 +01:00
}, fmt.Errorf("error while Closing the comand server.")
}
2024-03-18 10:53:54 +01:00
oldCommandServer = nil
}
2024-03-10 19:45:03 +01:00
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_EMPTY, "")
return resp, nil
2024-03-10 19:45:03 +01:00
}
2024-09-26 23:27:04 +02:00
func (s *CoreService) Restart(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
return Restart(in)
}
2024-09-26 23:27:04 +02:00
func Restart(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
2024-03-10 19:45:03 +01:00
defer config.DeferPanicToError("restart", func(err error) {
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
})
log.Debug("[Service] Restarting")
if CoreState != pb.CoreState_STARTED {
return &pb.CoreInfoResponse{
CoreState: CoreState,
MessageType: pb.MessageType_INSTANCE_NOT_STARTED,
Message: "instance is not started",
}, fmt.Errorf("instance not started")
}
if Box == nil {
return &pb.CoreInfoResponse{
CoreState: CoreState,
MessageType: pb.MessageType_INSTANCE_NOT_FOUND,
Message: "instance is not found",
}, fmt.Errorf("instance not found")
}
resp, err := Stop()
2024-03-10 19:45:03 +01:00
if err != nil {
return resp, err
}
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
<-time.After(250 * time.Millisecond)
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
resp, gErr := StartService(in)
2024-03-10 19:45:03 +01:00
return resp, gErr
}