refactor global and admin service to use grpc
This commit is contained in:
@@ -1,133 +0,0 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/hiddify/libcore/global"
|
||||
"github.com/hiddify/libcore/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
serverCertPath = "cert/server-cert.pem"
|
||||
serverKeyPath = "cert/server-key.pem"
|
||||
clientCertPath = "cert/client-cert.pem"
|
||||
clientKeyPath = "cert/client-key.pem"
|
||||
)
|
||||
|
||||
func StartWebServer(Port int, TLS bool) {
|
||||
http.HandleFunc("/start", startHandler)
|
||||
http.HandleFunc("/stop", StopHandler)
|
||||
http.HandleFunc("/status", StatusHandler)
|
||||
http.HandleFunc("/exit", ExitHandler)
|
||||
server := &http.Server{
|
||||
Addr: "127.0.0.1:" + fmt.Sprintf("%d", Port),
|
||||
}
|
||||
var err error
|
||||
if TLS {
|
||||
server.TLSConfig = &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
Certificates: []tls.Certificate{utils.LoadCertificate(serverCertPath, serverKeyPath)},
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ClientCAs: utils.LoadClientCA(clientCertPath),
|
||||
}
|
||||
err = server.ListenAndServeTLS(serverCertPath, serverKeyPath)
|
||||
} else {
|
||||
err = server.ListenAndServe()
|
||||
}
|
||||
if err != nil {
|
||||
panic("Error: " + err.Error())
|
||||
}
|
||||
}
|
||||
func startHandler(w http.ResponseWriter, r *http.Request) {
|
||||
queryParams := r.URL.Query()
|
||||
ipv6, err := strconv.ParseBool(queryParams.Get("Ipv6"))
|
||||
if err != nil {
|
||||
fmt.Printf("ipv6 Error: %v ==>using false\n", err)
|
||||
ipv6 = false
|
||||
}
|
||||
serverPort, err := strconv.Atoi(queryParams.Get("ServerPort"))
|
||||
if err != nil {
|
||||
fmt.Printf("serverPort Error: %v ==>using 2334\n", err)
|
||||
serverPort = 2334
|
||||
}
|
||||
strictRoute, err := strconv.ParseBool(queryParams.Get("StrictRoute"))
|
||||
if err != nil {
|
||||
fmt.Printf("strictRoute Error: %v ==>using false\n", err)
|
||||
strictRoute = false
|
||||
}
|
||||
endpointIndependentNat, err := strconv.ParseBool(queryParams.Get("EndpointIndependentNat"))
|
||||
if err != nil {
|
||||
fmt.Printf("endpointIndependentNat Error: %v ==>using false\n", err)
|
||||
endpointIndependentNat = false
|
||||
}
|
||||
theStack := GetStack(queryParams.Get("Stack"))
|
||||
|
||||
parameters := global.Parameters{Ipv6: ipv6, ServerPort: serverPort, StrictRoute: strictRoute, EndpointIndependentNat: endpointIndependentNat, Stack: theStack}
|
||||
|
||||
// err = global.WriteParameters(parameters.Ipv6, parameters.ServerPort, parameters.StrictRoute, parameters.EndpointIndependentNat, GetStringFromStack(parameters.Stack))
|
||||
// if err != nil {
|
||||
// http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
// return
|
||||
// }
|
||||
err = global.SetupC("./", "./", "./tmp", false)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
err = global.StartServiceC(true, global.MakeConfig(parameters.Ipv6, parameters.ServerPort, parameters.StrictRoute, parameters.EndpointIndependentNat, GetStringFromStack(parameters.Stack)))
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
http.Error(w, fmt.Sprintf("Ok"), http.StatusOK)
|
||||
}
|
||||
func StatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
func StopHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err := global.StopServiceC()
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
http.Error(w, fmt.Sprintf("Ok"), http.StatusOK)
|
||||
}
|
||||
func ExitHandler(w http.ResponseWriter, r *http.Request) {
|
||||
global.StopServiceC()
|
||||
os.Exit(0)
|
||||
http.Error(w, fmt.Sprintf("Ok"), http.StatusOK)
|
||||
}
|
||||
func GetStack(stack string) global.Stack {
|
||||
|
||||
switch stack {
|
||||
case "system":
|
||||
return global.System
|
||||
case "gvisor":
|
||||
return global.GVisor
|
||||
case "mixed":
|
||||
return global.Mixed
|
||||
// case "LWIP":
|
||||
// return global.LWIP
|
||||
default:
|
||||
fmt.Printf("Stack Error: %s is not valid==> using GVisor\n", stack)
|
||||
return global.GVisor
|
||||
}
|
||||
}
|
||||
func GetStringFromStack(stack global.Stack) string {
|
||||
switch stack {
|
||||
case global.System:
|
||||
return "system"
|
||||
case global.GVisor:
|
||||
return "gvisor"
|
||||
case global.Mixed:
|
||||
return "mixed"
|
||||
// case global.LWIP:
|
||||
// return "LWIP"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/hiddify/libcore/global"
|
||||
v2 "github.com/hiddify/libcore/v2"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -29,5 +29,5 @@ func init() {
|
||||
}
|
||||
|
||||
func runCommand(cmd *cobra.Command, args []string) {
|
||||
global.RunStandalone(hiddifySettingPath, configPath)
|
||||
v2.RunStandalone(hiddifySettingPath, configPath)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hiddify/libcore/admin_service"
|
||||
v2 "github.com/hiddify/libcore/v2"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -15,7 +15,7 @@ var commandService = &cobra.Command{
|
||||
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
arg := args[0]
|
||||
code, out := admin_service.StartService(arg)
|
||||
code, out := v2.StartTunnelService(arg)
|
||||
fmt.Printf("exitCode:%d msg=%s", code, out)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
context "context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
dns "github.com/sagernet/sing-dns"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -59,49 +60,46 @@ func startTunnelRequestWithFailover(opt ConfigOptions, installService bool) {
|
||||
}
|
||||
|
||||
func startTunnelRequest(opt ConfigOptions, installService bool) (bool, error) {
|
||||
params := map[string]interface{}{
|
||||
"Ipv6": opt.IPv6Mode == option.DomainStrategy(dns.DomainStrategyUseIPv4),
|
||||
"ServerPort": opt.InboundOptions.MixedPort,
|
||||
"StrictRoute": opt.InboundOptions.StrictRoute,
|
||||
"EndpointIndependentNat": true,
|
||||
"Stack": opt.InboundOptions.TUNStack,
|
||||
}
|
||||
|
||||
values := url.Values{}
|
||||
for key, value := range params {
|
||||
values.Add(key, fmt.Sprint(value))
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s%s?%s", serviceURL, startEndpoint, values.Encode())
|
||||
fmt.Printf("URL: %s\n", url)
|
||||
response, err := http.Get(url)
|
||||
conn, err := grpc.Dial("127.0.0.1:18020", grpc.WithInsecure())
|
||||
if err != nil {
|
||||
log.Printf("did not connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
c := pb.NewTunnelServiceClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
_, err = c.Start(ctx, &pb.TunnelStartRequest{
|
||||
Ipv6: opt.IPv6Mode == option.DomainStrategy(dns.DomainStrategyUseIPv4),
|
||||
ServerPort: int32(opt.InboundOptions.MixedPort),
|
||||
StrictRoute: opt.InboundOptions.StrictRoute,
|
||||
EndpointIndependentNat: true,
|
||||
Stack: opt.InboundOptions.TUNStack,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("could not greet: %v", err)
|
||||
|
||||
if installService {
|
||||
return runTunnelService(opt)
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(response.Body)
|
||||
fmt.Printf("Response Code: %d %s. Response Body: %s Error:%v\n", response.StatusCode, response.Status, body, err)
|
||||
if err != nil || response.StatusCode != http.StatusOK {
|
||||
return false, fmt.Errorf("Unexpected Status Code: %d %s. Response Body: %s error:%v", response.StatusCode, response.Status, body, err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func stopTunnelRequest() (bool, error) {
|
||||
response, err := http.Get(serviceURL + stopEndpoint)
|
||||
conn, err := grpc.Dial("127.0.0.1:18020", grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("HTTP Request Error: %v", err)
|
||||
log.Printf("did not connect: %v", err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
defer conn.Close()
|
||||
c := pb.NewTunnelServiceClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
body, err := io.ReadAll(response.Body)
|
||||
// fmt.Printf("Response Code: %d %s. Response Body: %s Error:%v\n", response.StatusCode, response.Status, body, err)
|
||||
if err != nil || response.StatusCode != http.StatusOK {
|
||||
return false, fmt.Errorf("unexpected Status Code: %d %s. Response Body: %s error:%v", response.StatusCode, response.Status, body, err)
|
||||
_, err = c.Stop(ctx, &pb.Empty{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/hiddify/libcore/bridge"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
)
|
||||
|
||||
type CommandClientHandler struct {
|
||||
port int64
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) Connected() {
|
||||
cch.logger.Debug("CONNECTED")
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) Disconnected(message string) {
|
||||
cch.logger.Debug("DISCONNECTED: ", message)
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) ClearLog() {
|
||||
cch.logger.Debug("clear log")
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) WriteLog(message string) {
|
||||
cch.logger.Debug("log: ", message)
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) WriteStatus(message *libbox.StatusMessage) {
|
||||
msg, err := json.Marshal(
|
||||
map[string]int64{
|
||||
"connections-in": int64(message.ConnectionsIn),
|
||||
"connections-out": int64(message.ConnectionsOut),
|
||||
"uplink": message.Uplink,
|
||||
"downlink": message.Downlink,
|
||||
"uplink-total": message.UplinkTotal,
|
||||
"downlink-total": message.DownlinkTotal,
|
||||
},
|
||||
)
|
||||
cch.logger.Debug("Memory: ", libbox.FormatBytes(message.Memory), ", Goroutines: ", message.Goroutines)
|
||||
if err != nil {
|
||||
bridge.SendStringToPort(cch.port, fmt.Sprintf("error: %e", err))
|
||||
} else {
|
||||
bridge.SendStringToPort(cch.port, string(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) WriteGroups(message libbox.OutboundGroupIterator) {
|
||||
if message == nil {
|
||||
return
|
||||
}
|
||||
groups := []*OutboundGroup{}
|
||||
for message.HasNext() {
|
||||
group := message.Next()
|
||||
items := group.GetItems()
|
||||
groupItems := []*OutboundGroupItem{}
|
||||
for items.HasNext() {
|
||||
item := items.Next()
|
||||
groupItems = append(groupItems,
|
||||
&OutboundGroupItem{
|
||||
Tag: item.Tag,
|
||||
Type: item.Type,
|
||||
URLTestTime: item.URLTestTime,
|
||||
URLTestDelay: item.URLTestDelay,
|
||||
},
|
||||
)
|
||||
}
|
||||
groups = append(groups, &OutboundGroup{Tag: group.Tag, Type: group.Type, Selected: group.Selected, Items: groupItems})
|
||||
}
|
||||
response, err := json.Marshal(groups)
|
||||
if err != nil {
|
||||
bridge.SendStringToPort(cch.port, fmt.Sprintf("error: %e", err))
|
||||
} else {
|
||||
bridge.SendStringToPort(cch.port, string(response))
|
||||
}
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) InitializeClashMode(modeList libbox.StringIterator, currentMode string) {
|
||||
cch.logger.Debug("initial clash mode: ", currentMode)
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) UpdateClashMode(newMode string) {
|
||||
cch.logger.Debug("update clash mode: ", newMode)
|
||||
}
|
||||
|
||||
type OutboundGroup struct {
|
||||
Tag string `json:"tag"`
|
||||
Type string `json:"type"`
|
||||
Selected string `json:"selected"`
|
||||
Items []*OutboundGroupItem `json:"items"`
|
||||
}
|
||||
|
||||
type OutboundGroupItem struct {
|
||||
Tag string `json:"tag"`
|
||||
Type string `json:"type"`
|
||||
URLTestTime int64 `json:"url-test-time"`
|
||||
URLTestDelay int32 `json:"url-test-delay"`
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
)
|
||||
|
||||
var commandServer *libbox.CommandServer
|
||||
|
||||
type CommandServerHandler struct {
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) ServiceReload() error {
|
||||
csh.logger.Trace("Reloading service")
|
||||
propagateStatus(Starting)
|
||||
if commandServer != nil {
|
||||
commandServer.SetService(nil)
|
||||
commandServer = nil
|
||||
}
|
||||
if box != nil {
|
||||
box.Close()
|
||||
box = nil
|
||||
}
|
||||
return startService(true)
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) GetSystemProxyStatus() *libbox.SystemProxyStatus {
|
||||
csh.logger.Trace("Getting system proxy status")
|
||||
return &libbox.SystemProxyStatus{Available: true, Enabled: false}
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) SetSystemProxyEnabled(isEnabled bool) error {
|
||||
csh.logger.Trace("Setting system proxy status, enabled? ", isEnabled)
|
||||
return csh.ServiceReload()
|
||||
}
|
||||
|
||||
func startCommandServer(logFactory log.Factory) error {
|
||||
logger := logFactory.NewLogger("[Command Server Handler]")
|
||||
logger.Trace("Starting command server")
|
||||
commandServer = libbox.NewCommandServer(&CommandServerHandler{logger: logger}, 300)
|
||||
return commandServer.Start()
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
)
|
||||
|
||||
var (
|
||||
statusClient *libbox.CommandClient
|
||||
groupClient *libbox.CommandClient
|
||||
)
|
||||
|
||||
func StartCommand(command int32, port int64, logFactory log.Factory) error {
|
||||
switch command {
|
||||
case libbox.CommandStatus:
|
||||
statusClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{
|
||||
port: port,
|
||||
logger: logFactory.NewLogger("[Status Command Client]"),
|
||||
},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandStatus,
|
||||
StatusInterval: 1000000000,
|
||||
},
|
||||
)
|
||||
return statusClient.Connect()
|
||||
case libbox.CommandGroup:
|
||||
groupClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{
|
||||
port: port,
|
||||
logger: logFactory.NewLogger("[Group Command Client]"),
|
||||
},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandGroup,
|
||||
StatusInterval: 1000000000,
|
||||
},
|
||||
)
|
||||
return groupClient.Connect()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func StopCommand(command int32) error {
|
||||
switch command {
|
||||
case libbox.CommandStatus:
|
||||
err := statusClient.Disconnect()
|
||||
statusClient = nil
|
||||
return err
|
||||
case libbox.CommandGroup:
|
||||
err := groupClient.Disconnect()
|
||||
groupClient = nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package global
|
||||
|
||||
const (
|
||||
Stopped = "Stopped"
|
||||
Starting = "Starting"
|
||||
Started = "Started"
|
||||
Stopping = "Stopping"
|
||||
)
|
||||
|
||||
const (
|
||||
EmptyConfiguration = "EmptyConfiguration"
|
||||
StartCommandServer = "StartCommandServer"
|
||||
CreateService = "CreateService"
|
||||
StartService = "StartService"
|
||||
)
|
||||
405
global/global.go
405
global/global.go
@@ -1,405 +0,0 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hiddify/libcore/config"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
var box *libbox.BoxService
|
||||
var configOptions *config.ConfigOptions
|
||||
var activeConfigPath *string
|
||||
var logFactory *log.Factory
|
||||
|
||||
func setup(baseDir string, workingDir string, tempDir string, statusPort int64, debug bool) error {
|
||||
Setup(baseDir, workingDir, tempDir)
|
||||
statusPropagationPort = statusPort
|
||||
|
||||
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 err
|
||||
}
|
||||
logFactory = &factory
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse(path string, tempPath string, debug bool) error {
|
||||
config, err := config.ParseConfig(tempPath, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(path, config, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func changeConfigOptions(configOptionsJson string) error {
|
||||
configOptions = &config.ConfigOptions{}
|
||||
err := json.Unmarshal([]byte(configOptionsJson), configOptions)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if configOptions.Warp.WireguardConfigStr != "" {
|
||||
err := json.Unmarshal([]byte(configOptions.Warp.WireguardConfigStr), &configOptions.Warp.WireguardConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateConfig(path string) (string, error) {
|
||||
config, err := generateConfigFromFile(path, *configOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func generateConfigFromFile(path string, configOpt config.ConfigOptions) (string, error) {
|
||||
os.Chdir(filepath.Dir(path))
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options, err := parseConfig(string(content))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
config, err := config.BuildConfigJson(configOpt, options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func start(configPath string, disableMemoryLimit bool) error {
|
||||
if status != Stopped {
|
||||
return nil
|
||||
}
|
||||
propagateStatus(Starting)
|
||||
|
||||
activeConfigPath = &configPath
|
||||
|
||||
libbox.SetMemoryLimit(!disableMemoryLimit)
|
||||
err := startService(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func startService(delayStart bool) error {
|
||||
content, err := os.ReadFile(*activeConfigPath)
|
||||
if err != nil {
|
||||
return stopAndAlert(EmptyConfiguration, err)
|
||||
}
|
||||
options, err := parseConfig(string(content))
|
||||
if err != nil {
|
||||
return stopAndAlert(EmptyConfiguration, err)
|
||||
}
|
||||
os.Chdir(filepath.Dir(*activeConfigPath))
|
||||
var patchedOptions *option.Options
|
||||
patchedOptions, err = config.BuildConfig(*configOptions, options)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error building config: %w", err)
|
||||
}
|
||||
|
||||
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "tunnel-current-config.json"), *patchedOptions)
|
||||
|
||||
err = startCommandServer(*logFactory)
|
||||
if err != nil {
|
||||
return stopAndAlert(StartCommandServer, err)
|
||||
}
|
||||
|
||||
instance, err := NewService(*patchedOptions)
|
||||
if err != nil {
|
||||
return stopAndAlert(CreateService, err)
|
||||
}
|
||||
|
||||
if delayStart {
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
|
||||
err = instance.Start()
|
||||
if err != nil {
|
||||
return stopAndAlert(StartService, err)
|
||||
}
|
||||
box = instance
|
||||
commandServer.SetService(box)
|
||||
|
||||
propagateStatus(Started)
|
||||
return nil
|
||||
}
|
||||
|
||||
func stop() error {
|
||||
if status != Started {
|
||||
return nil
|
||||
}
|
||||
if box == nil {
|
||||
return errors.New("instance not found")
|
||||
}
|
||||
config.DeactivateTunnelService()
|
||||
propagateStatus(Stopping)
|
||||
|
||||
commandServer.SetService(nil)
|
||||
err := box.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
box = nil
|
||||
|
||||
err = commandServer.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandServer = nil
|
||||
propagateStatus(Stopped)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func restart(configPath string, disableMemoryLimit bool) error {
|
||||
log.Debug("[Service] Restarting")
|
||||
|
||||
if status != Started {
|
||||
return nil
|
||||
}
|
||||
if box == nil {
|
||||
return errors.New("instance not found")
|
||||
}
|
||||
|
||||
err := stop()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
propagateStatus(Starting)
|
||||
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
|
||||
activeConfigPath = &configPath
|
||||
libbox.SetMemoryLimit(!disableMemoryLimit)
|
||||
gErr := startService(false)
|
||||
if gErr != nil {
|
||||
return gErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func startCommandClient(command int, port int64) error {
|
||||
err := StartCommand(int32(command), port, *logFactory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopCommandClient(command int) error {
|
||||
err := StopCommand(int32(command))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func selectOutbound(groupTag string, outboundTag string) error {
|
||||
err := libbox.NewStandaloneCommandClient().SelectOutbound(groupTag, outboundTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func urlTest(groupTag string) error {
|
||||
err := libbox.NewStandaloneCommandClient().URLTest(groupTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func StartServiceC(delayStart bool, content string) error {
|
||||
if box != nil {
|
||||
return errors.New("instance already started")
|
||||
}
|
||||
options, err := parseConfig(content)
|
||||
// if err != nil {
|
||||
// return stopAndAlert(EmptyConfiguration, err)
|
||||
// }
|
||||
// configOptions = &config.ConfigOptions{}
|
||||
// patchedOptions, err := config.BuildConfig(*configOptions, options)
|
||||
|
||||
// options = *patchedOptions
|
||||
|
||||
// config.SaveCurrentConfig(filepath.Join(sWorkingPath, "custom-current-config.json"), options)
|
||||
// if err != nil {
|
||||
// fmt.Printf("Error in saving config: %v\n", err)
|
||||
// return err
|
||||
// }
|
||||
|
||||
// err = startCommandServer(*logFactory)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
instance, err := NewService(options)
|
||||
if err != nil {
|
||||
// return stopAndAlert(CreateService, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// if delayStart {
|
||||
// time.Sleep(250 * time.Millisecond)
|
||||
// }
|
||||
|
||||
err = instance.Start()
|
||||
if err != nil {
|
||||
// return stopAndAlert(StartService, err)
|
||||
fmt.Printf("String Service Error: %v\n", err)
|
||||
return err
|
||||
}
|
||||
box = instance
|
||||
// commandServer.SetService(box)
|
||||
|
||||
status = Started
|
||||
return nil
|
||||
}
|
||||
func StopServiceC() error {
|
||||
// if status != Started {
|
||||
// return errors.New("instance not started")
|
||||
// }
|
||||
config.DeactivateTunnelService()
|
||||
if box == nil {
|
||||
return errors.New("instance not found")
|
||||
}
|
||||
// propagateStatus(Stopping)
|
||||
err := box.Close()
|
||||
// commandServer.SetService(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
box = nil
|
||||
|
||||
// err = commandServer.Close()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
commandServer = nil
|
||||
status = Stopped
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetupC(baseDir string, workDir string, tempDir string, debug bool) error {
|
||||
err := os.MkdirAll(baseDir, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(workDir, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(tempDir, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Setup(baseDir, workDir, tempDir)
|
||||
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 err
|
||||
}
|
||||
logFactory = &factory
|
||||
return nil
|
||||
}
|
||||
|
||||
func MakeConfig(Ipv6 bool, ServerPort int, StrictRoute bool, EndpointIndependentNat bool, Stack string) string {
|
||||
var ipv6 string
|
||||
if Ipv6 {
|
||||
ipv6 = ` "inet6_address": "fdfe:dcba:9876::1/126",`
|
||||
} else {
|
||||
ipv6 = ""
|
||||
}
|
||||
base := `{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"tag": "tun-in",
|
||||
"interface_name": "HiddifyTunnel",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
` + ipv6 + `
|
||||
"mtu": 9000,
|
||||
"auto_route": true,
|
||||
"strict_route": ` + fmt.Sprintf("%t", StrictRoute) + `,
|
||||
"endpoint_independent_nat": ` + fmt.Sprintf("%t", EndpointIndependentNat) + `,
|
||||
"stack": "` + Stack + `"
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"tag": "socks-out",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": ` + fmt.Sprintf("%d", ServerPort) + `,
|
||||
"version": "5"
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
return base
|
||||
}
|
||||
|
||||
func WriteParameters(Ipv6 bool, ServerPort int, StrictRoute bool, EndpointIndependentNat bool, Stack string) error {
|
||||
parameters := fmt.Sprintf("%t,%d,%t,%t,%s", Ipv6, ServerPort, StrictRoute, EndpointIndependentNat, Stack)
|
||||
err := os.WriteFile("parameters.config", []byte(parameters), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func ReadParameters() (bool, int, bool, bool, string, error) {
|
||||
Data, err := os.ReadFile("parameters.config")
|
||||
if err != nil {
|
||||
return false, 0, false, false, "", err
|
||||
}
|
||||
DataSlice := strings.Split(string(Data), ",")
|
||||
Ipv6, _ := strconv.ParseBool(DataSlice[0])
|
||||
ServerPort, _ := strconv.Atoi(DataSlice[1])
|
||||
StrictRoute, _ := strconv.ParseBool(DataSlice[2])
|
||||
EndpointIndependentNat, _ := strconv.ParseBool(DataSlice[3])
|
||||
stack := DataSlice[4]
|
||||
return Ipv6, ServerPort, StrictRoute, EndpointIndependentNat, stack, nil
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package global
|
||||
|
||||
type Stack string
|
||||
|
||||
const (
|
||||
System Stack = "system"
|
||||
GVisor Stack = "gvisor"
|
||||
Mixed Stack = "mixed"
|
||||
// LWIP Stack = "LWIP"
|
||||
)
|
||||
|
||||
type Parameters struct {
|
||||
Ipv6 bool
|
||||
ServerPort int
|
||||
StrictRoute bool
|
||||
EndpointIndependentNat bool
|
||||
Stack Stack
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"runtime"
|
||||
runtimeDebug "runtime/debug"
|
||||
|
||||
B "github.com/sagernet/sing-box"
|
||||
"github.com/sagernet/sing-box/common/urltest"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/service"
|
||||
"github.com/sagernet/sing/service/filemanager"
|
||||
"github.com/sagernet/sing/service/pause"
|
||||
)
|
||||
|
||||
var (
|
||||
sWorkingPath string
|
||||
sTempPath string
|
||||
sUserID int
|
||||
sGroupID int
|
||||
)
|
||||
|
||||
func Setup(basePath string, workingPath string, tempPath string) {
|
||||
tcpConn := runtime.GOOS == "windows" //TODO add TVOS
|
||||
libbox.Setup(basePath, workingPath, tempPath, tcpConn)
|
||||
sWorkingPath = workingPath
|
||||
os.Chdir(sWorkingPath)
|
||||
sTempPath = tempPath
|
||||
sUserID = os.Getuid()
|
||||
sGroupID = os.Getgid()
|
||||
}
|
||||
|
||||
func NewService(options option.Options) (*libbox.BoxService, error) {
|
||||
runtimeDebug.FreeOSMemory()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
|
||||
urlTestHistoryStorage := urltest.NewHistoryStorage()
|
||||
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
|
||||
instance, err := B.New(B.Options{
|
||||
Context: ctx,
|
||||
Options: options,
|
||||
})
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, E.Cause(err, "create service")
|
||||
}
|
||||
runtimeDebug.FreeOSMemory()
|
||||
service := libbox.NewBoxService(
|
||||
ctx,
|
||||
cancel,
|
||||
instance,
|
||||
service.FromContext[pause.Manager](ctx),
|
||||
urlTestHistoryStorage,
|
||||
)
|
||||
return &service, nil
|
||||
}
|
||||
|
||||
func parseConfig(configContent string) (option.Options, error) {
|
||||
var options option.Options
|
||||
err := options.UnmarshalJSON([]byte(configContent))
|
||||
if err != nil {
|
||||
return option.Options{}, E.Cause(err, "decode config")
|
||||
}
|
||||
return options, nil
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hiddify/libcore/bridge"
|
||||
)
|
||||
|
||||
var statusPropagationPort int64
|
||||
var status = Stopped
|
||||
|
||||
type StatusMessage struct {
|
||||
Status string `json:"status"`
|
||||
Alert *string `json:"alert"`
|
||||
Message *string `json:"message"`
|
||||
}
|
||||
|
||||
func propagateStatus(newStatus string) {
|
||||
status = newStatus
|
||||
|
||||
msg, _ := json.Marshal(StatusMessage{Status: status})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
}
|
||||
|
||||
func stopAndAlert(alert string, err error) error {
|
||||
status = Stopped
|
||||
message := err.Error()
|
||||
|
||||
msg, _ := json.Marshal(StatusMessage{Status: status, Alert: &alert, Message: &message})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
return nil
|
||||
}
|
||||
@@ -199,34 +199,6 @@ func (LogType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_b52c484803f63ee3, []int{4}
|
||||
}
|
||||
|
||||
type StackType int32
|
||||
|
||||
const (
|
||||
StackType_SYSTEM StackType = 0
|
||||
StackType_GVISOR StackType = 1
|
||||
StackType_MIXED StackType = 2
|
||||
)
|
||||
|
||||
var StackType_name = map[int32]string{
|
||||
0: "SYSTEM",
|
||||
1: "GVISOR",
|
||||
2: "MIXED",
|
||||
}
|
||||
|
||||
var StackType_value = map[string]int32{
|
||||
"SYSTEM": 0,
|
||||
"GVISOR": 1,
|
||||
"MIXED": 2,
|
||||
}
|
||||
|
||||
func (x StackType) String() string {
|
||||
return proto.EnumName(StackType_name, int32(x))
|
||||
}
|
||||
|
||||
func (StackType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_b52c484803f63ee3, []int{5}
|
||||
}
|
||||
|
||||
type CoreInfoResponse struct {
|
||||
CoreState CoreState `protobuf:"varint,1,opt,name=core_state,json=coreState,proto3,enum=hiddifyrpc.CoreState" json:"core_state,omitempty"`
|
||||
MessageType MessageType `protobuf:"varint,2,opt,name=message_type,json=messageType,proto3,enum=hiddifyrpc.MessageType" json:"message_type,omitempty"`
|
||||
@@ -288,6 +260,7 @@ type StartRequest struct {
|
||||
DisableMemoryLimit bool `protobuf:"varint,3,opt,name=disable_memory_limit,json=disableMemoryLimit,proto3" json:"disable_memory_limit,omitempty"`
|
||||
DelayStart bool `protobuf:"varint,4,opt,name=delay_start,json=delayStart,proto3" json:"delay_start,omitempty"`
|
||||
EnableOldCommandServer bool `protobuf:"varint,5,opt,name=enable_old_command_server,json=enableOldCommandServer,proto3" json:"enable_old_command_server,omitempty"`
|
||||
EnableRawConfig bool `protobuf:"varint,6,opt,name=enable_raw_config,json=enableRawConfig,proto3" json:"enable_raw_config,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -353,6 +326,13 @@ func (m *StartRequest) GetEnableOldCommandServer() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *StartRequest) GetEnableRawConfig() bool {
|
||||
if m != nil {
|
||||
return m.EnableRawConfig
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type SetupRequest struct {
|
||||
BasePath string `protobuf:"bytes,1,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"`
|
||||
WorkingPath string `protobuf:"bytes,2,opt,name=working_path,json=workingPath,proto3" json:"working_path,omitempty"`
|
||||
@@ -1562,14 +1542,14 @@ func (m *StopRequest) XXX_DiscardUnknown() {
|
||||
var xxx_messageInfo_StopRequest proto.InternalMessageInfo
|
||||
|
||||
type TunnelStartRequest struct {
|
||||
Ipv6 bool `protobuf:"varint,1,opt,name=ipv6,proto3" json:"ipv6,omitempty"`
|
||||
ServerPort int32 `protobuf:"varint,2,opt,name=server_port,json=serverPort,proto3" json:"server_port,omitempty"`
|
||||
StrictRoute bool `protobuf:"varint,3,opt,name=strict_route,json=strictRoute,proto3" json:"strict_route,omitempty"`
|
||||
EndpointIndependentNat bool `protobuf:"varint,4,opt,name=endpoint_independent_nat,json=endpointIndependentNat,proto3" json:"endpoint_independent_nat,omitempty"`
|
||||
Stack StackType `protobuf:"varint,5,opt,name=stack,proto3,enum=hiddifyrpc.StackType" json:"stack,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Ipv6 bool `protobuf:"varint,1,opt,name=ipv6,proto3" json:"ipv6,omitempty"`
|
||||
ServerPort int32 `protobuf:"varint,2,opt,name=server_port,json=serverPort,proto3" json:"server_port,omitempty"`
|
||||
StrictRoute bool `protobuf:"varint,3,opt,name=strict_route,json=strictRoute,proto3" json:"strict_route,omitempty"`
|
||||
EndpointIndependentNat bool `protobuf:"varint,4,opt,name=endpoint_independent_nat,json=endpointIndependentNat,proto3" json:"endpoint_independent_nat,omitempty"`
|
||||
Stack string `protobuf:"bytes,5,opt,name=stack,proto3" json:"stack,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *TunnelStartRequest) Reset() { *m = TunnelStartRequest{} }
|
||||
@@ -1625,11 +1605,11 @@ func (m *TunnelStartRequest) GetEndpointIndependentNat() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *TunnelStartRequest) GetStack() StackType {
|
||||
func (m *TunnelStartRequest) GetStack() string {
|
||||
if m != nil {
|
||||
return m.Stack
|
||||
}
|
||||
return StackType_SYSTEM
|
||||
return ""
|
||||
}
|
||||
|
||||
type TunnelResponse struct {
|
||||
@@ -1677,7 +1657,6 @@ func init() {
|
||||
proto.RegisterEnum("hiddifyrpc.MessageType", MessageType_name, MessageType_value)
|
||||
proto.RegisterEnum("hiddifyrpc.LogLevel", LogLevel_name, LogLevel_value)
|
||||
proto.RegisterEnum("hiddifyrpc.LogType", LogType_name, LogType_value)
|
||||
proto.RegisterEnum("hiddifyrpc.StackType", StackType_name, StackType_value)
|
||||
proto.RegisterType((*CoreInfoResponse)(nil), "hiddifyrpc.CoreInfoResponse")
|
||||
proto.RegisterType((*StartRequest)(nil), "hiddifyrpc.StartRequest")
|
||||
proto.RegisterType((*SetupRequest)(nil), "hiddifyrpc.SetupRequest")
|
||||
@@ -1711,132 +1690,131 @@ func init() {
|
||||
func init() { proto.RegisterFile("hiddifyrpc/hiddify.proto", fileDescriptor_b52c484803f63ee3) }
|
||||
|
||||
var fileDescriptor_b52c484803f63ee3 = []byte{
|
||||
// 2025 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xdd, 0x72, 0xdb, 0xc6,
|
||||
0x15, 0x36, 0x28, 0x52, 0x24, 0x0f, 0x49, 0x19, 0x5a, 0xc9, 0x32, 0xad, 0xd8, 0xb5, 0x83, 0x69,
|
||||
0x12, 0x55, 0x4d, 0xe5, 0x54, 0x71, 0xe3, 0xfe, 0x79, 0x3c, 0x14, 0x09, 0x29, 0xac, 0x28, 0x92,
|
||||
0x03, 0x40, 0x71, 0xdc, 0xce, 0x14, 0x03, 0x01, 0x2b, 0x1a, 0x15, 0x88, 0x45, 0x81, 0xa5, 0x12,
|
||||
0x4e, 0x3b, 0xbd, 0x68, 0x67, 0xfa, 0x02, 0x9d, 0xe9, 0x65, 0x1f, 0xa4, 0x37, 0x7d, 0x82, 0x5e,
|
||||
0xf5, 0x0d, 0x3a, 0x7d, 0x85, 0xde, 0x77, 0xf6, 0x07, 0x24, 0x40, 0x91, 0x56, 0x9a, 0xe4, 0x6e,
|
||||
0xf7, 0x9c, 0xb3, 0x07, 0xe7, 0x7f, 0xbf, 0x05, 0x34, 0xdf, 0xf8, 0x9e, 0xe7, 0x5f, 0x4e, 0xe3,
|
||||
0xc8, 0x7d, 0x2a, 0x97, 0x07, 0x51, 0x4c, 0x28, 0x41, 0x30, 0xe7, 0x68, 0x7f, 0x53, 0x40, 0x6d,
|
||||
0x93, 0x18, 0x77, 0xc3, 0x4b, 0x62, 0xe0, 0x24, 0x22, 0x61, 0x82, 0xd1, 0x33, 0x00, 0x97, 0xc4,
|
||||
0xd8, 0x4e, 0xa8, 0x43, 0x71, 0x53, 0x79, 0xa2, 0xec, 0x6d, 0x1c, 0xde, 0x3b, 0x98, 0x9f, 0x3a,
|
||||
0x60, 0x27, 0x4c, 0xc6, 0x34, 0xaa, 0x6e, 0xba, 0x44, 0x3f, 0x85, 0xfa, 0x18, 0x27, 0x89, 0x33,
|
||||
0xc2, 0x36, 0x9d, 0x46, 0xb8, 0x59, 0xe0, 0xe7, 0xee, 0x67, 0xcf, 0x9d, 0x09, 0xbe, 0x35, 0x8d,
|
||||
0xb0, 0x51, 0x1b, 0xcf, 0x37, 0xa8, 0x09, 0x65, 0xb9, 0x6d, 0xae, 0x3d, 0x51, 0xf6, 0xaa, 0x46,
|
||||
0xba, 0xd5, 0xfe, 0xa3, 0x40, 0xdd, 0xa4, 0x4e, 0x4c, 0x0d, 0xfc, 0xdb, 0x09, 0x4e, 0x28, 0x7a,
|
||||
0x0c, 0x35, 0x97, 0x84, 0x97, 0xfe, 0xc8, 0x8e, 0x1c, 0xfa, 0x86, 0x5b, 0x57, 0x35, 0x40, 0x90,
|
||||
0x86, 0x0e, 0x7d, 0x83, 0xde, 0x83, 0x0d, 0x29, 0xe0, 0x92, 0x90, 0xe2, 0x90, 0x72, 0x4b, 0xaa,
|
||||
0x46, 0x43, 0x50, 0xdb, 0x82, 0x88, 0x3e, 0x82, 0x6d, 0xcf, 0x4f, 0x9c, 0x8b, 0x00, 0xdb, 0x63,
|
||||
0x3c, 0x26, 0xf1, 0xd4, 0x0e, 0xfc, 0xb1, 0x4f, 0xf9, 0xf7, 0x2b, 0x06, 0x92, 0xbc, 0x33, 0xce,
|
||||
0xea, 0x31, 0x0e, 0xfb, 0xb2, 0x87, 0x03, 0x67, 0xca, 0xe2, 0x12, 0xd3, 0x66, 0x91, 0x0b, 0x02,
|
||||
0x27, 0x71, 0x0b, 0xd1, 0x4f, 0xe0, 0x01, 0x0e, 0xb9, 0x46, 0x12, 0x78, 0xb6, 0x4b, 0xc6, 0x63,
|
||||
0x27, 0xf4, 0xec, 0x04, 0xc7, 0xd7, 0x38, 0x6e, 0x96, 0xb8, 0xf8, 0x8e, 0x10, 0x18, 0x04, 0x5e,
|
||||
0x5b, 0xb0, 0x4d, 0xce, 0xd5, 0xae, 0xa0, 0x6e, 0x62, 0x3a, 0x89, 0x52, 0x2f, 0xdf, 0x81, 0xea,
|
||||
0x85, 0x93, 0xe0, 0xac, 0x8f, 0x15, 0x46, 0xe0, 0x1e, 0xbe, 0x0b, 0xf5, 0x2f, 0x48, 0x7c, 0xe5,
|
||||
0x87, 0x32, 0x06, 0xc2, 0xbf, 0x9a, 0xa4, 0x71, 0x91, 0x77, 0xa0, 0x4a, 0xf1, 0x38, 0x12, 0x7c,
|
||||
0x11, 0xd2, 0x0a, 0x23, 0x30, 0xa6, 0xe6, 0x42, 0x65, 0x96, 0xeb, 0x17, 0xd0, 0x88, 0xe5, 0xda,
|
||||
0x76, 0x89, 0x97, 0xa6, 0xbb, 0x99, 0x4d, 0x5b, 0x2a, 0xdc, 0x26, 0x1e, 0x36, 0xea, 0x71, 0x66,
|
||||
0x97, 0x4d, 0x5c, 0x21, 0x9f, 0x38, 0x0d, 0xea, 0x9f, 0xe2, 0x20, 0x20, 0xa9, 0x47, 0x08, 0x8a,
|
||||
0xa1, 0x33, 0xc6, 0xd2, 0x19, 0xbe, 0xd6, 0xbe, 0x07, 0x0d, 0x29, 0x23, 0xad, 0xc9, 0xa8, 0x53,
|
||||
0xf2, 0xea, 0xca, 0x50, 0xd2, 0xc7, 0x11, 0x9d, 0x6a, 0xff, 0x28, 0x00, 0x98, 0xd3, 0x84, 0xe2,
|
||||
0x31, 0xab, 0x59, 0xb4, 0x03, 0xeb, 0x22, 0x7d, 0xfc, 0xc0, 0x9a, 0x21, 0x77, 0xe8, 0x3b, 0x00,
|
||||
0x23, 0x12, 0x93, 0x09, 0xf5, 0x43, 0x9c, 0x70, 0xdb, 0x4a, 0x46, 0x86, 0x22, 0xab, 0x24, 0xc4,
|
||||
0x2e, 0xf5, 0x49, 0x98, 0xd8, 0x7e, 0xc8, 0xa3, 0x54, 0xe2, 0x55, 0x92, 0x52, 0xbb, 0x21, 0xfa,
|
||||
0x00, 0xee, 0x66, 0xc5, 0xc8, 0x44, 0xe4, 0xbd, 0x64, 0x64, 0x4f, 0x0f, 0x26, 0x14, 0x7d, 0x1f,
|
||||
0x36, 0x69, 0xec, 0x5c, 0x5e, 0xfa, 0xae, 0xed, 0x5c, 0x3b, 0x7e, 0xc0, 0xb2, 0x2c, 0x73, 0xae,
|
||||
0x4a, 0x46, 0x2b, 0xa5, 0x33, 0xa3, 0x27, 0x51, 0xe0, 0x87, 0x57, 0xcd, 0x75, 0x61, 0xb4, 0xd8,
|
||||
0xa1, 0x5d, 0xa8, 0x78, 0xe4, 0x8b, 0x90, 0x73, 0xca, 0x9c, 0x33, 0xdb, 0xb3, 0xa4, 0x0b, 0x29,
|
||||
0x9b, 0x12, 0xea, 0x04, 0xcd, 0x0a, 0xe7, 0xd7, 0x04, 0xcd, 0x62, 0x24, 0xe6, 0x53, 0x2a, 0x2e,
|
||||
0x85, 0xaa, 0x5c, 0xa8, 0x91, 0x52, 0xb9, 0x98, 0xf6, 0x27, 0x05, 0x36, 0x07, 0x13, 0x7a, 0x41,
|
||||
0x26, 0xa1, 0x77, 0x12, 0x93, 0x49, 0xd4, 0xa5, 0x78, 0x8c, 0x54, 0x58, 0xa3, 0xce, 0x48, 0x86,
|
||||
0x9d, 0x2d, 0x59, 0xc6, 0x66, 0x8d, 0x5c, 0x35, 0xf8, 0x1a, 0x69, 0xd0, 0x98, 0xc4, 0x81, 0x4d,
|
||||
0x71, 0x42, 0x6d, 0xea, 0x8f, 0x45, 0xbb, 0x32, 0x33, 0xe2, 0xc0, 0xc2, 0x09, 0xb5, 0xfc, 0x31,
|
||||
0x46, 0xdf, 0x85, 0x8d, 0x99, 0x0c, 0xef, 0x0e, 0x19, 0xb2, 0xba, 0x14, 0xea, 0x30, 0x9a, 0xf6,
|
||||
0x67, 0x05, 0x1a, 0x39, 0x2b, 0xbe, 0xa2, 0x05, 0xbb, 0x50, 0x49, 0x70, 0x80, 0x5d, 0x8a, 0xbd,
|
||||
0xb4, 0xb0, 0xd3, 0x3d, 0xfa, 0x18, 0x4a, 0x3e, 0xc5, 0xe3, 0xa4, 0x59, 0x7c, 0xb2, 0xb6, 0x57,
|
||||
0x3b, 0x7c, 0x94, 0x2d, 0xe2, 0x1b, 0x1e, 0x1b, 0x42, 0x56, 0xeb, 0x2c, 0x44, 0xa3, 0xe7, 0x27,
|
||||
0x14, 0x3d, 0x4d, 0x35, 0x29, 0x5c, 0xd3, 0x83, 0x95, 0x9a, 0x52, 0x2d, 0x03, 0xa8, 0xbd, 0x72,
|
||||
0xe2, 0xa8, 0xe5, 0xba, 0x64, 0x12, 0x52, 0xf4, 0x08, 0xc0, 0x11, 0x4b, 0xdb, 0xf7, 0xa4, 0x4b,
|
||||
0x55, 0x49, 0xe9, 0x7a, 0x2c, 0x99, 0x8e, 0xeb, 0xe2, 0x24, 0xb1, 0x29, 0xb9, 0xc2, 0x61, 0xda,
|
||||
0xc1, 0x82, 0x66, 0x31, 0x92, 0xf6, 0x77, 0x05, 0xb6, 0x98, 0xc6, 0x57, 0x7e, 0x8c, 0x47, 0x13,
|
||||
0x27, 0xf6, 0xda, 0x7c, 0x7c, 0xb1, 0x29, 0x14, 0xc5, 0xfe, 0xb5, 0x43, 0xb1, 0x7d, 0x85, 0xa7,
|
||||
0xe9, 0xfc, 0x93, 0xa4, 0x53, 0x3c, 0x45, 0x1f, 0x02, 0x0a, 0x88, 0xeb, 0x04, 0xb6, 0xe3, 0x79,
|
||||
0x31, 0xfb, 0x84, 0x1f, 0x5d, 0x3f, 0x93, 0x5f, 0x50, 0x39, 0xa7, 0x25, 0x18, 0xdd, 0xe8, 0xfa,
|
||||
0xd9, 0x52, 0xe9, 0x4f, 0x64, 0x60, 0x17, 0xa5, 0x3f, 0x41, 0xef, 0xc3, 0xdd, 0x08, 0xe3, 0xd8,
|
||||
0x8e, 0x26, 0x17, 0x81, 0xef, 0x72, 0x03, 0x8a, 0x62, 0xb8, 0x32, 0xf2, 0x90, 0x53, 0x4f, 0xf1,
|
||||
0x54, 0xfb, 0xab, 0x02, 0x3b, 0xcc, 0xf8, 0x13, 0x1c, 0xe2, 0xd8, 0x61, 0x4d, 0x32, 0x6b, 0xf1,
|
||||
0x1f, 0x42, 0x59, 0xc6, 0x81, 0xdb, 0x5e, 0xcb, 0xdf, 0x10, 0x99, 0x18, 0x1a, 0xa9, 0x1c, 0x2b,
|
||||
0x8c, 0x80, 0x8c, 0xa4, 0x0b, 0x6c, 0x89, 0x9e, 0xc3, 0xba, 0x98, 0xe6, 0xdc, 0xd2, 0xda, 0xe1,
|
||||
0xe3, 0x45, 0x1d, 0x0b, 0x51, 0x33, 0xa4, 0xb8, 0x76, 0x0a, 0x9b, 0x62, 0x78, 0x0c, 0x63, 0xf2,
|
||||
0x25, 0x1b, 0xdb, 0x74, 0x92, 0xa0, 0x87, 0x50, 0x9d, 0xf7, 0xac, 0xc2, 0x7b, 0x76, 0x4e, 0x60,
|
||||
0x33, 0x49, 0x0c, 0x6d, 0x8f, 0x5b, 0x50, 0x31, 0xd2, 0xad, 0xf6, 0x7b, 0xa8, 0x0f, 0x9d, 0x38,
|
||||
0xc1, 0xe9, 0x88, 0x6b, 0x42, 0x39, 0xbd, 0x72, 0xe4, 0xf4, 0x92, 0xdb, 0xc5, 0x4b, 0xab, 0x70,
|
||||
0xe3, 0xd2, 0x7a, 0xdb, 0xbc, 0x46, 0xdb, 0x50, 0xf2, 0xf0, 0xc5, 0x64, 0x24, 0xaf, 0x1c, 0xb1,
|
||||
0xd1, 0xfe, 0xa8, 0x40, 0x43, 0x7e, 0xfe, 0x5b, 0x9b, 0xe5, 0xf9, 0x1b, 0x73, 0x66, 0xfe, 0xea,
|
||||
0xeb, 0xb9, 0x07, 0xbb, 0xed, 0x37, 0x4e, 0x38, 0xc2, 0x22, 0xce, 0x83, 0x88, 0x0f, 0xc4, 0x34,
|
||||
0x20, 0x07, 0xb0, 0x25, 0xdd, 0x26, 0x82, 0x61, 0xff, 0x26, 0x21, 0xa1, 0x0c, 0xce, 0xa6, 0x9b,
|
||||
0x3d, 0xf2, 0x8b, 0x84, 0x84, 0xda, 0xaf, 0xe1, 0x9e, 0xac, 0x18, 0xa9, 0x2f, 0x73, 0x79, 0x64,
|
||||
0x6e, 0x42, 0xbe, 0xce, 0x87, 0xac, 0xb0, 0x2a, 0x64, 0x6b, 0xd9, 0x90, 0xbd, 0x84, 0x9d, 0x45,
|
||||
0xfd, 0x32, 0x74, 0x37, 0x41, 0x83, 0xb2, 0x04, 0x34, 0x68, 0xaf, 0xe0, 0x9e, 0xc9, 0x87, 0x4d,
|
||||
0x3a, 0x03, 0x32, 0xf7, 0xf5, 0x88, 0x8d, 0x03, 0x7b, 0x3e, 0xc1, 0x2a, 0x9c, 0x60, 0x39, 0x23,
|
||||
0xd6, 0xed, 0x44, 0xca, 0x73, 0xbe, 0xec, 0xf6, 0x94, 0x66, 0x39, 0x23, 0xed, 0x07, 0xb0, 0x71,
|
||||
0x2e, 0xa6, 0xe3, 0x57, 0xd1, 0xa8, 0xfd, 0x01, 0x1e, 0xa4, 0x8e, 0xb0, 0x6a, 0xcf, 0x07, 0xeb,
|
||||
0x31, 0xd4, 0x02, 0xdf, 0xc5, 0xac, 0x0a, 0x32, 0x13, 0x42, 0x92, 0xd8, 0x84, 0xc8, 0x0f, 0xa7,
|
||||
0xc2, 0x6d, 0xc3, 0x69, 0xed, 0xe6, 0x70, 0x7a, 0x01, 0x0f, 0x4d, 0x4c, 0x33, 0x9d, 0xa4, 0x8b,
|
||||
0x96, 0x48, 0x4d, 0x78, 0x04, 0xe0, 0x27, 0x76, 0xda, 0x36, 0xb2, 0xa5, 0xfc, 0x44, 0x4a, 0x69,
|
||||
0xbf, 0x03, 0xe8, 0x91, 0x91, 0x44, 0x83, 0x68, 0x1f, 0x4a, 0x01, 0xbe, 0xc6, 0x81, 0x2c, 0xd7,
|
||||
0xed, 0x6c, 0xb9, 0xf6, 0xc8, 0xa8, 0xc7, 0x78, 0x86, 0x10, 0x41, 0x1f, 0x64, 0x6e, 0x84, 0x8d,
|
||||
0xc3, 0xad, 0x05, 0x51, 0x0e, 0x2c, 0xc5, 0x35, 0xb1, 0xba, 0x64, 0x1b, 0x50, 0x33, 0x29, 0x49,
|
||||
0x91, 0x96, 0xf6, 0x2f, 0x05, 0x90, 0x35, 0x09, 0x43, 0x1c, 0xe4, 0x60, 0x26, 0x82, 0x22, 0x9f,
|
||||
0x84, 0xc2, 0x76, 0xbe, 0x66, 0x81, 0x15, 0x60, 0xce, 0x8e, 0x48, 0x4c, 0x53, 0x50, 0x21, 0x48,
|
||||
0x43, 0x12, 0x53, 0x16, 0xb9, 0x84, 0xc6, 0xbe, 0x4b, 0x6d, 0x86, 0x33, 0xb0, 0x2c, 0xbe, 0x9a,
|
||||
0xa0, 0x19, 0x8c, 0x84, 0x7e, 0x0c, 0x4d, 0x1c, 0x7a, 0x11, 0xf1, 0x59, 0xf0, 0x43, 0x0f, 0x47,
|
||||
0x38, 0xf4, 0x70, 0x48, 0xed, 0xd0, 0x49, 0x11, 0xe5, 0x4e, 0xca, 0xef, 0xce, 0xd9, 0x7d, 0x87,
|
||||
0x21, 0x8c, 0x52, 0x42, 0x1d, 0xf7, 0x8a, 0xa3, 0x8a, 0x05, 0x40, 0x6e, 0x32, 0x06, 0xf7, 0x5e,
|
||||
0xc8, 0x68, 0xfb, 0xb0, 0x21, 0x9c, 0xba, 0x1d, 0x5a, 0xed, 0x6b, 0x50, 0xcf, 0x4e, 0x05, 0xb4,
|
||||
0x0e, 0x85, 0xc1, 0xa9, 0x7a, 0x07, 0x01, 0xac, 0x1f, 0xb7, 0xba, 0x3d, 0xbd, 0xa3, 0x2a, 0xfb,
|
||||
0x2d, 0xa8, 0xce, 0x40, 0x3f, 0xaa, 0x41, 0xd9, 0xb4, 0x06, 0xc3, 0xa1, 0xde, 0x51, 0xef, 0xa0,
|
||||
0x3a, 0x54, 0x4c, 0xab, 0x65, 0x58, 0xdd, 0xfe, 0x89, 0xaa, 0x08, 0x56, 0xcb, 0xb0, 0xf4, 0x8e,
|
||||
0x5a, 0x10, 0xac, 0xc1, 0x70, 0xc8, 0x58, 0x6b, 0xfb, 0xff, 0x2c, 0x40, 0x2d, 0xf3, 0x00, 0x40,
|
||||
0x55, 0x28, 0xe9, 0x67, 0x43, 0xeb, 0xb5, 0x7a, 0x07, 0xdd, 0x87, 0x2d, 0xbe, 0xb4, 0xdb, 0x83,
|
||||
0xfe, 0x71, 0xf7, 0xe4, 0xdc, 0x68, 0x59, 0xdd, 0x41, 0x5f, 0x55, 0x50, 0x13, 0xb6, 0xb9, 0x3a,
|
||||
0xbb, 0x3d, 0x38, 0x3b, 0x6b, 0xf5, 0x3b, 0xb6, 0xa9, 0x1b, 0x9f, 0xe9, 0x86, 0x5a, 0x40, 0x08,
|
||||
0x36, 0xda, 0x86, 0xde, 0xb2, 0x74, 0x4e, 0xea, 0xb6, 0x75, 0x75, 0x0d, 0x6d, 0x42, 0x43, 0x48,
|
||||
0xa7, 0xa4, 0x22, 0xda, 0x06, 0xf5, 0xbc, 0xaf, 0x7f, 0x3e, 0xd4, 0xdb, 0x96, 0xde, 0xb1, 0x75,
|
||||
0xc3, 0x18, 0x18, 0x6a, 0x09, 0x6d, 0xc1, 0xdd, 0x56, 0xcf, 0xd0, 0x5b, 0x9d, 0xd7, 0x76, 0x6a,
|
||||
0xed, 0x7a, 0x9e, 0x28, 0xbc, 0x2b, 0xa3, 0x1d, 0x40, 0xdd, 0xbe, 0x69, 0xb5, 0xfa, 0x6d, 0xdd,
|
||||
0xee, 0x0f, 0x2c, 0xfb, 0x78, 0x70, 0xde, 0xef, 0xa8, 0x15, 0x66, 0x58, 0x8e, 0x9e, 0x9e, 0xa8,
|
||||
0x2e, 0xe1, 0x88, 0x0f, 0x00, 0x7a, 0x00, 0xf7, 0xb8, 0x01, 0xf6, 0xd1, 0x79, 0xb7, 0xd7, 0xe9,
|
||||
0xf6, 0x4f, 0xa4, 0xbb, 0x6a, 0x8d, 0x1d, 0x12, 0xac, 0x61, 0xcb, 0x30, 0x33, 0x9c, 0xfa, 0x9c,
|
||||
0xc3, 0x2c, 0xcb, 0x70, 0x1a, 0xfb, 0x47, 0x50, 0x49, 0xbb, 0x83, 0xc5, 0xb2, 0xa3, 0x1f, 0x9d,
|
||||
0x9f, 0xa8, 0x77, 0x50, 0x05, 0x8a, 0xdd, 0xfe, 0xf1, 0x40, 0xe4, 0xe2, 0x55, 0xcb, 0xe8, 0xb3,
|
||||
0xe8, 0x17, 0x78, 0xb4, 0xb9, 0xf7, 0x6b, 0x6c, 0x79, 0xdc, 0xb2, 0x5a, 0x3d, 0xb5, 0xb8, 0xff,
|
||||
0x21, 0x94, 0x65, 0xdb, 0xb0, 0x73, 0xed, 0x81, 0xa1, 0xab, 0x77, 0x78, 0x0e, 0x65, 0x00, 0x15,
|
||||
0x56, 0x04, 0xf2, 0x8b, 0x85, 0xfd, 0x03, 0xa8, 0xce, 0x0a, 0x8d, 0x31, 0xcc, 0xd7, 0xa6, 0xa5,
|
||||
0x9f, 0x89, 0x4a, 0x39, 0xf9, 0xac, 0x6b, 0x0e, 0x0c, 0x55, 0x61, 0xda, 0xcf, 0xba, 0x9f, 0xb3,
|
||||
0xfc, 0x1f, 0xfe, 0x45, 0x81, 0x12, 0xc7, 0xf7, 0xe8, 0x25, 0x54, 0x4c, 0x67, 0x2a, 0xd6, 0xb9,
|
||||
0xeb, 0x28, 0xfb, 0x44, 0xd8, 0x7d, 0xb0, 0x84, 0x23, 0xab, 0xb7, 0x0b, 0x1b, 0xa9, 0x02, 0x93,
|
||||
0xc6, 0xd8, 0x19, 0x7f, 0x2d, 0x35, 0x7b, 0xca, 0x47, 0xca, 0xe1, 0xbf, 0xab, 0x50, 0x64, 0xb5,
|
||||
0x8c, 0x5e, 0x42, 0x49, 0xbc, 0xdb, 0x9a, 0x0b, 0xad, 0x34, 0x9b, 0x02, 0xbb, 0x0f, 0x17, 0x5f,
|
||||
0xbd, 0xb9, 0x77, 0xf2, 0xd9, 0xfc, 0xed, 0xcc, 0x40, 0x23, 0x1b, 0xc8, 0xe8, 0x7e, 0x5e, 0xd7,
|
||||
0x6c, 0xce, 0xbc, 0x5d, 0x15, 0x33, 0x0c, 0x9d, 0xce, 0x01, 0x71, 0xc2, 0xdf, 0x36, 0x2b, 0x75,
|
||||
0xad, 0x06, 0xb6, 0xcc, 0x0e, 0xae, 0x6c, 0x00, 0x9b, 0x67, 0x8e, 0x1f, 0x7e, 0x7b, 0x0a, 0x3b,
|
||||
0xd0, 0x38, 0x49, 0x47, 0xfe, 0xdb, 0x95, 0xed, 0xe4, 0x18, 0xb3, 0x03, 0x5c, 0xcb, 0x73, 0x28,
|
||||
0xf1, 0x77, 0xee, 0x42, 0xcc, 0x33, 0x4f, 0xdf, 0xdd, 0xed, 0x65, 0x70, 0x05, 0xfd, 0x1c, 0x4a,
|
||||
0x1c, 0xec, 0xe4, 0x0f, 0x66, 0xe1, 0x57, 0x3e, 0xef, 0x79, 0x64, 0xf4, 0x2b, 0xd8, 0x5a, 0x02,
|
||||
0x53, 0xd0, 0xfb, 0xb9, 0x9c, 0xac, 0xc4, 0x31, 0xb7, 0x94, 0xc1, 0xb1, 0xfc, 0x43, 0xc1, 0x9e,
|
||||
0xf2, 0xbe, 0x8b, 0xbf, 0x76, 0x39, 0x3d, 0x87, 0x22, 0x0b, 0x23, 0xda, 0xcc, 0x4a, 0xf1, 0x47,
|
||||
0xef, 0x2d, 0x07, 0x5b, 0x50, 0x36, 0x70, 0xf2, 0x8d, 0x4a, 0x99, 0xf5, 0x57, 0x0e, 0xd8, 0xa0,
|
||||
0x77, 0xf3, 0x09, 0x5a, 0x02, 0x7a, 0x56, 0x64, 0xea, 0x67, 0x50, 0x96, 0x50, 0x06, 0xed, 0x66,
|
||||
0x05, 0xf2, 0xf8, 0x66, 0xc5, 0x61, 0x1b, 0xd0, 0x4d, 0x60, 0x83, 0xde, 0xcb, 0xca, 0xae, 0x04,
|
||||
0x3e, 0xbb, 0xda, 0xe2, 0x2b, 0x60, 0xc9, 0xf3, 0xe3, 0x53, 0xd8, 0x3e, 0xc9, 0x21, 0x17, 0xf9,
|
||||
0x06, 0x58, 0x12, 0xf4, 0x47, 0x37, 0xeb, 0x38, 0x7b, 0x82, 0x63, 0xc1, 0x25, 0x18, 0x08, 0xed,
|
||||
0x2d, 0x94, 0xf6, 0x4a, 0x98, 0xb4, 0x22, 0x06, 0x47, 0x50, 0x63, 0x83, 0xfd, 0xd6, 0x89, 0xb2,
|
||||
0xb3, 0x80, 0x7e, 0xe4, 0xe5, 0xca, 0x87, 0xdc, 0x7f, 0x15, 0x68, 0x48, 0x54, 0x23, 0xab, 0xf2,
|
||||
0xc5, 0xed, 0xd3, 0x2e, 0x97, 0xae, 0x05, 0xf8, 0xf0, 0xa3, 0xd5, 0xc5, 0xf9, 0xb6, 0x63, 0xcf,
|
||||
0x61, 0x7d, 0x75, 0x80, 0x6f, 0xf9, 0x9e, 0xfe, 0xa5, 0x4f, 0xff, 0xcf, 0x63, 0x47, 0x1b, 0xbf,
|
||||
0xac, 0x1f, 0x3c, 0x9d, 0xb3, 0x2f, 0xd6, 0xf9, 0x2f, 0xcf, 0x8f, 0xff, 0x17, 0x00, 0x00, 0xff,
|
||||
0xff, 0x17, 0x3d, 0x94, 0x57, 0x0e, 0x15, 0x00, 0x00,
|
||||
// 2014 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xdd, 0x6e, 0xe3, 0xc6,
|
||||
0x15, 0x5e, 0xea, 0xc7, 0x92, 0x8e, 0x24, 0x2f, 0x3d, 0xf6, 0x7a, 0x65, 0x65, 0x37, 0xbb, 0x21,
|
||||
0x9a, 0xc4, 0x75, 0x53, 0x6f, 0xea, 0x6c, 0xb3, 0xfd, 0x0b, 0x16, 0xb2, 0x44, 0x3b, 0xaa, 0x65,
|
||||
0x49, 0xa0, 0xe8, 0x6e, 0xd3, 0x02, 0x25, 0x68, 0x72, 0xac, 0x65, 0x4d, 0x71, 0x58, 0x72, 0xe4,
|
||||
0x8d, 0xd0, 0xa2, 0x17, 0x2d, 0xd0, 0xeb, 0x02, 0x05, 0x7a, 0xd9, 0x07, 0x29, 0x0a, 0xf4, 0x09,
|
||||
0xfa, 0x12, 0x7d, 0x8d, 0xde, 0x14, 0xf3, 0x43, 0x89, 0x94, 0xa5, 0x75, 0x9a, 0xe6, 0x6e, 0xe6,
|
||||
0xfc, 0xf1, 0xcc, 0x37, 0x67, 0xce, 0x7c, 0x43, 0x68, 0xbc, 0xf6, 0x5c, 0xd7, 0xbb, 0x9a, 0x45,
|
||||
0xa1, 0xf3, 0x4c, 0x0e, 0x0f, 0xc3, 0x88, 0x50, 0x82, 0x60, 0xa1, 0xd1, 0xfe, 0xa6, 0x80, 0xda,
|
||||
0x26, 0x11, 0xee, 0x06, 0x57, 0xc4, 0xc0, 0x71, 0x48, 0x82, 0x18, 0xa3, 0xe7, 0x00, 0x0e, 0x89,
|
||||
0xb0, 0x15, 0x53, 0x9b, 0xe2, 0x86, 0xf2, 0x54, 0xd9, 0xdf, 0x3c, 0x7a, 0x70, 0xb8, 0xf0, 0x3a,
|
||||
0x64, 0x1e, 0x23, 0xa6, 0x34, 0x2a, 0x4e, 0x32, 0x44, 0x3f, 0x82, 0xda, 0x04, 0xc7, 0xb1, 0x3d,
|
||||
0xc6, 0x16, 0x9d, 0x85, 0xb8, 0x91, 0xe3, 0x7e, 0x0f, 0xd3, 0x7e, 0xe7, 0x42, 0x6f, 0xce, 0x42,
|
||||
0x6c, 0x54, 0x27, 0x8b, 0x09, 0x6a, 0x40, 0x49, 0x4e, 0x1b, 0xf9, 0xa7, 0xca, 0x7e, 0xc5, 0x48,
|
||||
0xa6, 0xda, 0x9f, 0x73, 0x50, 0x1b, 0x51, 0x3b, 0xa2, 0x06, 0xfe, 0xcd, 0x14, 0xc7, 0x14, 0x3d,
|
||||
0x81, 0xaa, 0x43, 0x82, 0x2b, 0x6f, 0x6c, 0x85, 0x36, 0x7d, 0xcd, 0xb3, 0xab, 0x18, 0x20, 0x44,
|
||||
0x43, 0x9b, 0xbe, 0x46, 0xef, 0xc3, 0xa6, 0x34, 0x70, 0x48, 0x40, 0x71, 0x40, 0x79, 0x26, 0x15,
|
||||
0xa3, 0x2e, 0xa4, 0x6d, 0x21, 0x44, 0x1f, 0xc3, 0x8e, 0xeb, 0xc5, 0xf6, 0xa5, 0x8f, 0xad, 0x09,
|
||||
0x9e, 0x90, 0x68, 0x66, 0xf9, 0xde, 0xc4, 0xa3, 0xfc, 0xfb, 0x65, 0x03, 0x49, 0xdd, 0x39, 0x57,
|
||||
0xf5, 0x98, 0x86, 0x7d, 0xd9, 0xc5, 0xbe, 0x3d, 0x63, 0xb8, 0x44, 0xb4, 0x51, 0xe0, 0x86, 0xc0,
|
||||
0x45, 0x3c, 0x43, 0xf4, 0x43, 0xd8, 0xc3, 0x01, 0x8f, 0x48, 0x7c, 0xd7, 0x72, 0xc8, 0x64, 0x62,
|
||||
0x07, 0xae, 0x15, 0xe3, 0xe8, 0x06, 0x47, 0x8d, 0x22, 0x37, 0xdf, 0x15, 0x06, 0x03, 0xdf, 0x6d,
|
||||
0x0b, 0xf5, 0x88, 0x6b, 0xd1, 0x01, 0x6c, 0x49, 0xd7, 0xc8, 0x7e, 0x63, 0x89, 0x4c, 0x1b, 0x1b,
|
||||
0xdc, 0xe5, 0xbe, 0x50, 0x18, 0xf6, 0x9b, 0x36, 0x17, 0x6b, 0xd7, 0x50, 0x1b, 0x61, 0x3a, 0x0d,
|
||||
0x13, 0x44, 0xde, 0x81, 0xca, 0xa5, 0x1d, 0xe3, 0x34, 0x1e, 0x65, 0x26, 0xe0, 0x68, 0xbc, 0x07,
|
||||
0xb5, 0x37, 0x24, 0xba, 0xf6, 0x02, 0x89, 0x97, 0xc0, 0xa2, 0x2a, 0x65, 0xdc, 0xe4, 0x1d, 0xa8,
|
||||
0x50, 0x3c, 0x09, 0x85, 0x5e, 0xc0, 0x5f, 0x66, 0x02, 0xa6, 0xd4, 0x1c, 0x28, 0xcf, 0xeb, 0xe2,
|
||||
0x33, 0xa8, 0x47, 0x72, 0x6c, 0x39, 0xc4, 0x4d, 0x4a, 0xa3, 0x91, 0xde, 0xe2, 0xc4, 0xb8, 0x4d,
|
||||
0x5c, 0x6c, 0xd4, 0xa2, 0xd4, 0x2c, 0xbd, 0xc9, 0xb9, 0xec, 0x26, 0x6b, 0x50, 0xfb, 0x1c, 0xfb,
|
||||
0x3e, 0x49, 0x56, 0x84, 0xa0, 0x10, 0xd8, 0x13, 0x2c, 0x17, 0xc3, 0xc7, 0xda, 0xb7, 0xa1, 0x2e,
|
||||
0x6d, 0x64, 0x36, 0xa9, 0x70, 0x4a, 0x36, 0x5c, 0x09, 0x8a, 0xfa, 0x24, 0xa4, 0x33, 0xed, 0x9f,
|
||||
0x39, 0x80, 0xd1, 0x2c, 0xa6, 0x78, 0xc2, 0xea, 0x1b, 0xed, 0xc2, 0x86, 0xd8, 0x6a, 0xee, 0x90,
|
||||
0x37, 0xe4, 0x0c, 0xbd, 0x0b, 0x30, 0x26, 0x11, 0x99, 0x52, 0x2f, 0xc0, 0x31, 0xcf, 0xad, 0x68,
|
||||
0xa4, 0x24, 0xb2, 0xa2, 0x02, 0xec, 0x50, 0x8f, 0x04, 0xb1, 0xe5, 0x05, 0x1c, 0xa5, 0x22, 0xaf,
|
||||
0xa8, 0x44, 0xda, 0x0d, 0xd0, 0x87, 0x70, 0x3f, 0x6d, 0x46, 0xa6, 0xa2, 0x46, 0x8a, 0x46, 0xda,
|
||||
0x7b, 0x30, 0xa5, 0xe8, 0x3b, 0xb0, 0x45, 0x23, 0xfb, 0xea, 0xca, 0x73, 0x2c, 0xfb, 0xc6, 0xf6,
|
||||
0x7c, 0xb6, 0xbd, 0xb2, 0x3e, 0x54, 0xa9, 0x68, 0x25, 0x72, 0x96, 0xf4, 0x34, 0xf4, 0xbd, 0xe0,
|
||||
0x9a, 0x97, 0x43, 0xde, 0x90, 0x33, 0xd4, 0x84, 0xb2, 0x4b, 0xde, 0x04, 0x5c, 0x53, 0xe2, 0x9a,
|
||||
0xf9, 0x9c, 0x6d, 0xba, 0xb0, 0xb2, 0x28, 0xa1, 0xb6, 0xdf, 0x28, 0x73, 0x7d, 0x55, 0xc8, 0x4c,
|
||||
0x26, 0x62, 0x6b, 0x4a, 0xcc, 0xa5, 0x51, 0x85, 0x1b, 0xd5, 0x13, 0x29, 0x37, 0xd3, 0xfe, 0xa8,
|
||||
0xc0, 0xd6, 0x60, 0x4a, 0x2f, 0xc9, 0x34, 0x70, 0x4f, 0x23, 0x32, 0x0d, 0xbb, 0x14, 0x4f, 0x90,
|
||||
0x0a, 0x79, 0x6a, 0x8f, 0x25, 0xec, 0x6c, 0xc8, 0x76, 0x6c, 0x7e, 0xe8, 0x2b, 0x06, 0x1f, 0x23,
|
||||
0x0d, 0xea, 0xd3, 0xc8, 0xb7, 0x28, 0x8e, 0xa9, 0x45, 0xbd, 0x89, 0x38, 0xda, 0x2c, 0x8d, 0xc8,
|
||||
0x37, 0x71, 0x4c, 0x4d, 0x6f, 0x82, 0xd1, 0xb7, 0x60, 0x73, 0x6e, 0xc3, 0x4f, 0x92, 0x84, 0xac,
|
||||
0x26, 0x8d, 0x3a, 0x4c, 0xa6, 0xfd, 0x49, 0x81, 0x7a, 0x26, 0x8b, 0xaf, 0x98, 0x41, 0x13, 0xca,
|
||||
0x31, 0xf6, 0xb1, 0x43, 0xb1, 0x9b, 0x14, 0x76, 0x32, 0x47, 0x9f, 0x40, 0xd1, 0xa3, 0x78, 0x12,
|
||||
0x37, 0x0a, 0x4f, 0xf3, 0xfb, 0xd5, 0xa3, 0xc7, 0xe9, 0x22, 0xbe, 0xb5, 0x62, 0x43, 0xd8, 0x6a,
|
||||
0x9d, 0x25, 0x34, 0x7a, 0x5e, 0x4c, 0xd1, 0xb3, 0x24, 0x92, 0xc2, 0x23, 0xed, 0xad, 0x8d, 0x94,
|
||||
0x44, 0x19, 0x40, 0xf5, 0x95, 0x1d, 0x85, 0x2d, 0xc7, 0x21, 0xd3, 0x80, 0xa2, 0xc7, 0x00, 0xb6,
|
||||
0x18, 0x5a, 0x9e, 0x2b, 0x97, 0x54, 0x91, 0x92, 0xae, 0xcb, 0x36, 0xd3, 0x76, 0x1c, 0x1c, 0xc7,
|
||||
0x16, 0x25, 0xd7, 0x38, 0x48, 0x4e, 0xb0, 0x90, 0x99, 0x4c, 0xa4, 0xfd, 0x5d, 0x81, 0x6d, 0x16,
|
||||
0xf1, 0x95, 0x17, 0xe1, 0xf1, 0xd4, 0x8e, 0x5c, 0xd1, 0x29, 0x58, 0xc7, 0x0a, 0x23, 0xef, 0xc6,
|
||||
0xa6, 0xd8, 0xba, 0xc6, 0xb3, 0xa4, 0x57, 0x4a, 0xd1, 0x19, 0x9e, 0xa1, 0x8f, 0x00, 0xf9, 0xc4,
|
||||
0xb1, 0x7d, 0xcb, 0x76, 0xdd, 0x88, 0x7d, 0xc2, 0x0b, 0x6f, 0x9e, 0xcb, 0x2f, 0xa8, 0x5c, 0xd3,
|
||||
0x12, 0x8a, 0x6e, 0x78, 0xf3, 0x7c, 0xa5, 0xf5, 0xa7, 0x12, 0xd8, 0x65, 0xeb, 0x4f, 0xd1, 0x07,
|
||||
0x70, 0x3f, 0xc4, 0x38, 0xb2, 0xc2, 0xe9, 0xa5, 0xef, 0x39, 0x3c, 0x81, 0x82, 0x68, 0xc4, 0x4c,
|
||||
0x3c, 0xe4, 0xd2, 0x33, 0x3c, 0xd3, 0xfe, 0xaa, 0xc0, 0x2e, 0x4b, 0xfe, 0x14, 0x07, 0x38, 0xb2,
|
||||
0xd9, 0x21, 0x99, 0x1f, 0xf1, 0xef, 0x41, 0x49, 0xe2, 0xc0, 0x73, 0xaf, 0x66, 0x6f, 0x93, 0x14,
|
||||
0x86, 0x46, 0x62, 0xc7, 0x0a, 0xc3, 0x27, 0x63, 0xb9, 0x04, 0x36, 0x44, 0x2f, 0x60, 0x43, 0xf6,
|
||||
0xd3, 0x3c, 0x8f, 0xf1, 0x64, 0x39, 0xc6, 0x12, 0x6a, 0x86, 0x34, 0xd7, 0xce, 0x60, 0x4b, 0x34,
|
||||
0x8f, 0x61, 0x44, 0xbe, 0x64, 0x2d, 0x9e, 0x4e, 0x63, 0xf4, 0x08, 0x2a, 0x8b, 0x33, 0xab, 0xf0,
|
||||
0x33, 0xbb, 0x10, 0xb0, 0x9e, 0x24, 0xba, 0xb5, 0xcb, 0x33, 0x28, 0x1b, 0xc9, 0x54, 0xfb, 0x1d,
|
||||
0xd4, 0x86, 0x76, 0x14, 0xe3, 0xa4, 0xc5, 0x35, 0xa0, 0x94, 0x5c, 0x4f, 0xb2, 0x7b, 0xc9, 0xe9,
|
||||
0xf2, 0x05, 0x97, 0xbb, 0x75, 0xc1, 0xbd, 0xad, 0x5f, 0xa3, 0x1d, 0x28, 0xba, 0xf8, 0x72, 0x3a,
|
||||
0x96, 0xd7, 0x93, 0x98, 0x68, 0x7f, 0x50, 0xa0, 0x2e, 0x3f, 0xff, 0x8d, 0xf5, 0xf2, 0xec, 0xed,
|
||||
0x3a, 0x4f, 0x7f, 0xfd, 0x55, 0xde, 0x83, 0x66, 0xfb, 0xb5, 0x1d, 0x8c, 0xb1, 0xc0, 0x79, 0x10,
|
||||
0xf2, 0x86, 0x98, 0x00, 0x72, 0x08, 0xdb, 0x72, 0xd9, 0x44, 0x28, 0xac, 0x5f, 0xc7, 0x24, 0x90,
|
||||
0xe0, 0x6c, 0x39, 0x69, 0x97, 0x9f, 0xc6, 0x24, 0xd0, 0x7e, 0x05, 0x0f, 0x64, 0xc5, 0xc8, 0x78,
|
||||
0xa9, 0xcb, 0x23, 0x75, 0x13, 0xf2, 0x71, 0x16, 0xb2, 0xdc, 0x3a, 0xc8, 0xf2, 0x69, 0xc8, 0x5e,
|
||||
0xc2, 0xee, 0x72, 0x7c, 0x09, 0xdd, 0x6d, 0x82, 0xa1, 0xac, 0x20, 0x18, 0xda, 0x2b, 0x78, 0x30,
|
||||
0xe2, 0xcd, 0x26, 0xe9, 0x01, 0xa9, 0xfb, 0x7a, 0xcc, 0xda, 0x81, 0xb5, 0xe8, 0x60, 0x65, 0x2e,
|
||||
0x30, 0xed, 0x31, 0x3b, 0xed, 0x44, 0xda, 0x73, 0xbd, 0x3c, 0xed, 0x89, 0xcc, 0xb4, 0xc7, 0xda,
|
||||
0x77, 0x61, 0xf3, 0x42, 0x74, 0xc7, 0xaf, 0x12, 0x51, 0xfb, 0x3d, 0xec, 0x25, 0x0b, 0x61, 0xd5,
|
||||
0x9e, 0x05, 0xeb, 0x09, 0x54, 0x7d, 0xcf, 0xc1, 0xac, 0x0a, 0x52, 0x1d, 0x42, 0x8a, 0x58, 0x87,
|
||||
0xc8, 0x36, 0xa7, 0xdc, 0x5d, 0xcd, 0x29, 0x7f, 0xbb, 0x39, 0x7d, 0x06, 0x8f, 0x46, 0x98, 0xa6,
|
||||
0x4e, 0x92, 0x2e, 0x8e, 0x44, 0x92, 0xc2, 0x63, 0x00, 0x2f, 0xb6, 0x92, 0x63, 0x23, 0x8f, 0x94,
|
||||
0x17, 0x4b, 0x2b, 0xed, 0xb7, 0x00, 0x3d, 0x32, 0x96, 0xcc, 0x11, 0x1d, 0x40, 0xd1, 0xc7, 0x37,
|
||||
0xd8, 0x97, 0xe5, 0xba, 0x93, 0x2e, 0xd7, 0x1e, 0x19, 0xf7, 0x98, 0xce, 0x10, 0x26, 0xe8, 0xc3,
|
||||
0xd4, 0x8d, 0xb0, 0x79, 0xb4, 0xbd, 0x64, 0xca, 0x49, 0xa8, 0xb8, 0x26, 0xd6, 0x97, 0x6c, 0x1d,
|
||||
0xaa, 0x23, 0x4a, 0x12, 0xa6, 0xa5, 0xfd, 0x43, 0x01, 0x64, 0x4e, 0x83, 0x00, 0xfb, 0x19, 0x4a,
|
||||
0x8a, 0xa0, 0xc0, 0x3b, 0xa1, 0xc8, 0x9d, 0x8f, 0x19, 0xb0, 0x82, 0xf8, 0x59, 0x21, 0x89, 0x68,
|
||||
0x42, 0x2a, 0x84, 0x68, 0x48, 0x22, 0xca, 0x90, 0x8b, 0x69, 0xe4, 0x39, 0xd4, 0x62, 0x3c, 0x03,
|
||||
0xcb, 0xe2, 0xab, 0x0a, 0x99, 0xc1, 0x44, 0xe8, 0x07, 0xd0, 0xc0, 0x81, 0x1b, 0x12, 0x8f, 0x81,
|
||||
0x1f, 0xb8, 0x38, 0xc4, 0x81, 0x8b, 0x03, 0x6a, 0x05, 0x76, 0xc2, 0x3e, 0x77, 0x13, 0x7d, 0x77,
|
||||
0xa1, 0xee, 0xdb, 0x94, 0x95, 0x74, 0x4c, 0x6d, 0xe7, 0x9a, 0xb3, 0x8a, 0x8a, 0x21, 0x26, 0xda,
|
||||
0x01, 0x6c, 0x8a, 0xec, 0xef, 0xe6, 0x50, 0x07, 0x1a, 0xd4, 0xd2, 0xc7, 0x1f, 0x6d, 0x40, 0x6e,
|
||||
0x70, 0xa6, 0xde, 0x43, 0x00, 0x1b, 0x27, 0xad, 0x6e, 0x4f, 0xef, 0xa8, 0xca, 0x41, 0x0b, 0x2a,
|
||||
0xf3, 0x97, 0x00, 0xaa, 0x42, 0x69, 0x64, 0x0e, 0x86, 0x43, 0xbd, 0xa3, 0xde, 0x43, 0x35, 0x28,
|
||||
0x8f, 0xcc, 0x96, 0x61, 0x76, 0xfb, 0xa7, 0xaa, 0x22, 0x54, 0x2d, 0xc3, 0xd4, 0x3b, 0x6a, 0x4e,
|
||||
0xa8, 0x06, 0xc3, 0x21, 0x53, 0xe5, 0x0f, 0xfe, 0x95, 0x83, 0x6a, 0xea, 0x55, 0x80, 0x2a, 0x50,
|
||||
0xd4, 0xcf, 0x87, 0xe6, 0x17, 0xea, 0x3d, 0xf4, 0x10, 0xb6, 0xf9, 0xd0, 0x6a, 0x0f, 0xfa, 0x27,
|
||||
0xdd, 0xd3, 0x0b, 0xa3, 0x65, 0x76, 0x07, 0x7d, 0x55, 0x41, 0x0d, 0xd8, 0xe1, 0xe1, 0xac, 0xf6,
|
||||
0xe0, 0xfc, 0xbc, 0xd5, 0xef, 0x58, 0x23, 0xdd, 0xf8, 0x99, 0x6e, 0xa8, 0x39, 0x84, 0x60, 0xb3,
|
||||
0x6d, 0xe8, 0x2d, 0x53, 0xe7, 0xa2, 0x6e, 0x5b, 0x57, 0xf3, 0x68, 0x0b, 0xea, 0xc2, 0x3a, 0x11,
|
||||
0x15, 0xd0, 0x0e, 0xa8, 0x17, 0x7d, 0xfd, 0xe7, 0x43, 0xbd, 0x6d, 0xea, 0x1d, 0x4b, 0x37, 0x8c,
|
||||
0x81, 0xa1, 0x16, 0xd1, 0x36, 0xdc, 0x6f, 0xf5, 0x0c, 0xbd, 0xd5, 0xf9, 0xc2, 0x4a, 0xb2, 0xdd,
|
||||
0xc8, 0x0a, 0xc5, 0xea, 0x4a, 0x68, 0x17, 0x50, 0xb7, 0x3f, 0x32, 0x5b, 0xfd, 0xb6, 0x6e, 0xf5,
|
||||
0x07, 0xa6, 0x75, 0x32, 0xb8, 0xe8, 0x77, 0xd4, 0x32, 0x4b, 0x2c, 0x23, 0x4f, 0x3c, 0x2a, 0x2b,
|
||||
0x34, 0xe2, 0x03, 0x80, 0xf6, 0xe0, 0x01, 0x4f, 0xc0, 0x3a, 0xbe, 0xe8, 0xf6, 0x3a, 0xdd, 0xfe,
|
||||
0xa9, 0x5c, 0xae, 0x5a, 0x65, 0x4e, 0x42, 0x35, 0x6c, 0x19, 0xa3, 0x94, 0xa6, 0xb6, 0xd0, 0xb0,
|
||||
0xcc, 0x52, 0x9a, 0xfa, 0xc1, 0x31, 0x94, 0x93, 0x63, 0xc0, 0xb0, 0xec, 0xe8, 0xc7, 0x17, 0xa7,
|
||||
0xea, 0x3d, 0x54, 0x86, 0x42, 0xb7, 0x7f, 0x32, 0x10, 0x7b, 0xf1, 0xaa, 0x65, 0xf4, 0x19, 0xfa,
|
||||
0x39, 0x8e, 0x36, 0x5f, 0x7d, 0x9e, 0x0d, 0x4f, 0x5a, 0x66, 0xab, 0xa7, 0x16, 0x0e, 0x3e, 0x82,
|
||||
0x92, 0x3c, 0x1f, 0xcc, 0xaf, 0x3d, 0x30, 0x74, 0xf5, 0x1e, 0xdf, 0x43, 0x09, 0xa0, 0xc2, 0x8a,
|
||||
0x40, 0x7e, 0x31, 0x77, 0xf4, 0x17, 0x05, 0x8a, 0x9c, 0x98, 0xa3, 0x97, 0x50, 0x1e, 0xd9, 0x33,
|
||||
0x31, 0xce, 0xdc, 0x23, 0x69, 0x6e, 0xdf, 0xdc, 0x5b, 0xa1, 0x91, 0xd5, 0xd8, 0x85, 0xcd, 0x24,
|
||||
0xc0, 0x88, 0x46, 0xd8, 0x9e, 0x7c, 0xad, 0x30, 0xfb, 0xca, 0xc7, 0xca, 0xd1, 0xbf, 0x2b, 0x50,
|
||||
0x60, 0xb5, 0x89, 0x5e, 0x42, 0x51, 0x3c, 0xce, 0x32, 0xa1, 0xd2, 0xc7, 0xb7, 0xf9, 0x68, 0xf9,
|
||||
0x69, 0x9b, 0x79, 0x0c, 0x9f, 0x2f, 0x1e, 0xc8, 0x8c, 0xed, 0xb1, 0x4e, 0x8a, 0x1e, 0x66, 0x63,
|
||||
0xcd, 0x1b, 0xc4, 0xdb, 0x43, 0xb1, 0xc4, 0xd0, 0xd9, 0x82, 0xc9, 0xc6, 0xfc, 0x51, 0xb2, 0x36,
|
||||
0xd6, 0x7a, 0x46, 0xca, 0xf2, 0xe0, 0xc1, 0x06, 0xb0, 0x75, 0x6e, 0x7b, 0xc1, 0x37, 0x17, 0xb0,
|
||||
0x03, 0xf5, 0xd3, 0xa4, 0x57, 0xbf, 0x3d, 0xd8, 0x6e, 0x46, 0x31, 0x77, 0xe0, 0x51, 0x5e, 0x40,
|
||||
0x91, 0x3f, 0x50, 0x97, 0x30, 0x4f, 0xbd, 0x59, 0x9b, 0x3b, 0xab, 0x78, 0x06, 0xfa, 0x09, 0x14,
|
||||
0x39, 0x4b, 0xc9, 0x3a, 0xa6, 0x79, 0x53, 0x76, 0xdf, 0xb3, 0x94, 0xe6, 0x97, 0xb0, 0xbd, 0x82,
|
||||
0x5f, 0xa0, 0x0f, 0x32, 0x7b, 0xb2, 0x96, 0x80, 0xdc, 0x51, 0x06, 0x27, 0xf2, 0x37, 0x04, 0x7b,
|
||||
0xaf, 0x7b, 0x0e, 0xfe, 0xda, 0xe5, 0xf4, 0x02, 0x0a, 0x0c, 0x46, 0xb4, 0x95, 0xb6, 0xe2, 0xaf,
|
||||
0xd5, 0x3b, 0x1c, 0x5b, 0x50, 0x32, 0x70, 0xfc, 0x7f, 0x95, 0x32, 0x3b, 0x5f, 0x19, 0x46, 0x82,
|
||||
0xde, 0xcb, 0x6e, 0xd0, 0x0a, 0xb6, 0xb2, 0x66, 0xa7, 0x7e, 0x0c, 0x25, 0xc9, 0x41, 0x50, 0x33,
|
||||
0x6d, 0x90, 0x25, 0x26, 0x6b, 0x9c, 0x2d, 0x40, 0xb7, 0x19, 0x09, 0x7a, 0x3f, 0x6d, 0xbb, 0x96,
|
||||
0xb1, 0x34, 0xb5, 0x65, 0xfa, 0xbe, 0xe2, 0xdd, 0xf0, 0x39, 0xec, 0x9c, 0x66, 0x28, 0x87, 0x24,
|
||||
0xef, 0x2b, 0x40, 0x7f, 0x7c, 0xbb, 0x8e, 0xd3, 0x1e, 0x9c, 0xc4, 0xad, 0x20, 0x2f, 0x68, 0x7f,
|
||||
0xa9, 0xb4, 0xd7, 0xf2, 0x9b, 0x35, 0x18, 0x1c, 0x43, 0x95, 0x35, 0xea, 0x3b, 0x3b, 0xca, 0xee,
|
||||
0x12, 0x6d, 0x91, 0x97, 0x25, 0x6f, 0x72, 0xff, 0x51, 0xa0, 0x2e, 0xe9, 0x88, 0xac, 0xca, 0x76,
|
||||
0xd2, 0xed, 0xde, 0x4d, 0xbb, 0xdd, 0xa6, 0x2c, 0xcd, 0xe6, 0x6d, 0xfd, 0x3c, 0xb5, 0xef, 0xaf,
|
||||
0x2f, 0xd1, 0xb7, 0xb9, 0xbd, 0x80, 0x8d, 0xf5, 0x30, 0xdf, 0xf1, 0x3d, 0xfd, 0x4b, 0x8f, 0xfe,
|
||||
0x8f, 0x6e, 0xc7, 0x9b, 0xbf, 0xa8, 0x1d, 0x3e, 0x5b, 0xa8, 0x2f, 0x37, 0xf8, 0xdf, 0xcd, 0x4f,
|
||||
0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x2e, 0xae, 0xf7, 0x33, 0xf9, 0x14, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ message StartRequest {
|
||||
bool disable_memory_limit = 3;
|
||||
bool delay_start = 4;
|
||||
bool enable_old_command_server = 5;
|
||||
bool enable_raw_config = 6;
|
||||
}
|
||||
|
||||
message SetupRequest {
|
||||
@@ -193,19 +194,14 @@ message StopRequest{
|
||||
}
|
||||
|
||||
|
||||
enum StackType {
|
||||
SYSTEM = 0;
|
||||
GVISOR = 1;
|
||||
MIXED = 2;
|
||||
|
||||
}
|
||||
|
||||
message TunnelStartRequest {
|
||||
bool ipv6 = 1;
|
||||
int32 server_port = 2;
|
||||
bool strict_route = 3;
|
||||
bool endpoint_independent_nat = 4;
|
||||
StackType stack = 5;
|
||||
string stack = 5;
|
||||
|
||||
}
|
||||
|
||||
message TunnelResponse {
|
||||
@@ -240,7 +236,7 @@ service Core {
|
||||
|
||||
|
||||
service TunnelService {
|
||||
rpc Start(StartRequest) returns (TunnelResponse);
|
||||
rpc Start(TunnelStartRequest ) returns (TunnelResponse);
|
||||
rpc Stop(Empty) returns (TunnelResponse);
|
||||
rpc Status(Empty) returns (TunnelResponse);
|
||||
rpc Exit(Empty) returns (TunnelResponse);
|
||||
|
||||
@@ -1034,7 +1034,7 @@ const (
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type TunnelServiceClient interface {
|
||||
Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*TunnelResponse, error)
|
||||
Start(ctx context.Context, in *TunnelStartRequest, opts ...grpc.CallOption) (*TunnelResponse, error)
|
||||
Stop(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TunnelResponse, error)
|
||||
Status(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TunnelResponse, error)
|
||||
Exit(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TunnelResponse, error)
|
||||
@@ -1048,7 +1048,7 @@ func NewTunnelServiceClient(cc grpc.ClientConnInterface) TunnelServiceClient {
|
||||
return &tunnelServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *tunnelServiceClient) Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*TunnelResponse, error) {
|
||||
func (c *tunnelServiceClient) Start(ctx context.Context, in *TunnelStartRequest, opts ...grpc.CallOption) (*TunnelResponse, error) {
|
||||
out := new(TunnelResponse)
|
||||
err := c.cc.Invoke(ctx, TunnelService_Start_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
@@ -1088,7 +1088,7 @@ func (c *tunnelServiceClient) Exit(ctx context.Context, in *Empty, opts ...grpc.
|
||||
// All implementations must embed UnimplementedTunnelServiceServer
|
||||
// for forward compatibility
|
||||
type TunnelServiceServer interface {
|
||||
Start(context.Context, *StartRequest) (*TunnelResponse, error)
|
||||
Start(context.Context, *TunnelStartRequest) (*TunnelResponse, error)
|
||||
Stop(context.Context, *Empty) (*TunnelResponse, error)
|
||||
Status(context.Context, *Empty) (*TunnelResponse, error)
|
||||
Exit(context.Context, *Empty) (*TunnelResponse, error)
|
||||
@@ -1099,7 +1099,7 @@ type TunnelServiceServer interface {
|
||||
type UnimplementedTunnelServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedTunnelServiceServer) Start(context.Context, *StartRequest) (*TunnelResponse, error) {
|
||||
func (UnimplementedTunnelServiceServer) Start(context.Context, *TunnelStartRequest) (*TunnelResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Start not implemented")
|
||||
}
|
||||
func (UnimplementedTunnelServiceServer) Stop(context.Context, *Empty) (*TunnelResponse, error) {
|
||||
@@ -1125,7 +1125,7 @@ func RegisterTunnelServiceServer(s grpc.ServiceRegistrar, srv TunnelServiceServe
|
||||
}
|
||||
|
||||
func _TunnelService_Start_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StartRequest)
|
||||
in := new(TunnelStartRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1137,7 +1137,7 @@ func _TunnelService_Start_Handler(srv interface{}, ctx context.Context, dec func
|
||||
FullMethod: TunnelService_Start_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TunnelServiceServer).Start(ctx, req.(*StartRequest))
|
||||
return srv.(TunnelServiceServer).Start(ctx, req.(*TunnelStartRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
)
|
||||
|
||||
var EnableBridge = true
|
||||
var coreInfoObserver = NewObserver[pb.CoreInfoResponse](10)
|
||||
var CoreState = pb.CoreState_STOPPED
|
||||
|
||||
@@ -20,8 +21,10 @@ func SetCoreStatus(state pb.CoreState, msgType pb.MessageType, message string) p
|
||||
Message: message,
|
||||
}
|
||||
coreInfoObserver.Emit(info)
|
||||
msg, _ := json.Marshal(StatusMessage{Status: convert2OldState(CoreState)})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
if EnableBridge {
|
||||
msg, _ := json.Marshal(StatusMessage{Status: convert2OldState(CoreState)})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
}
|
||||
return info
|
||||
|
||||
}
|
||||
|
||||
49
v2/custom.go
49
v2/custom.go
@@ -13,7 +13,6 @@ import (
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
var Box *libbox.BoxService
|
||||
@@ -34,9 +33,11 @@ func StopAndAlert(msgType pb.MessageType, message string) {
|
||||
if commandServer != nil {
|
||||
commandServer.Close()
|
||||
}
|
||||
alert := msgType.String()
|
||||
msg, _ := json.Marshal(StatusMessage{Status: convert2OldState(CoreState), Alert: &alert, Message: &message})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
if EnableBridge {
|
||||
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) {
|
||||
@@ -48,15 +49,17 @@ func Start(in *pb.StartRequest) (*pb.CoreInfoResponse, 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")
|
||||
if CoreState != pb.CoreState_STOPPED {
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Starting0000")
|
||||
return &pb.CoreInfoResponse{
|
||||
CoreState: CoreState,
|
||||
MessageType: pb.MessageType_INSTANCE_NOT_STOPPED,
|
||||
}, fmt.Errorf("instance not stopped")
|
||||
}
|
||||
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "")
|
||||
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Starting1111")
|
||||
SetCoreStatus(pb.CoreState_STARTING, pb.MessageType_EMPTY, "Starting222")
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Starting2")
|
||||
libbox.SetMemoryLimit(!in.DisableMemoryLimit)
|
||||
resp, err := StartService(in)
|
||||
return resp, err
|
||||
@@ -65,7 +68,7 @@ func (s *CoreService) StartService(ctx context.Context, in *pb.StartRequest) (*p
|
||||
return StartService(in)
|
||||
}
|
||||
func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Starting3")
|
||||
content := in.ConfigContent
|
||||
if content == "" {
|
||||
|
||||
@@ -80,22 +83,28 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
}
|
||||
content = string(fileContent)
|
||||
}
|
||||
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Starting4")
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, content)
|
||||
parsedContent, err := parseConfig(content)
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Parsed")
|
||||
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_PARSING_CONFIG, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
var patchedOptions *option.Options
|
||||
patchedOptions, err = config.BuildConfig(*configOptions, parsedContent)
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_BUILDING_CONFIG, err.Error())
|
||||
return &resp, err
|
||||
if !in.EnableRawConfig {
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Building config")
|
||||
parsedContent_tmp, err := config.BuildConfig(*configOptions, parsedContent)
|
||||
parsedContent = *parsedContent_tmp
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_BUILDING_CONFIG, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
}
|
||||
|
||||
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "current-config.json"), *patchedOptions)
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Saving Contnet")
|
||||
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "current-config.json"), parsedContent)
|
||||
if in.EnableOldCommandServer {
|
||||
err = startCommandServer(*logFactory)
|
||||
if err != nil {
|
||||
@@ -105,13 +114,15 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
}
|
||||
}
|
||||
|
||||
instance, err := NewService(*patchedOptions)
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Stating Service ")
|
||||
instance, err := NewService(parsedContent)
|
||||
|
||||
if err != nil {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_CREATE_SERVICE, err.Error())
|
||||
return &resp, err
|
||||
}
|
||||
|
||||
Log(pb.LogLevel_INFO, pb.LogType_CORE, "Service.. started")
|
||||
if in.DelayStart {
|
||||
<-time.After(250 * time.Millisecond)
|
||||
}
|
||||
|
||||
@@ -1,223 +1,233 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/hiddify/libcore/config"
|
||||
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
func RunStandalone(hiddifySettingPath string, configPath string) error {
|
||||
fmt.Println("Running in standalone mode")
|
||||
current, err := readAndBuildConfig(hiddifySettingPath, configPath)
|
||||
if err != nil {
|
||||
fmt.Printf("Error in read and build config %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
go StartServiceC(false, current.Config)
|
||||
go updateConfigInterval(current, hiddifySettingPath, configPath)
|
||||
fmt.Printf("Press CTRL+C to stop\n")
|
||||
fmt.Printf("Open http://localhost:6756/?secret=hiddify in your browser\n")
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
<-sigChan
|
||||
err = StopServiceC()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type ConfigResult struct {
|
||||
Config string
|
||||
RefreshInterval int
|
||||
}
|
||||
|
||||
func readAndBuildConfig(hiddifySettingPath string, configPath string) (ConfigResult, error) {
|
||||
var result ConfigResult
|
||||
|
||||
result, err := readConfigContent(configPath)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
hiddifyconfig := config.DefaultConfigOptions()
|
||||
if hiddifySettingPath != "" {
|
||||
hiddifyconfig, err = readConfigOptionsAt(hiddifySettingPath)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
result.Config, err = buildConfig(result.Config, *hiddifyconfig)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func readConfigContent(configPath string) (ConfigResult, error) {
|
||||
var content string
|
||||
var refreshInterval int
|
||||
|
||||
if strings.HasPrefix(configPath, "http://") || strings.HasPrefix(configPath, "https://") {
|
||||
client := &http.Client{}
|
||||
|
||||
// Create a new request
|
||||
req, err := http.NewRequest("GET", configPath, nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating request:", err)
|
||||
return ConfigResult{}, err
|
||||
}
|
||||
req.Header.Set("User-Agent", "HiddifyNext/17.5.0 ("+runtime.GOOS+") like ClashMeta v2ray sing-box")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making GET request:", err)
|
||||
return ConfigResult{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ConfigResult{}, fmt.Errorf("failed to read config body: %w", err)
|
||||
}
|
||||
content = string(body)
|
||||
refreshInterval, _ = extractRefreshInterval(resp.Header, content)
|
||||
fmt.Printf("Refresh interval: %d\n", refreshInterval)
|
||||
} else {
|
||||
data, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return ConfigResult{}, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
content = string(data)
|
||||
}
|
||||
|
||||
return ConfigResult{
|
||||
Config: content,
|
||||
RefreshInterval: refreshInterval,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func extractRefreshInterval(header http.Header, bodyStr string) (int, error) {
|
||||
refreshIntervalStr := header.Get("profile-update-interval")
|
||||
if refreshIntervalStr != "" {
|
||||
refreshInterval, err := strconv.Atoi(refreshIntervalStr)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to parse refresh interval from header: %w", err)
|
||||
}
|
||||
return refreshInterval, nil
|
||||
}
|
||||
|
||||
lines := strings.Split(bodyStr, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "//profile-update-interval:") || strings.HasPrefix(line, "#profile-update-interval:") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
str := strings.TrimSpace(parts[1])
|
||||
refreshInterval, err := strconv.Atoi(str)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to parse refresh interval from body: %w", err)
|
||||
}
|
||||
return refreshInterval, nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
func buildConfig(configContent string, options config.ConfigOptions) (string, error) {
|
||||
parsedContent, err := config.ParseConfigContent(configContent, true)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse config content: %w", err)
|
||||
}
|
||||
singconfigs, err := readConfigBytes([]byte(parsedContent))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
finalconfig, err := config.BuildConfig(options, *singconfigs)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to build config: %w", err)
|
||||
}
|
||||
|
||||
finalconfig.Log.Output = ""
|
||||
finalconfig.Experimental.ClashAPI.ExternalUI = "webui"
|
||||
if options.AllowConnectionFromLAN {
|
||||
finalconfig.Experimental.ClashAPI.ExternalController = "0.0.0.0:6756"
|
||||
} else {
|
||||
finalconfig.Experimental.ClashAPI.ExternalController = "127.0.0.1:6756"
|
||||
}
|
||||
|
||||
if finalconfig.Experimental.ClashAPI.Secret == "" {
|
||||
// finalconfig.Experimental.ClashAPI.Secret = "hiddify"
|
||||
}
|
||||
|
||||
if err := SetupC("./", "./", "./tmp", false); err != nil {
|
||||
return "", fmt.Errorf("failed to set up global configuration: %w", err)
|
||||
}
|
||||
|
||||
configStr, err := config.ToJson(*finalconfig)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to convert config to JSON: %w", err)
|
||||
}
|
||||
|
||||
return configStr, nil
|
||||
}
|
||||
|
||||
func updateConfigInterval(current ConfigResult, hiddifySettingPath string, configPath string) {
|
||||
if current.RefreshInterval <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
<-time.After(time.Duration(current.RefreshInterval) * time.Hour)
|
||||
new, err := readAndBuildConfig(hiddifySettingPath, configPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if new.Config != current.Config {
|
||||
go StopServiceC()
|
||||
go StartServiceC(false, new.Config)
|
||||
}
|
||||
current = new
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func readConfigBytes(content []byte) (*option.Options, error) {
|
||||
var options option.Options
|
||||
err := options.UnmarshalJSON(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &options, nil
|
||||
}
|
||||
|
||||
func readConfigOptionsAt(path string) (*config.ConfigOptions, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var options config.ConfigOptions
|
||||
err = json.Unmarshal(content, &options)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if options.Warp.WireguardConfigStr != "" {
|
||||
err := json.Unmarshal([]byte(options.Warp.WireguardConfigStr), &options.Warp.WireguardConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &options, nil
|
||||
}
|
||||
package v2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/hiddify/libcore/config"
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
func RunStandalone(hiddifySettingPath string, configPath string) error {
|
||||
fmt.Println("Running in standalone mode")
|
||||
current, err := readAndBuildConfig(hiddifySettingPath, configPath)
|
||||
if err != nil {
|
||||
fmt.Printf("Error in read and build config %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
go StartService(&pb.StartRequest{
|
||||
ConfigPath: configPath,
|
||||
EnableOldCommandServer: false,
|
||||
DelayStart: false,
|
||||
})
|
||||
go updateConfigInterval(current, hiddifySettingPath, configPath)
|
||||
fmt.Printf("Press CTRL+C to stop\n")
|
||||
fmt.Printf("Open http://localhost:6756/?secret=hiddify in your browser\n")
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
<-sigChan
|
||||
_, err = Stop()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type ConfigResult struct {
|
||||
Config string
|
||||
RefreshInterval int
|
||||
}
|
||||
|
||||
func readAndBuildConfig(hiddifySettingPath string, configPath string) (ConfigResult, error) {
|
||||
var result ConfigResult
|
||||
|
||||
result, err := readConfigContent(configPath)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
hiddifyconfig := config.DefaultConfigOptions()
|
||||
if hiddifySettingPath != "" {
|
||||
hiddifyconfig, err = readConfigOptionsAt(hiddifySettingPath)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
result.Config, err = buildConfig(result.Config, *hiddifyconfig)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func readConfigContent(configPath string) (ConfigResult, error) {
|
||||
var content string
|
||||
var refreshInterval int
|
||||
|
||||
if strings.HasPrefix(configPath, "http://") || strings.HasPrefix(configPath, "https://") {
|
||||
client := &http.Client{}
|
||||
|
||||
// Create a new request
|
||||
req, err := http.NewRequest("GET", configPath, nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating request:", err)
|
||||
return ConfigResult{}, err
|
||||
}
|
||||
req.Header.Set("User-Agent", "HiddifyNext/17.5.0 ("+runtime.GOOS+") like ClashMeta v2ray sing-box")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making GET request:", err)
|
||||
return ConfigResult{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ConfigResult{}, fmt.Errorf("failed to read config body: %w", err)
|
||||
}
|
||||
content = string(body)
|
||||
refreshInterval, _ = extractRefreshInterval(resp.Header, content)
|
||||
fmt.Printf("Refresh interval: %d\n", refreshInterval)
|
||||
} else {
|
||||
data, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return ConfigResult{}, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
content = string(data)
|
||||
}
|
||||
|
||||
return ConfigResult{
|
||||
Config: content,
|
||||
RefreshInterval: refreshInterval,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func extractRefreshInterval(header http.Header, bodyStr string) (int, error) {
|
||||
refreshIntervalStr := header.Get("profile-update-interval")
|
||||
if refreshIntervalStr != "" {
|
||||
refreshInterval, err := strconv.Atoi(refreshIntervalStr)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to parse refresh interval from header: %w", err)
|
||||
}
|
||||
return refreshInterval, nil
|
||||
}
|
||||
|
||||
lines := strings.Split(bodyStr, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "//profile-update-interval:") || strings.HasPrefix(line, "#profile-update-interval:") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
str := strings.TrimSpace(parts[1])
|
||||
refreshInterval, err := strconv.Atoi(str)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to parse refresh interval from body: %w", err)
|
||||
}
|
||||
return refreshInterval, nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
func buildConfig(configContent string, options config.ConfigOptions) (string, error) {
|
||||
parsedContent, err := config.ParseConfigContent(configContent, true)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse config content: %w", err)
|
||||
}
|
||||
singconfigs, err := readConfigBytes([]byte(parsedContent))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
finalconfig, err := config.BuildConfig(options, *singconfigs)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to build config: %w", err)
|
||||
}
|
||||
|
||||
finalconfig.Log.Output = ""
|
||||
finalconfig.Experimental.ClashAPI.ExternalUI = "webui"
|
||||
if options.AllowConnectionFromLAN {
|
||||
finalconfig.Experimental.ClashAPI.ExternalController = "0.0.0.0:6756"
|
||||
} else {
|
||||
finalconfig.Experimental.ClashAPI.ExternalController = "127.0.0.1:6756"
|
||||
}
|
||||
|
||||
if finalconfig.Experimental.ClashAPI.Secret == "" {
|
||||
// finalconfig.Experimental.ClashAPI.Secret = "hiddify"
|
||||
}
|
||||
|
||||
if err := Setup("./", "./", "./tmp", 0, false); err != nil {
|
||||
return "", fmt.Errorf("failed to set up global configuration: %w", err)
|
||||
}
|
||||
|
||||
configStr, err := config.ToJson(*finalconfig)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to convert config to JSON: %w", err)
|
||||
}
|
||||
|
||||
return configStr, nil
|
||||
}
|
||||
|
||||
func updateConfigInterval(current ConfigResult, hiddifySettingPath string, configPath string) {
|
||||
if current.RefreshInterval <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
<-time.After(time.Duration(current.RefreshInterval) * time.Hour)
|
||||
new, err := readAndBuildConfig(hiddifySettingPath, configPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if new.Config != current.Config {
|
||||
go Stop()
|
||||
go StartService(&pb.StartRequest{
|
||||
ConfigContent: new.Config,
|
||||
DelayStart: false,
|
||||
EnableOldCommandServer: false,
|
||||
DisableMemoryLimit: false,
|
||||
})
|
||||
}
|
||||
current = new
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func readConfigBytes(content []byte) (*option.Options, error) {
|
||||
var options option.Options
|
||||
err := options.UnmarshalJSON(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &options, nil
|
||||
}
|
||||
|
||||
func readConfigOptionsAt(path string) (*config.ConfigOptions, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var options config.ConfigOptions
|
||||
err = json.Unmarshal(content, &options)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if options.Warp.WireguardConfigStr != "" {
|
||||
err := json.Unmarshal([]byte(options.Warp.WireguardConfigStr), &options.Warp.WireguardConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &options, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package admin_service
|
||||
package v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hiddify/libcore/global"
|
||||
"github.com/kardianos/service"
|
||||
)
|
||||
|
||||
@@ -17,11 +16,11 @@ type hiddifyNext struct{}
|
||||
var port int = 18020
|
||||
|
||||
func (m *hiddifyNext) Start(s service.Service) error {
|
||||
go StartWebServer(port, false)
|
||||
go StartTunnelGrpcServer(fmt.Sprintf("127.0.0.1:%d", port))
|
||||
return nil
|
||||
}
|
||||
func (m *hiddifyNext) Stop(s service.Service) error {
|
||||
err := global.StopServiceC()
|
||||
_, err := Stop()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -41,7 +40,7 @@ func getCurrentExecutableDirectory() string {
|
||||
|
||||
return executableDirectory
|
||||
}
|
||||
func StartService(goArg string) (int, string) {
|
||||
func StartTunnelService(goArg string) (int, string) {
|
||||
svcConfig := &service.Config{
|
||||
Name: "HiddifyTunnelService",
|
||||
DisplayName: "Hiddify Tunnel Service",
|
||||
92
v2/tunnel_service.go
Normal file
92
v2/tunnel_service.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
pb "github.com/hiddify/libcore/hiddifyrpc"
|
||||
)
|
||||
|
||||
func (s *TunnelService) Start(ctx context.Context, in *pb.TunnelStartRequest) (*pb.TunnelResponse, error) {
|
||||
if in.ServerPort == 0 {
|
||||
in.ServerPort = 2334
|
||||
}
|
||||
EnableBridge = false
|
||||
res, err := Start(&pb.StartRequest{
|
||||
ConfigContent: makeTunnelConfig(in.Ipv6, in.ServerPort, in.StrictRoute, in.EndpointIndependentNat, in.Stack),
|
||||
EnableOldCommandServer: false,
|
||||
DisableMemoryLimit: false,
|
||||
EnableRawConfig: true,
|
||||
})
|
||||
fmt.Printf("Start Result: %+v\n", res)
|
||||
if err != nil {
|
||||
return &pb.TunnelResponse{
|
||||
Message: err.Error(),
|
||||
}, err
|
||||
}
|
||||
return &pb.TunnelResponse{
|
||||
Message: "OK",
|
||||
}, err
|
||||
}
|
||||
|
||||
func makeTunnelConfig(Ipv6 bool, ServerPort int32, StrictRoute bool, EndpointIndependentNat bool, Stack string) string {
|
||||
var ipv6 string
|
||||
if Ipv6 {
|
||||
ipv6 = ` "inet6_address": "fdfe:dcba:9876::1/126",`
|
||||
} else {
|
||||
ipv6 = ""
|
||||
}
|
||||
base := `{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"tag": "tun-in",
|
||||
"interface_name": "HiddifyTunnel",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
` + ipv6 + `
|
||||
"mtu": 9000,
|
||||
"auto_route": true,
|
||||
"strict_route": ` + fmt.Sprintf("%t", StrictRoute) + `,
|
||||
"endpoint_independent_nat": ` + fmt.Sprintf("%t", EndpointIndependentNat) + `,
|
||||
"stack": "` + Stack + `"
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"tag": "socks-out",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": ` + fmt.Sprintf("%d", ServerPort) + `,
|
||||
"version": "5"
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
return base
|
||||
}
|
||||
|
||||
func (s *TunnelService) Stop(ctx context.Context, _ *pb.Empty) (*pb.TunnelResponse, error) {
|
||||
_, err := Stop()
|
||||
if err != nil {
|
||||
return &pb.TunnelResponse{
|
||||
Message: err.Error(),
|
||||
}, err
|
||||
}
|
||||
return &pb.TunnelResponse{
|
||||
Message: "OK",
|
||||
}, err
|
||||
}
|
||||
func (s *TunnelService) Status(ctx context.Context, _ *pb.Empty) (*pb.TunnelResponse, error) {
|
||||
|
||||
return &pb.TunnelResponse{
|
||||
Message: "Not Implemented",
|
||||
}, nil
|
||||
}
|
||||
func (s *TunnelService) Exit(ctx context.Context, _ *pb.Empty) (*pb.TunnelResponse, error) {
|
||||
Stop()
|
||||
os.Exit(0)
|
||||
return &pb.TunnelResponse{
|
||||
Message: "OK",
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user