2023-08-16 15:16:02 +03:30
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
#include "stdint.h"
|
|
|
|
|
*/
|
|
|
|
|
import "C"
|
|
|
|
|
import (
|
2023-09-01 14:52:30 +03:30
|
|
|
"encoding/json"
|
2024-01-19 17:55:58 +03:30
|
|
|
"fmt"
|
2023-10-27 16:39:48 +03:30
|
|
|
"io"
|
2023-08-19 14:09:49 +03:30
|
|
|
"os"
|
2024-01-26 02:18:21 +01:00
|
|
|
"path/filepath"
|
2023-10-27 14:36:00 +03:30
|
|
|
"time"
|
2023-08-28 13:08:43 +03:30
|
|
|
"unsafe"
|
2023-08-19 14:09:49 +03:30
|
|
|
|
2023-08-28 13:08:43 +03:30
|
|
|
"github.com/hiddify/libcore/bridge"
|
2024-01-15 17:17:05 +03:30
|
|
|
"github.com/hiddify/libcore/config"
|
2024-03-03 04:15:19 +01:00
|
|
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
|
|
|
|
v2 "github.com/hiddify/libcore/v2"
|
|
|
|
|
|
2023-08-27 13:57:23 +03:30
|
|
|
"github.com/sagernet/sing-box/experimental/libbox"
|
2023-10-27 14:36:00 +03:30
|
|
|
"github.com/sagernet/sing-box/log"
|
2024-01-19 17:55:58 +03:30
|
|
|
"github.com/sagernet/sing-box/option"
|
2023-08-16 15:16:02 +03:30
|
|
|
)
|
|
|
|
|
|
2024-03-03 04:15:19 +01:00
|
|
|
// var v2.Box *libbox.BoxService
|
2024-01-15 17:17:05 +03:30
|
|
|
var configOptions *config.ConfigOptions
|
2023-09-10 20:18:33 +03:30
|
|
|
var activeConfigPath *string
|
2023-10-27 16:39:48 +03:30
|
|
|
var logFactory *log.Factory
|
2023-08-16 15:16:02 +03:30
|
|
|
|
2023-08-28 13:08:43 +03:30
|
|
|
//export setupOnce
|
|
|
|
|
func setupOnce(api unsafe.Pointer) {
|
|
|
|
|
bridge.InitializeDartApi(api)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-16 15:16:02 +03:30
|
|
|
//export setup
|
2023-10-27 16:39:48 +03:30
|
|
|
func setup(baseDir *C.char, workingDir *C.char, tempDir *C.char, statusPort C.longlong, debug bool) (CErr *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("setup", func(err error) {
|
2023-10-27 16:39:48 +03:30
|
|
|
CErr = C.CString(err.Error())
|
2024-01-30 00:42:52 +01:00
|
|
|
fmt.Printf("Error: %+v\n", err)
|
2023-10-27 16:39:48 +03:30
|
|
|
})
|
|
|
|
|
|
2023-08-16 15:16:02 +03:30
|
|
|
Setup(C.GoString(baseDir), C.GoString(workingDir), C.GoString(tempDir))
|
2023-09-10 20:18:33 +03:30
|
|
|
statusPropagationPort = int64(statusPort)
|
2023-10-27 16:39:48 +03:30
|
|
|
|
|
|
|
|
var defaultWriter io.Writer
|
|
|
|
|
if !debug {
|
|
|
|
|
defaultWriter = io.Discard
|
|
|
|
|
}
|
|
|
|
|
factory, err := log.New(
|
|
|
|
|
log.Options{
|
|
|
|
|
DefaultWriter: defaultWriter,
|
|
|
|
|
BaseTime: time.Now(),
|
|
|
|
|
Observable: false,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
|
|
|
|
logFactory = &factory
|
|
|
|
|
return C.CString("")
|
2023-08-16 15:16:02 +03:30
|
|
|
}
|
|
|
|
|
|
2023-08-19 14:09:49 +03:30
|
|
|
//export parse
|
2023-10-14 17:22:26 +03:30
|
|
|
func parse(path *C.char, tempPath *C.char, debug bool) (CErr *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("parse", func(err error) {
|
2023-10-14 17:22:26 +03:30
|
|
|
CErr = C.CString(err.Error())
|
|
|
|
|
})
|
|
|
|
|
|
2024-01-15 17:59:45 +03:30
|
|
|
config, err := config.ParseConfig(C.GoString(tempPath), debug)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
2024-01-29 21:55:01 +01:00
|
|
|
err = os.WriteFile(C.GoString(path), config, 0644)
|
2023-08-16 15:16:02 +03:30
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
|
|
|
|
return C.CString("")
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-01 14:52:30 +03:30
|
|
|
//export changeConfigOptions
|
2023-10-14 17:22:26 +03:30
|
|
|
func changeConfigOptions(configOptionsJson *C.char) (CErr *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("changeConfigOptions", func(err error) {
|
2023-10-14 17:22:26 +03:30
|
|
|
CErr = C.CString(err.Error())
|
|
|
|
|
})
|
|
|
|
|
|
2024-01-15 17:17:05 +03:30
|
|
|
configOptions = &config.ConfigOptions{}
|
2023-09-01 14:52:30 +03:30
|
|
|
err := json.Unmarshal([]byte(C.GoString(configOptionsJson)), configOptions)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
2024-02-21 19:51:49 +01:00
|
|
|
if configOptions.Warp.WireguardConfigStr != "" {
|
|
|
|
|
err := json.Unmarshal([]byte(configOptions.Warp.WireguardConfigStr), &configOptions.Warp.WireguardConfig)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-01 14:52:30 +03:30
|
|
|
return C.CString("")
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-12 12:50:14 +03:30
|
|
|
//export generateConfig
|
|
|
|
|
func generateConfig(path *C.char) (res *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("generateConfig", func(err error) {
|
2023-11-12 12:50:14 +03:30
|
|
|
res = C.CString("error" + err.Error())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
config, err := generateConfigFromFile(C.GoString(path), *configOptions)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return C.CString("error" + err.Error())
|
|
|
|
|
}
|
|
|
|
|
return C.CString(config)
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-15 17:17:05 +03:30
|
|
|
func generateConfigFromFile(path string, configOpt config.ConfigOptions) (string, error) {
|
2024-01-26 02:18:21 +01:00
|
|
|
os.Chdir(filepath.Dir(path))
|
2023-11-12 12:50:14 +03:30
|
|
|
content, err := os.ReadFile(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
options, err := parseConfig(string(content))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
2024-01-15 17:17:05 +03:30
|
|
|
config, err := config.BuildConfigJson(configOpt, options)
|
2023-11-12 12:50:14 +03:30
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
return config, nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-10 20:18:33 +03:30
|
|
|
//export start
|
2023-10-26 15:12:56 +03:30
|
|
|
func start(configPath *C.char, disableMemoryLimit bool) (CErr *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("start", func(err error) {
|
2024-02-06 11:27:57 +01:00
|
|
|
stopAndAlert("Unexpected Error!", err)
|
2024-02-13 16:52:58 +01:00
|
|
|
CErr = C.CString(err.Error())
|
2023-10-14 17:22:26 +03:30
|
|
|
})
|
|
|
|
|
|
2024-03-03 04:15:19 +01:00
|
|
|
if v2.CoreState != pb.CoreState_STOPPED {
|
2023-09-10 20:18:33 +03:30
|
|
|
return C.CString("")
|
|
|
|
|
}
|
2024-03-03 04:15:19 +01:00
|
|
|
propagateStatus(pb.CoreState_STARTING)
|
2023-09-10 20:18:33 +03:30
|
|
|
|
2023-08-16 15:16:02 +03:30
|
|
|
path := C.GoString(configPath)
|
2023-09-10 20:18:33 +03:30
|
|
|
activeConfigPath = &path
|
2023-10-26 15:12:56 +03:30
|
|
|
|
|
|
|
|
libbox.SetMemoryLimit(!disableMemoryLimit)
|
2023-10-27 14:36:00 +03:30
|
|
|
err := startService(false)
|
2023-08-19 14:09:49 +03:30
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
2023-09-10 20:18:33 +03:30
|
|
|
return C.CString("")
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-27 14:36:00 +03:30
|
|
|
func startService(delayStart bool) error {
|
2023-09-10 20:18:33 +03:30
|
|
|
content, err := os.ReadFile(*activeConfigPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return stopAndAlert(EmptyConfiguration, err)
|
|
|
|
|
}
|
2023-08-19 14:09:49 +03:30
|
|
|
options, err := parseConfig(string(content))
|
2023-08-16 15:16:02 +03:30
|
|
|
if err != nil {
|
2023-09-10 20:18:33 +03:30
|
|
|
return stopAndAlert(EmptyConfiguration, err)
|
2023-08-16 15:16:02 +03:30
|
|
|
}
|
2024-01-26 02:18:21 +01:00
|
|
|
os.Chdir(filepath.Dir(*activeConfigPath))
|
2024-01-19 17:55:58 +03:30
|
|
|
var patchedOptions *option.Options
|
|
|
|
|
patchedOptions, err = config.BuildConfig(*configOptions, options)
|
|
|
|
|
if err != nil {
|
2024-02-06 11:27:57 +01:00
|
|
|
return stopAndAlert("Error Building Config", err)
|
2024-01-19 17:55:58 +03:30
|
|
|
}
|
2023-08-22 00:54:58 +03:30
|
|
|
|
2024-02-05 18:47:26 +01:00
|
|
|
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "current-config.json"), *patchedOptions)
|
2023-08-16 15:16:02 +03:30
|
|
|
|
2023-10-27 16:39:48 +03:30
|
|
|
err = startCommandServer(*logFactory)
|
2023-08-28 13:08:43 +03:30
|
|
|
if err != nil {
|
2023-09-10 20:18:33 +03:30
|
|
|
return stopAndAlert(StartCommandServer, err)
|
2023-08-28 13:08:43 +03:30
|
|
|
}
|
|
|
|
|
|
2024-01-19 17:55:58 +03:30
|
|
|
instance, err := NewService(*patchedOptions)
|
2023-08-16 15:16:02 +03:30
|
|
|
if err != nil {
|
2023-09-10 20:18:33 +03:30
|
|
|
return stopAndAlert(CreateService, err)
|
2023-08-16 15:16:02 +03:30
|
|
|
}
|
2023-10-27 14:36:00 +03:30
|
|
|
|
|
|
|
|
if delayStart {
|
|
|
|
|
time.Sleep(250 * time.Millisecond)
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-10 20:18:33 +03:30
|
|
|
err = instance.Start()
|
2023-08-28 13:08:43 +03:30
|
|
|
if err != nil {
|
2023-09-10 20:18:33 +03:30
|
|
|
return stopAndAlert(StartService, err)
|
2023-08-16 15:16:02 +03:30
|
|
|
}
|
2024-03-03 04:15:19 +01:00
|
|
|
v2.Box = instance
|
|
|
|
|
commandServer.SetService(v2.Box)
|
2023-08-16 15:16:02 +03:30
|
|
|
|
2024-03-03 04:15:19 +01:00
|
|
|
propagateStatus(pb.CoreState_STARTED)
|
2023-09-10 20:18:33 +03:30
|
|
|
return nil
|
2023-08-16 15:16:02 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//export stop
|
2023-10-14 17:22:26 +03:30
|
|
|
func stop() (CErr *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("stop", func(err error) {
|
2024-02-13 16:52:58 +01:00
|
|
|
stopAndAlert("Unexpected Error in Stop!", err)
|
2023-10-14 17:22:26 +03:30
|
|
|
CErr = C.CString(err.Error())
|
|
|
|
|
})
|
2024-03-09 21:07:15 +01:00
|
|
|
|
2024-03-03 04:15:19 +01:00
|
|
|
if v2.CoreState != pb.CoreState_STARTED {
|
2024-02-13 16:52:58 +01:00
|
|
|
stopAndAlert("Already Stopped", nil)
|
2023-09-10 20:18:33 +03:30
|
|
|
return C.CString("")
|
|
|
|
|
}
|
2024-03-03 04:15:19 +01:00
|
|
|
if v2.Box == nil {
|
2023-08-16 15:16:02 +03:30
|
|
|
return C.CString("instance not found")
|
|
|
|
|
}
|
2024-03-03 04:15:19 +01:00
|
|
|
propagateStatus(pb.CoreState_STOPPING)
|
2024-03-09 21:07:15 +01:00
|
|
|
config.DeactivateTunnelService()
|
2023-08-28 13:08:43 +03:30
|
|
|
commandServer.SetService(nil)
|
2024-02-13 16:52:58 +01:00
|
|
|
|
2024-03-03 04:15:19 +01:00
|
|
|
err := v2.Box.Close()
|
2023-08-16 15:16:02 +03:30
|
|
|
if err != nil {
|
2024-02-13 16:52:58 +01:00
|
|
|
stopAndAlert("Unexpected Error in Close!", err)
|
2023-08-16 15:16:02 +03:30
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
2024-03-03 04:15:19 +01:00
|
|
|
v2.Box = nil
|
2023-08-28 13:08:43 +03:30
|
|
|
err = commandServer.Close()
|
|
|
|
|
if err != nil {
|
2024-02-13 16:52:58 +01:00
|
|
|
stopAndAlert("Unexpected Error in Stop CommandServer/!", err)
|
2023-08-28 13:08:43 +03:30
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
|
|
|
|
commandServer = nil
|
2024-03-03 04:15:19 +01:00
|
|
|
propagateStatus(pb.CoreState_STOPPED)
|
2023-09-10 20:18:33 +03:30
|
|
|
return C.CString("")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//export restart
|
2023-10-26 15:12:56 +03:30
|
|
|
func restart(configPath *C.char, disableMemoryLimit bool) (CErr *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("restart", func(err error) {
|
2024-02-06 11:27:57 +01:00
|
|
|
stopAndAlert("Unexpected Error!", err)
|
2024-02-13 16:52:58 +01:00
|
|
|
CErr = C.CString(err.Error())
|
2023-10-14 17:22:26 +03:30
|
|
|
})
|
2023-10-27 14:36:00 +03:30
|
|
|
log.Debug("[Service] Restarting")
|
2023-10-14 17:22:26 +03:30
|
|
|
|
2024-03-03 04:15:19 +01:00
|
|
|
if v2.CoreState != pb.CoreState_STARTED {
|
2023-09-10 20:18:33 +03:30
|
|
|
return C.CString("")
|
|
|
|
|
}
|
2024-03-03 04:15:19 +01:00
|
|
|
if v2.Box == nil {
|
2023-09-10 20:18:33 +03:30
|
|
|
return C.CString("instance not found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := stop()
|
|
|
|
|
if C.GoString(err) != "" {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2023-10-27 14:36:00 +03:30
|
|
|
|
2024-03-03 04:15:19 +01:00
|
|
|
propagateStatus(pb.CoreState_STARTING)
|
2023-10-27 17:33:24 +03:30
|
|
|
|
2023-10-27 14:36:00 +03:30
|
|
|
time.Sleep(250 * time.Millisecond)
|
|
|
|
|
|
2023-10-27 17:33:24 +03:30
|
|
|
path := C.GoString(configPath)
|
|
|
|
|
activeConfigPath = &path
|
|
|
|
|
libbox.SetMemoryLimit(!disableMemoryLimit)
|
|
|
|
|
gErr := startService(false)
|
|
|
|
|
if gErr != nil {
|
|
|
|
|
return C.CString(gErr.Error())
|
2023-09-10 20:18:33 +03:30
|
|
|
}
|
2023-08-28 13:08:43 +03:30
|
|
|
return C.CString("")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//export startCommandClient
|
|
|
|
|
func startCommandClient(command C.int, port C.longlong) *C.char {
|
2023-10-27 16:39:48 +03:30
|
|
|
err := StartCommand(int32(command), int64(port), *logFactory)
|
2023-08-28 13:08:43 +03:30
|
|
|
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())
|
|
|
|
|
}
|
2023-08-16 15:16:02 +03:30
|
|
|
return C.CString("")
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-29 19:10:14 +03:30
|
|
|
//export selectOutbound
|
2023-10-14 17:22:26 +03:30
|
|
|
func selectOutbound(groupTag *C.char, outboundTag *C.char) (CErr *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("selectOutbound", func(err error) {
|
2023-10-14 17:22:26 +03:30
|
|
|
CErr = C.CString(err.Error())
|
|
|
|
|
})
|
|
|
|
|
|
2023-08-29 19:10:14 +03:30
|
|
|
err := libbox.NewStandaloneCommandClient().SelectOutbound(C.GoString(groupTag), C.GoString(outboundTag))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
|
|
|
|
return C.CString("")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//export urlTest
|
2023-10-14 17:22:26 +03:30
|
|
|
func urlTest(groupTag *C.char) (CErr *C.char) {
|
2024-01-15 17:17:05 +03:30
|
|
|
defer config.DeferPanicToError("urlTest", func(err error) {
|
2023-10-14 17:22:26 +03:30
|
|
|
CErr = C.CString(err.Error())
|
|
|
|
|
})
|
|
|
|
|
|
2023-08-29 19:10:14 +03:30
|
|
|
err := libbox.NewStandaloneCommandClient().URLTest(C.GoString(groupTag))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(err.Error())
|
|
|
|
|
}
|
|
|
|
|
return C.CString("")
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-18 12:31:17 +03:30
|
|
|
//export generateWarpConfig
|
|
|
|
|
func generateWarpConfig(licenseKey *C.char, accountId *C.char, accessToken *C.char) (CResp *C.char) {
|
|
|
|
|
defer config.DeferPanicToError("generateWarpConfig", func(err error) {
|
|
|
|
|
CResp = C.CString(fmt.Sprint("error: ", err.Error()))
|
|
|
|
|
})
|
|
|
|
|
account, err := config.GenerateWarpAccount(C.GoString(licenseKey), C.GoString(accountId), C.GoString(accessToken))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return C.CString(fmt.Sprint("error: ", err.Error()))
|
|
|
|
|
}
|
|
|
|
|
return C.CString(account)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-16 15:16:02 +03:30
|
|
|
func main() {}
|