release: version 0.17.7
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
//go:build !cgo
|
//go:build !cgo
|
||||||
// +build !cgo
|
// +build !cgo
|
||||||
|
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
func InitializeDartApi(api unsafe.Pointer) {
|
func InitializeDartApi(api unsafe.Pointer) {
|
||||||
}
|
}
|
||||||
func SendStringToPort(port int64, msg string) {
|
func SendStringToPort(port int64, msg string) {
|
||||||
}
|
}
|
||||||
|
|||||||
22
cli/main.go
22
cli/main.go
@@ -1,11 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/hiddify/libcore/cmd"
|
"github.com/hiddify/libcore/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cmd.ParseCli(os.Args[1:])
|
cmd.ParseCli(os.Args[1:])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/hiddify/libcore/cmd"
|
"github.com/hiddify/libcore/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
//export parseCli
|
//export parseCli
|
||||||
func parseCli(argc C.int, argv **C.char) *C.char {
|
func parseCli(argc C.int, argv **C.char) *C.char {
|
||||||
args := make([]string, argc)
|
args := make([]string, argc)
|
||||||
for i := 0; i < int(argc); i++ {
|
for i := 0; i < int(argc); i++ {
|
||||||
// fmt.Println("parseCli", C.GoString(*argv))
|
// fmt.Println("parseCli", C.GoString(*argv))
|
||||||
args[i] = C.GoString(*argv)
|
args[i] = C.GoString(*argv)
|
||||||
argv = (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + uintptr(unsafe.Sizeof(*argv))))
|
argv = (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + uintptr(unsafe.Sizeof(*argv))))
|
||||||
}
|
}
|
||||||
err := cmd.ParseCli(args[1:])
|
err := cmd.ParseCli(args[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return C.CString(err.Error())
|
return C.CString(err.Error())
|
||||||
}
|
}
|
||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,223 +1,223 @@
|
|||||||
package global
|
package global
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hiddify/libcore/config"
|
"github.com/hiddify/libcore/config"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RunStandalone(hiddifySettingPath string, configPath string) error {
|
func RunStandalone(hiddifySettingPath string, configPath string) error {
|
||||||
fmt.Println("Running in standalone mode")
|
fmt.Println("Running in standalone mode")
|
||||||
current, err := readAndBuildConfig(hiddifySettingPath, configPath)
|
current, err := readAndBuildConfig(hiddifySettingPath, configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error in read and build config %v", err)
|
fmt.Printf("Error in read and build config %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go StartServiceC(false, current.Config)
|
go StartServiceC(false, current.Config)
|
||||||
go updateConfigInterval(current, hiddifySettingPath, configPath)
|
go updateConfigInterval(current, hiddifySettingPath, configPath)
|
||||||
fmt.Printf("Press CTRL+C to stop\n")
|
fmt.Printf("Press CTRL+C to stop\n")
|
||||||
fmt.Printf("Open http://localhost:6756/?secret=hiddify in your browser\n")
|
fmt.Printf("Open http://localhost:6756/?secret=hiddify in your browser\n")
|
||||||
sigChan := make(chan os.Signal, 1)
|
sigChan := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
<-sigChan
|
<-sigChan
|
||||||
err = StopServiceC()
|
err = StopServiceC()
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigResult struct {
|
type ConfigResult struct {
|
||||||
Config string
|
Config string
|
||||||
RefreshInterval int
|
RefreshInterval int
|
||||||
}
|
}
|
||||||
|
|
||||||
func readAndBuildConfig(hiddifySettingPath string, configPath string) (ConfigResult, error) {
|
func readAndBuildConfig(hiddifySettingPath string, configPath string) (ConfigResult, error) {
|
||||||
var result ConfigResult
|
var result ConfigResult
|
||||||
|
|
||||||
result, err := readConfigContent(configPath)
|
result, err := readConfigContent(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
hiddifyconfig := config.DefaultConfigOptions()
|
hiddifyconfig := config.DefaultConfigOptions()
|
||||||
if hiddifySettingPath != "" {
|
if hiddifySettingPath != "" {
|
||||||
hiddifyconfig, err = readConfigOptionsAt(hiddifySettingPath)
|
hiddifyconfig, err = readConfigOptionsAt(hiddifySettingPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.Config, err = buildConfig(result.Config, *hiddifyconfig)
|
result.Config, err = buildConfig(result.Config, *hiddifyconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readConfigContent(configPath string) (ConfigResult, error) {
|
func readConfigContent(configPath string) (ConfigResult, error) {
|
||||||
var content string
|
var content string
|
||||||
var refreshInterval int
|
var refreshInterval int
|
||||||
|
|
||||||
if strings.HasPrefix(configPath, "http://") || strings.HasPrefix(configPath, "https://") {
|
if strings.HasPrefix(configPath, "http://") || strings.HasPrefix(configPath, "https://") {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
|
||||||
// Create a new request
|
// Create a new request
|
||||||
req, err := http.NewRequest("GET", configPath, nil)
|
req, err := http.NewRequest("GET", configPath, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error creating request:", err)
|
fmt.Println("Error creating request:", err)
|
||||||
return ConfigResult{}, err
|
return ConfigResult{}, err
|
||||||
}
|
}
|
||||||
req.Header.Set("User-Agent", "HiddifyNext/17.5.0 ("+runtime.GOOS+") like ClashMeta v2ray sing-box")
|
req.Header.Set("User-Agent", "HiddifyNext/17.5.0 ("+runtime.GOOS+") like ClashMeta v2ray sing-box")
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error making GET request:", err)
|
fmt.Println("Error making GET request:", err)
|
||||||
return ConfigResult{}, err
|
return ConfigResult{}, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigResult{}, fmt.Errorf("failed to read config body: %w", err)
|
return ConfigResult{}, fmt.Errorf("failed to read config body: %w", err)
|
||||||
}
|
}
|
||||||
content = string(body)
|
content = string(body)
|
||||||
refreshInterval, _ = extractRefreshInterval(resp.Header, content)
|
refreshInterval, _ = extractRefreshInterval(resp.Header, content)
|
||||||
fmt.Printf("Refresh interval: %d\n", refreshInterval)
|
fmt.Printf("Refresh interval: %d\n", refreshInterval)
|
||||||
} else {
|
} else {
|
||||||
data, err := ioutil.ReadFile(configPath)
|
data, err := ioutil.ReadFile(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigResult{}, fmt.Errorf("failed to read config file: %w", err)
|
return ConfigResult{}, fmt.Errorf("failed to read config file: %w", err)
|
||||||
}
|
}
|
||||||
content = string(data)
|
content = string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConfigResult{
|
return ConfigResult{
|
||||||
Config: content,
|
Config: content,
|
||||||
RefreshInterval: refreshInterval,
|
RefreshInterval: refreshInterval,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractRefreshInterval(header http.Header, bodyStr string) (int, error) {
|
func extractRefreshInterval(header http.Header, bodyStr string) (int, error) {
|
||||||
refreshIntervalStr := header.Get("profile-update-interval")
|
refreshIntervalStr := header.Get("profile-update-interval")
|
||||||
if refreshIntervalStr != "" {
|
if refreshIntervalStr != "" {
|
||||||
refreshInterval, err := strconv.Atoi(refreshIntervalStr)
|
refreshInterval, err := strconv.Atoi(refreshIntervalStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("failed to parse refresh interval from header: %w", err)
|
return 0, fmt.Errorf("failed to parse refresh interval from header: %w", err)
|
||||||
}
|
}
|
||||||
return refreshInterval, nil
|
return refreshInterval, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(bodyStr, "\n")
|
lines := strings.Split(bodyStr, "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
if strings.HasPrefix(line, "//profile-update-interval:") || strings.HasPrefix(line, "#profile-update-interval:") {
|
if strings.HasPrefix(line, "//profile-update-interval:") || strings.HasPrefix(line, "#profile-update-interval:") {
|
||||||
parts := strings.SplitN(line, ":", 2)
|
parts := strings.SplitN(line, ":", 2)
|
||||||
str := strings.TrimSpace(parts[1])
|
str := strings.TrimSpace(parts[1])
|
||||||
refreshInterval, err := strconv.Atoi(str)
|
refreshInterval, err := strconv.Atoi(str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("failed to parse refresh interval from body: %w", err)
|
return 0, fmt.Errorf("failed to parse refresh interval from body: %w", err)
|
||||||
}
|
}
|
||||||
return refreshInterval, nil
|
return refreshInterval, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
func buildConfig(configContent string, options config.ConfigOptions) (string, error) {
|
func buildConfig(configContent string, options config.ConfigOptions) (string, error) {
|
||||||
parsedContent, err := config.ParseConfigContent(configContent, true)
|
parsedContent, err := config.ParseConfigContent(configContent, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to parse config content: %w", err)
|
return "", fmt.Errorf("failed to parse config content: %w", err)
|
||||||
}
|
}
|
||||||
singconfigs, err := readConfigBytes([]byte(parsedContent))
|
singconfigs, err := readConfigBytes([]byte(parsedContent))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
finalconfig, err := config.BuildConfig(options, *singconfigs)
|
finalconfig, err := config.BuildConfig(options, *singconfigs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to build config: %w", err)
|
return "", fmt.Errorf("failed to build config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
finalconfig.Log.Output = ""
|
finalconfig.Log.Output = ""
|
||||||
finalconfig.Experimental.ClashAPI.ExternalUI = "webui"
|
finalconfig.Experimental.ClashAPI.ExternalUI = "webui"
|
||||||
if options.AllowConnectionFromLAN {
|
if options.AllowConnectionFromLAN {
|
||||||
finalconfig.Experimental.ClashAPI.ExternalController = "0.0.0.0:6756"
|
finalconfig.Experimental.ClashAPI.ExternalController = "0.0.0.0:6756"
|
||||||
} else {
|
} else {
|
||||||
finalconfig.Experimental.ClashAPI.ExternalController = "127.0.0.1:6756"
|
finalconfig.Experimental.ClashAPI.ExternalController = "127.0.0.1:6756"
|
||||||
}
|
}
|
||||||
|
|
||||||
if finalconfig.Experimental.ClashAPI.Secret == "" {
|
if finalconfig.Experimental.ClashAPI.Secret == "" {
|
||||||
// finalconfig.Experimental.ClashAPI.Secret = "hiddify"
|
// finalconfig.Experimental.ClashAPI.Secret = "hiddify"
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := SetupC("./", "./", "./tmp", false); err != nil {
|
if err := SetupC("./", "./", "./tmp", false); err != nil {
|
||||||
return "", fmt.Errorf("failed to set up global configuration: %w", err)
|
return "", fmt.Errorf("failed to set up global configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
configStr, err := config.ToJson(*finalconfig)
|
configStr, err := config.ToJson(*finalconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to convert config to JSON: %w", err)
|
return "", fmt.Errorf("failed to convert config to JSON: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return configStr, nil
|
return configStr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateConfigInterval(current ConfigResult, hiddifySettingPath string, configPath string) {
|
func updateConfigInterval(current ConfigResult, hiddifySettingPath string, configPath string) {
|
||||||
if current.RefreshInterval <= 0 {
|
if current.RefreshInterval <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
<-time.After(time.Duration(current.RefreshInterval) * time.Hour)
|
<-time.After(time.Duration(current.RefreshInterval) * time.Hour)
|
||||||
new, err := readAndBuildConfig(hiddifySettingPath, configPath)
|
new, err := readAndBuildConfig(hiddifySettingPath, configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if new.Config != current.Config {
|
if new.Config != current.Config {
|
||||||
go StopServiceC()
|
go StopServiceC()
|
||||||
go StartServiceC(false, new.Config)
|
go StartServiceC(false, new.Config)
|
||||||
}
|
}
|
||||||
current = new
|
current = new
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readConfigBytes(content []byte) (*option.Options, error) {
|
func readConfigBytes(content []byte) (*option.Options, error) {
|
||||||
var options option.Options
|
var options option.Options
|
||||||
err := options.UnmarshalJSON(content)
|
err := options.UnmarshalJSON(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &options, nil
|
return &options, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readConfigOptionsAt(path string) (*config.ConfigOptions, error) {
|
func readConfigOptionsAt(path string) (*config.ConfigOptions, error) {
|
||||||
content, err := os.ReadFile(path)
|
content, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var options config.ConfigOptions
|
var options config.ConfigOptions
|
||||||
err = json.Unmarshal(content, &options)
|
err = json.Unmarshal(content, &options)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if options.Warp.WireguardConfigStr != "" {
|
if options.Warp.WireguardConfigStr != "" {
|
||||||
err := json.Unmarshal([]byte(options.Warp.WireguardConfigStr), &options.Warp.WireguardConfig)
|
err := json.Unmarshal([]byte(options.Warp.WireguardConfigStr), &options.Warp.WireguardConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &options, nil
|
return &options, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,214 +1,214 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package hiddifyrpc;
|
package hiddifyrpc;
|
||||||
|
|
||||||
option go_package = "./hiddifyrpc";
|
option go_package = "./hiddifyrpc";
|
||||||
|
|
||||||
enum ResponseCode {
|
enum ResponseCode {
|
||||||
OK = 0;
|
OK = 0;
|
||||||
FAILED = 1;
|
FAILED = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CoreState {
|
enum CoreState {
|
||||||
STOPPED = 0;
|
STOPPED = 0;
|
||||||
STARTING = 1;
|
STARTING = 1;
|
||||||
STARTED = 2;
|
STARTED = 2;
|
||||||
STOPPING = 3;
|
STOPPING = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MessageType {
|
enum MessageType {
|
||||||
EMPTY=0;
|
EMPTY=0;
|
||||||
EMPTY_CONFIGURATION = 1;
|
EMPTY_CONFIGURATION = 1;
|
||||||
START_COMMAND_SERVER = 2;
|
START_COMMAND_SERVER = 2;
|
||||||
CREATE_SERVICE = 3;
|
CREATE_SERVICE = 3;
|
||||||
START_SERVICE = 4;
|
START_SERVICE = 4;
|
||||||
UNEXPECTED_ERROR = 5;
|
UNEXPECTED_ERROR = 5;
|
||||||
ALREADY_STARTED = 6;
|
ALREADY_STARTED = 6;
|
||||||
ALREADY_STOPPED = 7;
|
ALREADY_STOPPED = 7;
|
||||||
INSTANCE_NOT_FOUND = 8;
|
INSTANCE_NOT_FOUND = 8;
|
||||||
INSTANCE_NOT_STOPPED = 9;
|
INSTANCE_NOT_STOPPED = 9;
|
||||||
INSTANCE_NOT_STARTED = 10;
|
INSTANCE_NOT_STARTED = 10;
|
||||||
ERROR_BUILDING_CONFIG = 11;
|
ERROR_BUILDING_CONFIG = 11;
|
||||||
ERROR_PARSING_CONFIG = 12;
|
ERROR_PARSING_CONFIG = 12;
|
||||||
ERROR_READING_CONFIG = 13;
|
ERROR_READING_CONFIG = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CoreInfoResponse {
|
message CoreInfoResponse {
|
||||||
CoreState core_state = 1;
|
CoreState core_state = 1;
|
||||||
MessageType message_type = 2;
|
MessageType message_type = 2;
|
||||||
string message = 3;
|
string message = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message StartRequest {
|
message StartRequest {
|
||||||
string config_path = 1;
|
string config_path = 1;
|
||||||
string config_content = 2; // Optional if configPath is not provided.
|
string config_content = 2; // Optional if configPath is not provided.
|
||||||
bool disable_memory_limit = 3;
|
bool disable_memory_limit = 3;
|
||||||
bool delay_start = 4;
|
bool delay_start = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetupRequest {
|
message SetupRequest {
|
||||||
string base_path = 1;
|
string base_path = 1;
|
||||||
string working_path = 2;
|
string working_path = 2;
|
||||||
string temp_path = 3;
|
string temp_path = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Response {
|
message Response {
|
||||||
ResponseCode response_code = 1;
|
ResponseCode response_code = 1;
|
||||||
string message = 2;
|
string message = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
message HelloRequest {
|
message HelloRequest {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HelloResponse {
|
message HelloResponse {
|
||||||
string message = 1;
|
string message = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Empty {
|
message Empty {
|
||||||
}
|
}
|
||||||
|
|
||||||
message SystemInfo {
|
message SystemInfo {
|
||||||
int64 memory = 1;
|
int64 memory = 1;
|
||||||
int32 goroutines = 2;
|
int32 goroutines = 2;
|
||||||
int32 connections_in = 3;
|
int32 connections_in = 3;
|
||||||
int32 connections_out = 4;
|
int32 connections_out = 4;
|
||||||
bool traffic_available = 5;
|
bool traffic_available = 5;
|
||||||
int64 uplink = 6;
|
int64 uplink = 6;
|
||||||
int64 downlink = 7;
|
int64 downlink = 7;
|
||||||
int64 uplink_total = 8;
|
int64 uplink_total = 8;
|
||||||
int64 downlink_total = 9;
|
int64 downlink_total = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OutboundGroupItem {
|
message OutboundGroupItem {
|
||||||
string tag = 1;
|
string tag = 1;
|
||||||
string type = 2;
|
string type = 2;
|
||||||
int64 url_test_time = 3;
|
int64 url_test_time = 3;
|
||||||
int32 url_test_delay = 4;
|
int32 url_test_delay = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OutboundGroup {
|
message OutboundGroup {
|
||||||
string tag = 1;
|
string tag = 1;
|
||||||
string type = 2;
|
string type = 2;
|
||||||
string selected=3;
|
string selected=3;
|
||||||
repeated OutboundGroupItem items = 4;
|
repeated OutboundGroupItem items = 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
message OutboundGroupList{
|
message OutboundGroupList{
|
||||||
repeated OutboundGroup items = 1;
|
repeated OutboundGroup items = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message WarpAccount {
|
message WarpAccount {
|
||||||
string account_id = 1;
|
string account_id = 1;
|
||||||
string access_token = 2;
|
string access_token = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message WarpWireguardConfig {
|
message WarpWireguardConfig {
|
||||||
string private_key = 1;
|
string private_key = 1;
|
||||||
string local_address_ipv4 = 2;
|
string local_address_ipv4 = 2;
|
||||||
string local_address_ipv6 = 3;
|
string local_address_ipv6 = 3;
|
||||||
string peer_public_key = 4;
|
string peer_public_key = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message WarpGenerationResponse {
|
message WarpGenerationResponse {
|
||||||
WarpAccount account = 1;
|
WarpAccount account = 1;
|
||||||
string log = 2;
|
string log = 2;
|
||||||
WarpWireguardConfig config = 3;
|
WarpWireguardConfig config = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SystemProxyStatus {
|
message SystemProxyStatus {
|
||||||
bool available = 1;
|
bool available = 1;
|
||||||
bool enabled = 2;
|
bool enabled = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ParseRequest {
|
message ParseRequest {
|
||||||
string content = 1;
|
string content = 1;
|
||||||
bool debug = 2;
|
bool debug = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ParseResponse {
|
message ParseResponse {
|
||||||
ResponseCode response_code = 1;
|
ResponseCode response_code = 1;
|
||||||
string content = 2;
|
string content = 2;
|
||||||
string message = 3;
|
string message = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ChangeConfigOptionsRequest {
|
message ChangeConfigOptionsRequest {
|
||||||
string config_options_json = 1;
|
string config_options_json = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GenerateConfigRequest {
|
message GenerateConfigRequest {
|
||||||
string path = 1;
|
string path = 1;
|
||||||
string temp_path = 2;
|
string temp_path = 2;
|
||||||
bool debug = 3;
|
bool debug = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GenerateConfigResponse {
|
message GenerateConfigResponse {
|
||||||
string config_content = 1;
|
string config_content = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
message SelectOutboundRequest {
|
message SelectOutboundRequest {
|
||||||
string group_tag = 1;
|
string group_tag = 1;
|
||||||
string outbound_tag = 2;
|
string outbound_tag = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UrlTestRequest {
|
message UrlTestRequest {
|
||||||
string group_tag = 1;
|
string group_tag = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GenerateWarpConfigRequest {
|
message GenerateWarpConfigRequest {
|
||||||
string license_key = 1;
|
string license_key = 1;
|
||||||
string account_id = 2;
|
string account_id = 2;
|
||||||
string access_token = 3;
|
string access_token = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetSystemProxyEnabledRequest {
|
message SetSystemProxyEnabledRequest {
|
||||||
bool is_enabled = 1;
|
bool is_enabled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LogLevel {
|
enum LogLevel {
|
||||||
DEBUG = 0;
|
DEBUG = 0;
|
||||||
INFO = 1;
|
INFO = 1;
|
||||||
WARNING = 2;
|
WARNING = 2;
|
||||||
ERROR = 3;
|
ERROR = 3;
|
||||||
FATAL = 4;
|
FATAL = 4;
|
||||||
}
|
}
|
||||||
enum LogType {
|
enum LogType {
|
||||||
CORE = 0;
|
CORE = 0;
|
||||||
SERVICE = 1;
|
SERVICE = 1;
|
||||||
CONFIG = 2;
|
CONFIG = 2;
|
||||||
}
|
}
|
||||||
message LogMessage {
|
message LogMessage {
|
||||||
LogLevel level = 1;
|
LogLevel level = 1;
|
||||||
LogType type = 2;
|
LogType type = 2;
|
||||||
string message = 3;
|
string message = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message StopRequest{
|
message StopRequest{
|
||||||
}
|
}
|
||||||
|
|
||||||
service Hiddify {
|
service Hiddify {
|
||||||
rpc SayHello (HelloRequest) returns (HelloResponse);
|
rpc SayHello (HelloRequest) returns (HelloResponse);
|
||||||
rpc SayHelloStream (stream HelloRequest) returns (stream HelloResponse);
|
rpc SayHelloStream (stream HelloRequest) returns (stream HelloResponse);
|
||||||
rpc Start (StartRequest) returns (CoreInfoResponse);
|
rpc Start (StartRequest) returns (CoreInfoResponse);
|
||||||
rpc CoreInfoListener (stream StopRequest) returns (stream CoreInfoResponse);
|
rpc CoreInfoListener (stream StopRequest) returns (stream CoreInfoResponse);
|
||||||
rpc OutboundsInfo (stream StopRequest) returns (stream OutboundGroupList);
|
rpc OutboundsInfo (stream StopRequest) returns (stream OutboundGroupList);
|
||||||
rpc MainOutboundsInfo (stream StopRequest) returns (stream OutboundGroupList);
|
rpc MainOutboundsInfo (stream StopRequest) returns (stream OutboundGroupList);
|
||||||
rpc GetSystemInfo (stream StopRequest) returns (stream SystemInfo);
|
rpc GetSystemInfo (stream StopRequest) returns (stream SystemInfo);
|
||||||
rpc Setup (SetupRequest) returns (Response);
|
rpc Setup (SetupRequest) returns (Response);
|
||||||
rpc Parse (ParseRequest) returns (ParseResponse);
|
rpc Parse (ParseRequest) returns (ParseResponse);
|
||||||
//rpc ChangeConfigOptions (ChangeConfigOptionsRequest) returns (CoreInfoResponse);
|
//rpc ChangeConfigOptions (ChangeConfigOptionsRequest) returns (CoreInfoResponse);
|
||||||
//rpc GenerateConfig (GenerateConfigRequest) returns (GenerateConfigResponse);
|
//rpc GenerateConfig (GenerateConfigRequest) returns (GenerateConfigResponse);
|
||||||
rpc StartService (StartRequest) returns (CoreInfoResponse);
|
rpc StartService (StartRequest) returns (CoreInfoResponse);
|
||||||
rpc Stop (Empty) returns (CoreInfoResponse);
|
rpc Stop (Empty) returns (CoreInfoResponse);
|
||||||
rpc Restart (StartRequest) returns (CoreInfoResponse);
|
rpc Restart (StartRequest) returns (CoreInfoResponse);
|
||||||
rpc SelectOutbound (SelectOutboundRequest) returns (Response);
|
rpc SelectOutbound (SelectOutboundRequest) returns (Response);
|
||||||
rpc UrlTest (UrlTestRequest) returns (Response);
|
rpc UrlTest (UrlTestRequest) returns (Response);
|
||||||
rpc GenerateWarpConfig (GenerateWarpConfigRequest) returns (WarpGenerationResponse);
|
rpc GenerateWarpConfig (GenerateWarpConfigRequest) returns (WarpGenerationResponse);
|
||||||
rpc GetSystemProxyStatus (Empty) returns (SystemProxyStatus);
|
rpc GetSystemProxyStatus (Empty) returns (SystemProxyStatus);
|
||||||
rpc SetSystemProxyEnabled (SetSystemProxyEnabledRequest) returns (Response);
|
rpc SetSystemProxyEnabled (SetSystemProxyEnabledRequest) returns (Response);
|
||||||
rpc LogListener (stream StopRequest) returns (stream LogMessage);
|
rpc LogListener (stream StopRequest) returns (stream LogMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
326
v2/commands.go
326
v2/commands.go
@@ -1,163 +1,163 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox"
|
"github.com/sagernet/sing-box/experimental/libbox"
|
||||||
"github.com/sagernet/sing/common/observable"
|
"github.com/sagernet/sing/common/observable"
|
||||||
)
|
)
|
||||||
|
|
||||||
var systemInfoObserver = observable.Observer[pb.SystemInfo]{}
|
var systemInfoObserver = observable.Observer[pb.SystemInfo]{}
|
||||||
var outboundsInfoObserver = observable.Observer[pb.OutboundGroupList]{}
|
var outboundsInfoObserver = observable.Observer[pb.OutboundGroupList]{}
|
||||||
var mainOutboundsInfoObserver = observable.Observer[pb.OutboundGroupList]{}
|
var mainOutboundsInfoObserver = observable.Observer[pb.OutboundGroupList]{}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
statusClient *libbox.CommandClient
|
statusClient *libbox.CommandClient
|
||||||
groupClient *libbox.CommandClient
|
groupClient *libbox.CommandClient
|
||||||
groupInfoOnlyClient *libbox.CommandClient
|
groupInfoOnlyClient *libbox.CommandClient
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *server) GetSystemInfo(stream pb.Hiddify_GetSystemInfoServer) error {
|
func (s *server) GetSystemInfo(stream pb.Hiddify_GetSystemInfoServer) error {
|
||||||
if statusClient == nil {
|
if statusClient == nil {
|
||||||
statusClient = libbox.NewCommandClient(
|
statusClient = libbox.NewCommandClient(
|
||||||
&CommandClientHandler{},
|
&CommandClientHandler{},
|
||||||
&libbox.CommandClientOptions{
|
&libbox.CommandClientOptions{
|
||||||
Command: libbox.CommandStatus,
|
Command: libbox.CommandStatus,
|
||||||
StatusInterval: 1000000000, //1000ms debounce
|
StatusInterval: 1000000000, //1000ms debounce
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
statusClient.Disconnect()
|
statusClient.Disconnect()
|
||||||
statusClient = nil
|
statusClient = nil
|
||||||
}()
|
}()
|
||||||
statusClient.Connect()
|
statusClient.Connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub, _, _ := systemInfoObserver.Subscribe()
|
sub, _, _ := systemInfoObserver.Subscribe()
|
||||||
stopch := make(chan int)
|
stopch := make(chan int)
|
||||||
go func() {
|
go func() {
|
||||||
stream.Recv()
|
stream.Recv()
|
||||||
close(stopch)
|
close(stopch)
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stream.Context().Done():
|
case <-stream.Context().Done():
|
||||||
break
|
break
|
||||||
case <-stopch:
|
case <-stopch:
|
||||||
break
|
break
|
||||||
case info := <-sub:
|
case info := <-sub:
|
||||||
stream.Send(&info)
|
stream.Send(&info)
|
||||||
case <-time.After(1000 * time.Millisecond):
|
case <-time.After(1000 * time.Millisecond):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) OutboundsInfo(stream pb.Hiddify_OutboundsInfoServer) error {
|
func (s *server) OutboundsInfo(stream pb.Hiddify_OutboundsInfoServer) error {
|
||||||
if groupClient == nil {
|
if groupClient == nil {
|
||||||
groupClient = libbox.NewCommandClient(
|
groupClient = libbox.NewCommandClient(
|
||||||
&CommandClientHandler{},
|
&CommandClientHandler{},
|
||||||
&libbox.CommandClientOptions{
|
&libbox.CommandClientOptions{
|
||||||
Command: libbox.CommandGroup,
|
Command: libbox.CommandGroup,
|
||||||
StatusInterval: 500000000, //500ms debounce
|
StatusInterval: 500000000, //500ms debounce
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
groupClient.Disconnect()
|
groupClient.Disconnect()
|
||||||
groupClient = nil
|
groupClient = nil
|
||||||
}()
|
}()
|
||||||
groupClient.Connect()
|
groupClient.Connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub, _, _ := outboundsInfoObserver.Subscribe()
|
sub, _, _ := outboundsInfoObserver.Subscribe()
|
||||||
stopch := make(chan int)
|
stopch := make(chan int)
|
||||||
go func() {
|
go func() {
|
||||||
stream.Recv()
|
stream.Recv()
|
||||||
close(stopch)
|
close(stopch)
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stream.Context().Done():
|
case <-stream.Context().Done():
|
||||||
break
|
break
|
||||||
case <-stopch:
|
case <-stopch:
|
||||||
break
|
break
|
||||||
case info := <-sub:
|
case info := <-sub:
|
||||||
stream.Send(&info)
|
stream.Send(&info)
|
||||||
case <-time.After(500 * time.Millisecond):
|
case <-time.After(500 * time.Millisecond):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) MainOutboundsInfo(stream pb.Hiddify_MainOutboundsInfoServer) error {
|
func (s *server) MainOutboundsInfo(stream pb.Hiddify_MainOutboundsInfoServer) error {
|
||||||
if groupInfoOnlyClient == nil {
|
if groupInfoOnlyClient == nil {
|
||||||
groupInfoOnlyClient = libbox.NewCommandClient(
|
groupInfoOnlyClient = libbox.NewCommandClient(
|
||||||
&CommandClientHandler{},
|
&CommandClientHandler{},
|
||||||
&libbox.CommandClientOptions{
|
&libbox.CommandClientOptions{
|
||||||
Command: libbox.CommandGroupInfoOnly,
|
Command: libbox.CommandGroupInfoOnly,
|
||||||
StatusInterval: 500000000, //500ms debounce
|
StatusInterval: 500000000, //500ms debounce
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
groupInfoOnlyClient.Disconnect()
|
groupInfoOnlyClient.Disconnect()
|
||||||
groupInfoOnlyClient = nil
|
groupInfoOnlyClient = nil
|
||||||
}()
|
}()
|
||||||
groupInfoOnlyClient.Connect()
|
groupInfoOnlyClient.Connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub, _, _ := mainOutboundsInfoObserver.Subscribe()
|
sub, _, _ := mainOutboundsInfoObserver.Subscribe()
|
||||||
stopch := make(chan int)
|
stopch := make(chan int)
|
||||||
go func() {
|
go func() {
|
||||||
stream.Recv()
|
stream.Recv()
|
||||||
close(stopch)
|
close(stopch)
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stream.Context().Done():
|
case <-stream.Context().Done():
|
||||||
break
|
break
|
||||||
case <-stopch:
|
case <-stopch:
|
||||||
break
|
break
|
||||||
case info := <-sub:
|
case info := <-sub:
|
||||||
stream.Send(&info)
|
stream.Send(&info)
|
||||||
case <-time.After(500 * time.Millisecond):
|
case <-time.After(500 * time.Millisecond):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the SelectOutbound method
|
// Implement the SelectOutbound method
|
||||||
func (s *server) SelectOutbound(ctx context.Context, in *pb.SelectOutboundRequest) (*pb.Response, error) {
|
func (s *server) SelectOutbound(ctx context.Context, in *pb.SelectOutboundRequest) (*pb.Response, error) {
|
||||||
err := libbox.NewStandaloneCommandClient().SelectOutbound(in.GroupTag, in.OutboundTag)
|
err := libbox.NewStandaloneCommandClient().SelectOutbound(in.GroupTag, in.OutboundTag)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &pb.Response{
|
return &pb.Response{
|
||||||
ResponseCode: pb.ResponseCode_FAILED,
|
ResponseCode: pb.ResponseCode_FAILED,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.Response{
|
return &pb.Response{
|
||||||
ResponseCode: pb.ResponseCode_OK,
|
ResponseCode: pb.ResponseCode_OK,
|
||||||
Message: "",
|
Message: "",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the UrlTest method
|
// Implement the UrlTest method
|
||||||
func (s *server) UrlTest(ctx context.Context, in *pb.UrlTestRequest) (*pb.Response, error) {
|
func (s *server) UrlTest(ctx context.Context, in *pb.UrlTestRequest) (*pb.Response, error) {
|
||||||
err := libbox.NewStandaloneCommandClient().URLTest(in.GroupTag)
|
err := libbox.NewStandaloneCommandClient().URLTest(in.GroupTag)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &pb.Response{
|
return &pb.Response{
|
||||||
ResponseCode: pb.ResponseCode_FAILED,
|
ResponseCode: pb.ResponseCode_FAILED,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.Response{
|
return &pb.Response{
|
||||||
ResponseCode: pb.ResponseCode_OK,
|
ResponseCode: pb.ResponseCode_OK,
|
||||||
Message: "",
|
Message: "",
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||||
"github.com/sagernet/sing/common/observable"
|
"github.com/sagernet/sing/common/observable"
|
||||||
)
|
)
|
||||||
|
|
||||||
var coreInfoObserver = observable.Observer[pb.CoreInfoResponse]{}
|
var coreInfoObserver = observable.Observer[pb.CoreInfoResponse]{}
|
||||||
var CoreState = pb.CoreState_STOPPED
|
var CoreState = pb.CoreState_STOPPED
|
||||||
|
|
||||||
func SetCoreStatus(state pb.CoreState, msgType pb.MessageType, message string) pb.CoreInfoResponse {
|
func SetCoreStatus(state pb.CoreState, msgType pb.MessageType, message string) pb.CoreInfoResponse {
|
||||||
CoreState = state
|
CoreState = state
|
||||||
info := pb.CoreInfoResponse{
|
info := pb.CoreInfoResponse{
|
||||||
CoreState: state,
|
CoreState: state,
|
||||||
MessageType: msgType,
|
MessageType: msgType,
|
||||||
Message: message,
|
Message: message,
|
||||||
}
|
}
|
||||||
coreInfoObserver.Emit(info)
|
coreInfoObserver.Emit(info)
|
||||||
return info
|
return info
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) CoreInfoListener(stream pb.Hiddify_CoreInfoListenerServer) error {
|
func (s *server) CoreInfoListener(stream pb.Hiddify_CoreInfoListenerServer) error {
|
||||||
coreSub, _, _ := coreInfoObserver.Subscribe()
|
coreSub, _, _ := coreInfoObserver.Subscribe()
|
||||||
defer coreInfoObserver.UnSubscribe(coreSub)
|
defer coreInfoObserver.UnSubscribe(coreSub)
|
||||||
stopch := make(chan int)
|
stopch := make(chan int)
|
||||||
go func() {
|
go func() {
|
||||||
stream.Recv()
|
stream.Recv()
|
||||||
close(stopch)
|
close(stopch)
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stream.Context().Done():
|
case <-stream.Context().Done():
|
||||||
break
|
break
|
||||||
case <-stopch:
|
case <-stopch:
|
||||||
break
|
break
|
||||||
case info := <-coreSub:
|
case info := <-coreSub:
|
||||||
stream.Send(&info)
|
stream.Send(&info)
|
||||||
case <-time.After(500 * time.Millisecond):
|
case <-time.After(500 * time.Millisecond):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
464
v2/custom.go
464
v2/custom.go
@@ -1,232 +1,232 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hiddify/libcore/config"
|
"github.com/hiddify/libcore/config"
|
||||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox"
|
"github.com/sagernet/sing-box/experimental/libbox"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Box *libbox.BoxService
|
var Box *libbox.BoxService
|
||||||
var configOptions *config.ConfigOptions
|
var configOptions *config.ConfigOptions
|
||||||
var activeConfigPath *string
|
var activeConfigPath *string
|
||||||
var logFactory *log.Factory
|
var logFactory *log.Factory
|
||||||
|
|
||||||
func StopAndAlert(msgType pb.MessageType, message string) {
|
func StopAndAlert(msgType pb.MessageType, message string) {
|
||||||
SetCoreStatus(pb.CoreState_STOPPED, msgType, message)
|
SetCoreStatus(pb.CoreState_STOPPED, msgType, message)
|
||||||
config.DeactivateTunnelService()
|
config.DeactivateTunnelService()
|
||||||
// if commandServer != nil {
|
// if commandServer != nil {
|
||||||
// commandServer.SetService(nil)
|
// commandServer.SetService(nil)
|
||||||
// }
|
// }
|
||||||
if Box != nil {
|
if Box != nil {
|
||||||
Box.Close()
|
Box.Close()
|
||||||
Box = nil
|
Box = nil
|
||||||
}
|
}
|
||||||
// if commandServer != nil {
|
// if commandServer != nil {
|
||||||
// commandServer.Close()
|
// commandServer.Close()
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Start(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
func (s *server) Start(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||||
defer config.DeferPanicToError("start", func(err error) {
|
defer config.DeferPanicToError("start", func(err error) {
|
||||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||||
})
|
})
|
||||||
|
|
||||||
if CoreState != pb.CoreState_STOPPED {
|
if CoreState != pb.CoreState_STOPPED {
|
||||||
return &pb.CoreInfoResponse{
|
return &pb.CoreInfoResponse{
|
||||||
CoreState: CoreState,
|
CoreState: CoreState,
|
||||||
MessageType: pb.MessageType_INSTANCE_NOT_STOPPED,
|
MessageType: pb.MessageType_INSTANCE_NOT_STOPPED,
|
||||||
}, fmt.Errorf("instance not stopped")
|
}, fmt.Errorf("instance not stopped")
|
||||||
}
|
}
|
||||||
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
|
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
|
||||||
|
|
||||||
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
|
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
|
||||||
resp, err := s.StartService(ctx, in)
|
resp, err := s.StartService(ctx, in)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the StartService method
|
// Implement the StartService method
|
||||||
func (s *server) StartService(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
func (s *server) StartService(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||||
|
|
||||||
content := in.ConfigContent
|
content := in.ConfigContent
|
||||||
if content != "" {
|
if content != "" {
|
||||||
fileContent, err := os.ReadFile(*activeConfigPath)
|
fileContent, err := os.ReadFile(*activeConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_READING_CONFIG, err.Error())
|
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_READING_CONFIG, err.Error())
|
||||||
return &resp, err
|
return &resp, err
|
||||||
}
|
}
|
||||||
content = string(fileContent)
|
content = string(fileContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedContent, err := parseConfig(content)
|
parsedContent, err := parseConfig(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_PARSING_CONFIG, err.Error())
|
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_PARSING_CONFIG, err.Error())
|
||||||
return &resp, err
|
return &resp, err
|
||||||
}
|
}
|
||||||
var patchedOptions *option.Options
|
var patchedOptions *option.Options
|
||||||
patchedOptions, err = config.BuildConfig(*configOptions, parsedContent)
|
patchedOptions, err = config.BuildConfig(*configOptions, parsedContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_BUILDING_CONFIG, err.Error())
|
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_BUILDING_CONFIG, err.Error())
|
||||||
return &resp, err
|
return &resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "current-config.json"), *patchedOptions)
|
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "current-config.json"), *patchedOptions)
|
||||||
|
|
||||||
// err = startCommandServer(*logFactory)
|
// err = startCommandServer(*logFactory)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_COMMAND_SERVER, err.Error())
|
// resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_COMMAND_SERVER, err.Error())
|
||||||
// return &resp, err
|
// return &resp, err
|
||||||
// }
|
// }
|
||||||
|
|
||||||
instance, err := NewService(*patchedOptions)
|
instance, err := NewService(*patchedOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_CREATE_SERVICE, err.Error())
|
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_CREATE_SERVICE, err.Error())
|
||||||
return &resp, err
|
return &resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if in.DelayStart {
|
if in.DelayStart {
|
||||||
<-time.After(250 * time.Millisecond)
|
<-time.After(250 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = instance.Start()
|
err = instance.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_SERVICE, err.Error())
|
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_SERVICE, err.Error())
|
||||||
return &resp, err
|
return &resp, err
|
||||||
}
|
}
|
||||||
Box = instance
|
Box = instance
|
||||||
// commandServer.SetService(box)
|
// commandServer.SetService(box)
|
||||||
|
|
||||||
resp := SetCoreStatus(pb.CoreState_STARTED, pb.MessageType_EMPTY, "")
|
resp := SetCoreStatus(pb.CoreState_STARTED, pb.MessageType_EMPTY, "")
|
||||||
return &resp, nil
|
return &resp, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Parse(ctx context.Context, in *pb.ParseRequest) (*pb.ParseResponse, error) {
|
func (s *server) Parse(ctx context.Context, in *pb.ParseRequest) (*pb.ParseResponse, error) {
|
||||||
defer config.DeferPanicToError("parse", func(err error) {
|
defer config.DeferPanicToError("parse", func(err error) {
|
||||||
Log(pb.LogLevel_FATAL, pb.LogType_CONFIG, err.Error())
|
Log(pb.LogLevel_FATAL, pb.LogType_CONFIG, err.Error())
|
||||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||||
})
|
})
|
||||||
|
|
||||||
config, err := config.ParseConfigContent(in.Content, true)
|
config, err := config.ParseConfigContent(in.Content, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &pb.ParseResponse{
|
return &pb.ParseResponse{
|
||||||
ResponseCode: pb.ResponseCode_FAILED,
|
ResponseCode: pb.ResponseCode_FAILED,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
return &pb.ParseResponse{
|
return &pb.ParseResponse{
|
||||||
ResponseCode: pb.ResponseCode_OK,
|
ResponseCode: pb.ResponseCode_OK,
|
||||||
Content: string(config),
|
Content: string(config),
|
||||||
Message: "",
|
Message: "",
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (s *server) ChangeConfigOptions(ctx context.Context, in *pb.ChangeConfigOptionsRequest) (*pb.CoreInfoResponse, error) {
|
// func (s *server) ChangeConfigOptions(ctx context.Context, in *pb.ChangeConfigOptionsRequest) (*pb.CoreInfoResponse, error) {
|
||||||
// // Implement your change config options logic
|
// // Implement your change config options logic
|
||||||
// // Return a CoreInfoResponse
|
// // Return a CoreInfoResponse
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// func (s *server) GenerateConfig(ctx context.Context, in *pb.GenerateConfigRequest) (*pb.GenerateConfigResponse, error) {
|
// func (s *server) GenerateConfig(ctx context.Context, in *pb.GenerateConfigRequest) (*pb.GenerateConfigResponse, error) {
|
||||||
// defer config.DeferPanicToError("generateConfig", func(err error) {
|
// defer config.DeferPanicToError("generateConfig", func(err error) {
|
||||||
// Log(pb.LogLevel_FATAL, pb.LogType_CONFIG, err.Error())
|
// Log(pb.LogLevel_FATAL, pb.LogType_CONFIG, err.Error())
|
||||||
// StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
// StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||||
// })
|
// })
|
||||||
|
|
||||||
// config, err := generateConfigFromFile(C.GoString(path), *configOptions)
|
// config, err := generateConfigFromFile(C.GoString(path), *configOptions)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return C.CString("error" + err.Error())
|
// return C.CString("error" + err.Error())
|
||||||
// }
|
// }
|
||||||
// return C.CString(config)
|
// return C.CString(config)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Implement the Stop method
|
// Implement the Stop method
|
||||||
func (s *server) Stop(ctx context.Context, empty *pb.Empty) (*pb.CoreInfoResponse, error) {
|
func (s *server) Stop(ctx context.Context, empty *pb.Empty) (*pb.CoreInfoResponse, error) {
|
||||||
defer config.DeferPanicToError("stop", func(err error) {
|
defer config.DeferPanicToError("stop", func(err error) {
|
||||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||||
})
|
})
|
||||||
config.DeactivateTunnelService()
|
config.DeactivateTunnelService()
|
||||||
if CoreState != pb.CoreState_STARTED {
|
if CoreState != pb.CoreState_STARTED {
|
||||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, "Core is not started")
|
Log(pb.LogLevel_FATAL, pb.LogType_CORE, "Core is not started")
|
||||||
return &pb.CoreInfoResponse{
|
return &pb.CoreInfoResponse{
|
||||||
CoreState: CoreState,
|
CoreState: CoreState,
|
||||||
MessageType: pb.MessageType_INSTANCE_NOT_STARTED,
|
MessageType: pb.MessageType_INSTANCE_NOT_STARTED,
|
||||||
Message: "instance is not started",
|
Message: "instance is not started",
|
||||||
}, fmt.Errorf("instance not started")
|
}, fmt.Errorf("instance not started")
|
||||||
}
|
}
|
||||||
if Box == nil {
|
if Box == nil {
|
||||||
return &pb.CoreInfoResponse{
|
return &pb.CoreInfoResponse{
|
||||||
CoreState: CoreState,
|
CoreState: CoreState,
|
||||||
MessageType: pb.MessageType_INSTANCE_NOT_FOUND,
|
MessageType: pb.MessageType_INSTANCE_NOT_FOUND,
|
||||||
Message: "instance is not found",
|
Message: "instance is not found",
|
||||||
}, fmt.Errorf("instance not found")
|
}, fmt.Errorf("instance not found")
|
||||||
}
|
}
|
||||||
SetCoreStatus(pb.CoreState_STOPPING, pb.MessageType_EMPTY, "")
|
SetCoreStatus(pb.CoreState_STOPPING, pb.MessageType_EMPTY, "")
|
||||||
// commandServer.SetService(nil)
|
// commandServer.SetService(nil)
|
||||||
|
|
||||||
err := Box.Close()
|
err := Box.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &pb.CoreInfoResponse{
|
return &pb.CoreInfoResponse{
|
||||||
CoreState: CoreState,
|
CoreState: CoreState,
|
||||||
MessageType: pb.MessageType_UNEXPECTED_ERROR,
|
MessageType: pb.MessageType_UNEXPECTED_ERROR,
|
||||||
Message: "Error while stopping the service.",
|
Message: "Error while stopping the service.",
|
||||||
}, fmt.Errorf("Error while stopping the service.")
|
}, fmt.Errorf("Error while stopping the service.")
|
||||||
}
|
}
|
||||||
Box = nil
|
Box = nil
|
||||||
// err = commandServer.Close()
|
// err = commandServer.Close()
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return &pb.CoreInfoResponse{
|
// return &pb.CoreInfoResponse{
|
||||||
// CoreState: CoreState,
|
// CoreState: CoreState,
|
||||||
// MessageType: pb.MessageType_UNEXPECTED_ERROR,
|
// MessageType: pb.MessageType_UNEXPECTED_ERROR,
|
||||||
// Message: "Error while Closing the comand server.",
|
// Message: "Error while Closing the comand server.",
|
||||||
// }, fmt.Errorf("Error while Closing the comand server.")
|
// }, fmt.Errorf("Error while Closing the comand server.")
|
||||||
|
|
||||||
// }
|
// }
|
||||||
// commandServer = nil
|
// commandServer = nil
|
||||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_EMPTY, "")
|
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_EMPTY, "")
|
||||||
return &resp, nil
|
return &resp, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Restart(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
func (s *server) Restart(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||||
defer config.DeferPanicToError("restart", func(err error) {
|
defer config.DeferPanicToError("restart", func(err error) {
|
||||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||||
})
|
})
|
||||||
log.Debug("[Service] Restarting")
|
log.Debug("[Service] Restarting")
|
||||||
|
|
||||||
if CoreState != pb.CoreState_STARTED {
|
if CoreState != pb.CoreState_STARTED {
|
||||||
return &pb.CoreInfoResponse{
|
return &pb.CoreInfoResponse{
|
||||||
CoreState: CoreState,
|
CoreState: CoreState,
|
||||||
MessageType: pb.MessageType_INSTANCE_NOT_STARTED,
|
MessageType: pb.MessageType_INSTANCE_NOT_STARTED,
|
||||||
Message: "instance is not started",
|
Message: "instance is not started",
|
||||||
}, fmt.Errorf("instance not started")
|
}, fmt.Errorf("instance not started")
|
||||||
}
|
}
|
||||||
if Box == nil {
|
if Box == nil {
|
||||||
return &pb.CoreInfoResponse{
|
return &pb.CoreInfoResponse{
|
||||||
CoreState: CoreState,
|
CoreState: CoreState,
|
||||||
MessageType: pb.MessageType_INSTANCE_NOT_FOUND,
|
MessageType: pb.MessageType_INSTANCE_NOT_FOUND,
|
||||||
Message: "instance is not found",
|
Message: "instance is not found",
|
||||||
}, fmt.Errorf("instance not found")
|
}, fmt.Errorf("instance not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := s.Stop(ctx, &pb.Empty{})
|
resp, err := s.Stop(ctx, &pb.Empty{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
|
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
|
||||||
<-time.After(250 * time.Millisecond)
|
<-time.After(250 * time.Millisecond)
|
||||||
|
|
||||||
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
|
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
|
||||||
resp, gErr := s.StartService(ctx, in)
|
resp, gErr := s.StartService(ctx, in)
|
||||||
return resp, gErr
|
return resp, gErr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,62 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
address = "localhost:50051"
|
address = "localhost:50051"
|
||||||
defaultName = "world"
|
defaultName = "world"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
conn, err := grpc.Dial(address, grpc.WithInsecure())
|
conn, err := grpc.Dial(address, grpc.WithInsecure())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("did not connect: %v", err)
|
log.Fatalf("did not connect: %v", err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
c := pb.NewHiddifyClient(conn)
|
c := pb.NewHiddifyClient(conn)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// SayHello
|
// SayHello
|
||||||
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: defaultName})
|
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: defaultName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("could not greet: %v", err)
|
log.Fatalf("could not greet: %v", err)
|
||||||
}
|
}
|
||||||
log.Printf("Greeting: %s", r.Message)
|
log.Printf("Greeting: %s", r.Message)
|
||||||
|
|
||||||
// SayHelloStream
|
// SayHelloStream
|
||||||
stream, err := c.SayHelloStream(ctx)
|
stream, err := c.SayHelloStream(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("could not stream: %v", err)
|
log.Fatalf("could not stream: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
names := []string{"Alice", "Bob", "Charlie"}
|
names := []string{"Alice", "Bob", "Charlie"}
|
||||||
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
err := stream.Send(&pb.HelloRequest{Name: name})
|
err := stream.Send(&pb.HelloRequest{Name: name})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("could not send: %v", err)
|
log.Fatalf("could not send: %v", err)
|
||||||
}
|
}
|
||||||
r, err := stream.Recv()
|
r, err := stream.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("could not receive: %v", err)
|
log.Fatalf("could not receive: %v", err)
|
||||||
}
|
}
|
||||||
log.Printf("Received1: %s", r.Message)
|
log.Printf("Received1: %s", r.Message)
|
||||||
r2, err2 := stream.Recv()
|
r2, err2 := stream.Recv()
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
log.Fatalf("could not receive2: %v", err2)
|
log.Fatalf("could not receive2: %v", err2)
|
||||||
}
|
}
|
||||||
log.Printf("Received: %s", r2.Message)
|
log.Printf("Received: %s", r2.Message)
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
v2 "github.com/hiddify/libcore/v2"
|
v2 "github.com/hiddify/libcore/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
// defer C.free(unsafe.Pointer(port))
|
// defer C.free(unsafe.Pointer(port))
|
||||||
v2.StartGrpcServerGo("127.0.0.1:50051")
|
v2.StartGrpcServerGo("127.0.0.1:50051")
|
||||||
sigChan := make(chan os.Signal, 1)
|
sigChan := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||||
<-sigChan
|
<-sigChan
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type server struct {
|
type server struct {
|
||||||
pb.UnimplementedHiddifyServer
|
pb.UnimplementedHiddifyServer
|
||||||
}
|
}
|
||||||
|
|
||||||
//export StartGrpcServer
|
//export StartGrpcServer
|
||||||
func StartGrpcServer(listenAddress *C.char) (CErr *C.char) {
|
func StartGrpcServer(listenAddress *C.char) (CErr *C.char) {
|
||||||
//Example Listen Address: "127.0.0.1:50051"
|
//Example Listen Address: "127.0.0.1:50051"
|
||||||
err := StartGrpcServerGo(C.GoString(listenAddress))
|
err := StartGrpcServerGo(C.GoString(listenAddress))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return C.CString(err.Error())
|
return C.CString(err.Error())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartGrpcServerGo(listenAddressG string) error {
|
func StartGrpcServerGo(listenAddressG string) error {
|
||||||
//Example Listen Address: "127.0.0.1:50051"
|
//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(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
|
// defer C.free(unsafe.Pointer(listenAddress)) // free the C string when it's no longer needed
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", listenAddressG)
|
lis, err := net.Listen("tcp", listenAddressG)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to listen: %v", err)
|
log.Printf("failed to listen: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
pb.RegisterHiddifyServer(s, &server{})
|
pb.RegisterHiddifyServer(s, &server{})
|
||||||
log.Printf("Server listening on %s", listenAddressG)
|
log.Printf("Server listening on %s", listenAddressG)
|
||||||
go func() {
|
go func() {
|
||||||
if err := s.Serve(lis); err != nil {
|
if err := s.Serve(lis); err != nil {
|
||||||
log.Printf("failed to serve: %v", err)
|
log.Printf("failed to serve: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
72
v2/hello.go
72
v2/hello.go
@@ -1,36 +1,36 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
|
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
|
||||||
return &pb.HelloResponse{Message: "Hello, " + in.Name}, nil
|
return &pb.HelloResponse{Message: "Hello, " + in.Name}, nil
|
||||||
}
|
}
|
||||||
func (s *server) SayHelloStream(stream pb.Hiddify_SayHelloStreamServer) error {
|
func (s *server) SayHelloStream(stream pb.Hiddify_SayHelloStreamServer) error {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
req, err := stream.Recv()
|
req, err := stream.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("stream.Recv() failed: %v", err)
|
log.Printf("stream.Recv() failed: %v", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
log.Printf("Received: %v", req.Name)
|
log.Printf("Received: %v", req.Name)
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
err = stream.Send(&pb.HelloResponse{Message: "Hello, " + req.Name})
|
err = stream.Send(&pb.HelloResponse{Message: "Hello, " + req.Name})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("stream.Send() failed: %v", err)
|
log.Printf("stream.Send() failed: %v", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err = stream.Send(&pb.HelloResponse{Message: "Hello again, " + req.Name})
|
err = stream.Send(&pb.HelloResponse{Message: "Hello again, " + req.Name})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("stream.Send() failed: %v", err)
|
log.Printf("stream.Send() failed: %v", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||||
"github.com/sagernet/sing/common/observable"
|
"github.com/sagernet/sing/common/observable"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logObserver = observable.Observer[pb.LogMessage]{}
|
var logObserver = observable.Observer[pb.LogMessage]{}
|
||||||
|
|
||||||
func Log(level pb.LogLevel, typ pb.LogType, message string) {
|
func Log(level pb.LogLevel, typ pb.LogType, message string) {
|
||||||
logObserver.Emit(pb.LogMessage{
|
logObserver.Emit(pb.LogMessage{
|
||||||
Level: level,
|
Level: level,
|
||||||
Type: typ,
|
Type: typ,
|
||||||
Message: message,
|
Message: message,
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) LogListener(stream pb.Hiddify_LogListenerServer) error {
|
func (s *server) LogListener(stream pb.Hiddify_LogListenerServer) error {
|
||||||
logSub, _, _ := logObserver.Subscribe()
|
logSub, _, _ := logObserver.Subscribe()
|
||||||
defer logObserver.UnSubscribe(logSub)
|
defer logObserver.UnSubscribe(logSub)
|
||||||
|
|
||||||
stopch := make(chan int)
|
stopch := make(chan int)
|
||||||
go func() {
|
go func() {
|
||||||
stream.Recv()
|
stream.Recv()
|
||||||
close(stopch)
|
close(stopch)
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stream.Context().Done():
|
case <-stream.Context().Done():
|
||||||
break
|
break
|
||||||
case <-stopch:
|
case <-stopch:
|
||||||
break
|
break
|
||||||
case info := <-logSub:
|
case info := <-logSub:
|
||||||
stream.Send(&info)
|
stream.Send(&info)
|
||||||
case <-time.After(500 * time.Millisecond):
|
case <-time.After(500 * time.Millisecond):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
130
v2/warp.go
130
v2/warp.go
@@ -1,65 +1,65 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/hiddify/libcore/config"
|
"github.com/hiddify/libcore/config"
|
||||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox"
|
"github.com/sagernet/sing-box/experimental/libbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *server) GenerateWarpConfig(ctx context.Context, in *pb.GenerateWarpConfigRequest) (*pb.WarpGenerationResponse, error) {
|
func (s *server) GenerateWarpConfig(ctx context.Context, in *pb.GenerateWarpConfigRequest) (*pb.WarpGenerationResponse, error) {
|
||||||
account, log, wg, err := config.GenerateWarpInfo(in.LicenseKey, in.AccountId, in.AccessToken)
|
account, log, wg, err := config.GenerateWarpInfo(in.LicenseKey, in.AccountId, in.AccessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &pb.WarpGenerationResponse{
|
return &pb.WarpGenerationResponse{
|
||||||
Account: &pb.WarpAccount{
|
Account: &pb.WarpAccount{
|
||||||
AccountId: account.AccountID,
|
AccountId: account.AccountID,
|
||||||
AccessToken: account.AccessToken,
|
AccessToken: account.AccessToken,
|
||||||
},
|
},
|
||||||
Config: &pb.WarpWireguardConfig{
|
Config: &pb.WarpWireguardConfig{
|
||||||
PrivateKey: wg.PrivateKey,
|
PrivateKey: wg.PrivateKey,
|
||||||
LocalAddressIpv4: wg.LocalAddressIPv4,
|
LocalAddressIpv4: wg.LocalAddressIPv4,
|
||||||
LocalAddressIpv6: wg.LocalAddressIPv6,
|
LocalAddressIpv6: wg.LocalAddressIPv6,
|
||||||
PeerPublicKey: wg.PeerPublicKey,
|
PeerPublicKey: wg.PeerPublicKey,
|
||||||
},
|
},
|
||||||
Log: log,
|
Log: log,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the GetSystemProxyStatus method
|
// Implement the GetSystemProxyStatus method
|
||||||
func (s *server) GetSystemProxyStatus(ctx context.Context, empty *pb.Empty) (*pb.SystemProxyStatus, error) {
|
func (s *server) GetSystemProxyStatus(ctx context.Context, empty *pb.Empty) (*pb.SystemProxyStatus, error) {
|
||||||
status, err := libbox.NewStandaloneCommandClient().GetSystemProxyStatus()
|
status, err := libbox.NewStandaloneCommandClient().GetSystemProxyStatus()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.SystemProxyStatus{
|
return &pb.SystemProxyStatus{
|
||||||
Available: status.Available,
|
Available: status.Available,
|
||||||
Enabled: status.Enabled,
|
Enabled: status.Enabled,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the SetSystemProxyEnabled method
|
// Implement the SetSystemProxyEnabled method
|
||||||
func (s *server) SetSystemProxyEnabled(ctx context.Context, in *pb.SetSystemProxyEnabledRequest) (*pb.Response, error) {
|
func (s *server) SetSystemProxyEnabled(ctx context.Context, in *pb.SetSystemProxyEnabledRequest) (*pb.Response, error) {
|
||||||
err := libbox.NewStandaloneCommandClient().SetSystemProxyEnabled(in.IsEnabled)
|
err := libbox.NewStandaloneCommandClient().SetSystemProxyEnabled(in.IsEnabled)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &pb.Response{
|
return &pb.Response{
|
||||||
ResponseCode: pb.ResponseCode_FAILED,
|
ResponseCode: pb.ResponseCode_FAILED,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.Response{
|
return &pb.Response{
|
||||||
ResponseCode: pb.ResponseCode_OK,
|
ResponseCode: pb.ResponseCode_OK,
|
||||||
Message: "",
|
Message: "",
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user