new: Big Change, Add support for Extensions 😍
This commit is contained in:
@@ -6,11 +6,14 @@ import (
|
||||
|
||||
pb "github.com/hiddify/hiddify-core/hiddifyrpc"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var systemInfoObserver = NewObserver[pb.SystemInfo](10)
|
||||
var outboundsInfoObserver = NewObserver[pb.OutboundGroupList](10)
|
||||
var mainOutboundsInfoObserver = NewObserver[pb.OutboundGroupList](10)
|
||||
var (
|
||||
systemInfoObserver = NewObserver[pb.SystemInfo](10)
|
||||
outboundsInfoObserver = NewObserver[pb.OutboundGroupList](10)
|
||||
mainOutboundsInfoObserver = NewObserver[pb.OutboundGroupList](10)
|
||||
)
|
||||
|
||||
var (
|
||||
statusClient *libbox.CommandClient
|
||||
@@ -18,13 +21,13 @@ var (
|
||||
groupInfoOnlyClient *libbox.CommandClient
|
||||
)
|
||||
|
||||
func (s *CoreService) GetSystemInfo(stream pb.Core_GetSystemInfoServer) error {
|
||||
func (s *CoreService) GetSystemInfo(req *pb.Empty, stream grpc.ServerStreamingServer[pb.SystemInfo]) error {
|
||||
if statusClient == nil {
|
||||
statusClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandStatus,
|
||||
StatusInterval: 1000000000, //1000ms debounce
|
||||
StatusInterval: 1000000000, // 1000ms debounce
|
||||
},
|
||||
)
|
||||
|
||||
@@ -35,18 +38,14 @@ func (s *CoreService) GetSystemInfo(stream pb.Core_GetSystemInfoServer) error {
|
||||
statusClient.Connect()
|
||||
}
|
||||
|
||||
sub, _, _ := systemInfoObserver.Subscribe()
|
||||
stopch := make(chan int)
|
||||
go func() {
|
||||
stream.Recv()
|
||||
close(stopch)
|
||||
}()
|
||||
sub, done, _ := systemInfoObserver.Subscribe()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stream.Context().Done():
|
||||
break
|
||||
case <-stopch:
|
||||
break
|
||||
return nil
|
||||
case <-done:
|
||||
return nil
|
||||
case info := <-sub:
|
||||
stream.Send(&info)
|
||||
case <-time.After(1000 * time.Millisecond):
|
||||
@@ -54,13 +53,13 @@ func (s *CoreService) GetSystemInfo(stream pb.Core_GetSystemInfoServer) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CoreService) OutboundsInfo(stream pb.Core_OutboundsInfoServer) error {
|
||||
func (s *CoreService) OutboundsInfo(req *pb.Empty, stream grpc.ServerStreamingServer[pb.OutboundGroupList]) error {
|
||||
if groupClient == nil {
|
||||
groupClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandGroup,
|
||||
StatusInterval: 500000000, //500ms debounce
|
||||
StatusInterval: 500000000, // 500ms debounce
|
||||
},
|
||||
)
|
||||
|
||||
@@ -71,18 +70,14 @@ func (s *CoreService) OutboundsInfo(stream pb.Core_OutboundsInfoServer) error {
|
||||
groupClient.Connect()
|
||||
}
|
||||
|
||||
sub, _, _ := outboundsInfoObserver.Subscribe()
|
||||
stopch := make(chan int)
|
||||
go func() {
|
||||
stream.Recv()
|
||||
close(stopch)
|
||||
}()
|
||||
sub, done, _ := outboundsInfoObserver.Subscribe()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stream.Context().Done():
|
||||
break
|
||||
case <-stopch:
|
||||
break
|
||||
return nil
|
||||
case <-done:
|
||||
return nil
|
||||
case info := <-sub:
|
||||
stream.Send(&info)
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
@@ -90,13 +85,13 @@ func (s *CoreService) OutboundsInfo(stream pb.Core_OutboundsInfoServer) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CoreService) MainOutboundsInfo(stream pb.Core_MainOutboundsInfoServer) error {
|
||||
func (s *CoreService) MainOutboundsInfo(req *pb.Empty, stream grpc.ServerStreamingServer[pb.OutboundGroupList]) error {
|
||||
if groupInfoOnlyClient == nil {
|
||||
groupInfoOnlyClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandGroupInfoOnly,
|
||||
StatusInterval: 500000000, //500ms debounce
|
||||
StatusInterval: 500000000, // 500ms debounce
|
||||
},
|
||||
)
|
||||
|
||||
@@ -107,18 +102,14 @@ func (s *CoreService) MainOutboundsInfo(stream pb.Core_MainOutboundsInfoServer)
|
||||
groupInfoOnlyClient.Connect()
|
||||
}
|
||||
|
||||
sub, _, _ := mainOutboundsInfoObserver.Subscribe()
|
||||
stopch := make(chan int)
|
||||
go func() {
|
||||
stream.Recv()
|
||||
close(stopch)
|
||||
}()
|
||||
sub, stopch, _ := mainOutboundsInfoObserver.Subscribe()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stream.Context().Done():
|
||||
break
|
||||
return nil
|
||||
case <-stopch:
|
||||
break
|
||||
return nil
|
||||
case info := <-sub:
|
||||
stream.Send(&info)
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
@@ -129,9 +120,9 @@ func (s *CoreService) MainOutboundsInfo(stream pb.Core_MainOutboundsInfoServer)
|
||||
func (s *CoreService) SelectOutbound(ctx context.Context, in *pb.SelectOutboundRequest) (*pb.Response, error) {
|
||||
return SelectOutbound(in)
|
||||
}
|
||||
|
||||
func SelectOutbound(in *pb.SelectOutboundRequest) (*pb.Response, error) {
|
||||
err := libbox.NewStandaloneCommandClient().SelectOutbound(in.GroupTag, in.OutboundTag)
|
||||
|
||||
if err != nil {
|
||||
return &pb.Response{
|
||||
ResponseCode: pb.ResponseCode_FAILED,
|
||||
@@ -148,9 +139,9 @@ func SelectOutbound(in *pb.SelectOutboundRequest) (*pb.Response, error) {
|
||||
func (s *CoreService) UrlTest(ctx context.Context, in *pb.UrlTestRequest) (*pb.Response, error) {
|
||||
return UrlTest(in)
|
||||
}
|
||||
|
||||
func UrlTest(in *pb.UrlTestRequest) (*pb.Response, error) {
|
||||
err := libbox.NewStandaloneCommandClient().URLTest(in.GroupTag)
|
||||
|
||||
if err != nil {
|
||||
return &pb.Response{
|
||||
ResponseCode: pb.ResponseCode_FAILED,
|
||||
@@ -162,5 +153,4 @@ func UrlTest(in *pb.UrlTestRequest) (*pb.Response, error) {
|
||||
ResponseCode: pb.ResponseCode_OK,
|
||||
Message: "",
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
@@ -3,16 +3,18 @@ package v2
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hiddify/hiddify-core/bridge"
|
||||
pb "github.com/hiddify/hiddify-core/hiddifyrpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var coreInfoObserver = NewObserver[pb.CoreInfoResponse](10)
|
||||
var CoreState = pb.CoreState_STOPPED
|
||||
var (
|
||||
coreInfoObserver = *NewObserver[*pb.CoreInfoResponse](1)
|
||||
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 {
|
||||
msg := fmt.Sprintf("%s: %s %s", state.String(), msgType.String(), message)
|
||||
if msgType == pb.MessageType_EMPTY {
|
||||
msg = fmt.Sprintf("%s: %s", state.String(), message)
|
||||
@@ -24,32 +26,32 @@ func SetCoreStatus(state pb.CoreState, msgType pb.MessageType, message string) p
|
||||
MessageType: msgType,
|
||||
Message: message,
|
||||
}
|
||||
coreInfoObserver.Emit(info)
|
||||
coreInfoObserver.Emit(&info)
|
||||
if useFlutterBridge {
|
||||
msg, _ := json.Marshal(StatusMessage{Status: convert2OldState(CoreState)})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
}
|
||||
return info
|
||||
|
||||
return &info
|
||||
}
|
||||
|
||||
func (s *CoreService) CoreInfoListener(stream pb.Core_CoreInfoListenerServer) error {
|
||||
coreSub, _, _ := coreInfoObserver.Subscribe()
|
||||
func (s *CoreService) CoreInfoListener(req *pb.Empty, stream grpc.ServerStreamingServer[pb.CoreInfoResponse]) error {
|
||||
coreSub, done, err := coreInfoObserver.Subscribe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer coreInfoObserver.UnSubscribe(coreSub)
|
||||
stopch := make(chan int)
|
||||
go func() {
|
||||
stream.Recv()
|
||||
close(stopch)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stream.Context().Done():
|
||||
return nil
|
||||
case <-stopch:
|
||||
case <-done:
|
||||
return nil
|
||||
case info := <-coreSub:
|
||||
stream.Send(&info)
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
stream.Send(info)
|
||||
// case <-time.After(500 * time.Millisecond):
|
||||
// info := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_EMPTY, "")
|
||||
// stream.Send(info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
v2/custom.go
26
v2/custom.go
@@ -83,7 +83,7 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_READING_CONFIG, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
return &resp, err
|
||||
return resp, err
|
||||
}
|
||||
content = string(fileContent)
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_PARSING_CONFIG, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
return &resp, err
|
||||
return resp, err
|
||||
}
|
||||
if !in.EnableRawConfig {
|
||||
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Building config")
|
||||
@@ -105,7 +105,7 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_ERROR_BUILDING_CONFIG, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
return &resp, err
|
||||
return resp, err
|
||||
}
|
||||
parsedContent = *parsedContent_tmp
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_COMMAND_SERVER, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
return &resp, err
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_CREATE_SERVICE, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
return &resp, err
|
||||
return resp, err
|
||||
}
|
||||
Log(pb.LogLevel_DEBUG, pb.LogType_CORE, "Service.. started")
|
||||
if in.DelayStart {
|
||||
@@ -144,7 +144,7 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
Log(pb.LogLevel_FATAL, pb.LogType_CORE, err.Error())
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_START_SERVICE, err.Error())
|
||||
StopAndAlert(pb.MessageType_UNEXPECTED_ERROR, err.Error())
|
||||
return &resp, err
|
||||
return resp, err
|
||||
}
|
||||
Box = instance
|
||||
if in.EnableOldCommandServer {
|
||||
@@ -152,7 +152,7 @@ func StartService(in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
}
|
||||
|
||||
resp := SetCoreStatus(pb.CoreState_STARTED, pb.MessageType_EMPTY, "")
|
||||
return &resp, nil
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *CoreService) Parse(ctx context.Context, in *pb.ParseRequest) (*pb.ParseResponse, error) {
|
||||
@@ -199,13 +199,13 @@ func Parse(in *pb.ParseRequest) (*pb.ParseResponse, error) {
|
||||
}, err
|
||||
}
|
||||
|
||||
func (s *CoreService) ChangeHiddifyOptions(ctx context.Context, in *pb.ChangeHiddifyOptionsRequest) (*pb.CoreInfoResponse, error) {
|
||||
return ChangeHiddifyOptions(in)
|
||||
func (s *CoreService) ChangeHiddifySettings(ctx context.Context, in *pb.ChangeHiddifySettingsRequest) (*pb.CoreInfoResponse, error) {
|
||||
return ChangeHiddifySettings(in)
|
||||
}
|
||||
|
||||
func ChangeHiddifyOptions(in *pb.ChangeHiddifyOptionsRequest) (*pb.CoreInfoResponse, error) {
|
||||
HiddifyOptions = &config.HiddifyOptions{}
|
||||
err := json.Unmarshal([]byte(in.HiddifyOptionsJson), HiddifyOptions)
|
||||
func ChangeHiddifySettings(in *pb.ChangeHiddifySettingsRequest) (*pb.CoreInfoResponse, error) {
|
||||
HiddifyOptions = config.DefaultHiddifyOptions()
|
||||
err := json.Unmarshal([]byte(in.HiddifySettingsJson), HiddifyOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -314,7 +314,7 @@ func Stop() (*pb.CoreInfoResponse, error) {
|
||||
oldCommandServer = nil
|
||||
}
|
||||
resp := SetCoreStatus(pb.CoreState_STOPPED, pb.MessageType_EMPTY, "")
|
||||
return &resp, nil
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *CoreService) Restart(ctx context.Context, in *pb.StartRequest) (*pb.CoreInfoResponse, error) {
|
||||
|
||||
@@ -33,6 +33,11 @@ func StartGrpcServer(listenAddressG string, service string) (*grpc.Server, error
|
||||
}
|
||||
s := grpc.NewServer()
|
||||
if service == "core" {
|
||||
|
||||
// Setup("./tmp/", "./tmp", "./tmp", 11111, false)
|
||||
Setup("./tmp", "./", "./tmp", 0, false)
|
||||
|
||||
useFlutterBridge = false
|
||||
pb.RegisterCoreServer(s, &CoreService{})
|
||||
pb.RegisterExtensionHostServiceServer(s, &extension.ExtensionHostService{})
|
||||
} else if service == "hello" {
|
||||
|
||||
172
v2/independent_instance.go
Normal file
172
v2/independent_instance.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/hiddify/hiddify-core/config"
|
||||
"golang.org/x/net/proxy"
|
||||
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
func getRandomAvailblePort() uint16 {
|
||||
// TODO: implement it
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer listener.Close()
|
||||
return uint16(listener.Addr().(*net.TCPAddr).Port)
|
||||
}
|
||||
|
||||
func RunInstanceString(hiddifySettings *config.HiddifyOptions, proxiesInput string) (*HiddifyService, error) {
|
||||
if hiddifySettings == nil {
|
||||
hiddifySettings = config.DefaultHiddifyOptions()
|
||||
}
|
||||
singconfigs, err := config.ParseConfigContentToOptions(proxiesInput, true, hiddifySettings, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return RunInstance(hiddifySettings, singconfigs)
|
||||
}
|
||||
|
||||
func RunInstance(hiddifySettings *config.HiddifyOptions, singconfig *option.Options) (*HiddifyService, error) {
|
||||
if hiddifySettings == nil {
|
||||
hiddifySettings = config.DefaultHiddifyOptions()
|
||||
}
|
||||
hiddifySettings.EnableClashApi = false
|
||||
hiddifySettings.InboundOptions.MixedPort = getRandomAvailblePort()
|
||||
hiddifySettings.InboundOptions.EnableTun = false
|
||||
hiddifySettings.InboundOptions.EnableTunService = false
|
||||
hiddifySettings.InboundOptions.SetSystemProxy = false
|
||||
hiddifySettings.InboundOptions.TProxyPort = 0
|
||||
hiddifySettings.InboundOptions.LocalDnsPort = 0
|
||||
hiddifySettings.Region = "other"
|
||||
hiddifySettings.BlockAds = false
|
||||
hiddifySettings.LogFile = "/dev/null"
|
||||
|
||||
finalConfigs, err := config.BuildConfig(*hiddifySettings, *singconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instance, err := NewService(*finalConfigs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = instance.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
<-time.After(250 * time.Millisecond)
|
||||
hservice := &HiddifyService{libbox: instance, ListenPort: hiddifySettings.InboundOptions.MixedPort}
|
||||
hservice.PingCloudflare()
|
||||
return hservice, nil
|
||||
}
|
||||
|
||||
type HiddifyService struct {
|
||||
libbox *libbox.BoxService
|
||||
ListenPort uint16
|
||||
}
|
||||
|
||||
// dialer, err := s.libbox.GetInstance().Router().Dialer(context.Background())
|
||||
|
||||
func (s *HiddifyService) Close() error {
|
||||
return s.libbox.Close()
|
||||
}
|
||||
|
||||
func (s *HiddifyService) GetContent(url string) (string, error) {
|
||||
return s.ContentFromURL("GET", url, 10*time.Second)
|
||||
}
|
||||
|
||||
func (s *HiddifyService) ContentFromURL(method string, url string, timeout time.Duration) (string, error) {
|
||||
if method == "" {
|
||||
return "", fmt.Errorf("empty method")
|
||||
}
|
||||
if url == "" {
|
||||
return "", fmt.Errorf("empty url")
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
dialer, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", s.ListenPort), nil, proxy.Direct)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
Dial: dialer.Dial,
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
Timeout: timeout,
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
|
||||
return "", fmt.Errorf("request failed with status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if body == nil {
|
||||
return "", fmt.Errorf("empty body")
|
||||
}
|
||||
|
||||
return string(body), nil
|
||||
}
|
||||
|
||||
func (s *HiddifyService) PingCloudflare() (time.Duration, error) {
|
||||
return s.Ping("http://cp.cloudflare.com")
|
||||
}
|
||||
|
||||
// func (s *HiddifyService) RawConnection(ctx context.Context, url string) (net.Conn, error) {
|
||||
// return
|
||||
// }
|
||||
|
||||
func (s *HiddifyService) PingAverage(url string, count int) (time.Duration, error) {
|
||||
if count <= 0 {
|
||||
return -1, fmt.Errorf("count must be greater than 0")
|
||||
}
|
||||
|
||||
var sum int
|
||||
real_count := 0
|
||||
for i := 0; i < count; i++ {
|
||||
delay, err := s.Ping(url)
|
||||
if err == nil {
|
||||
real_count++
|
||||
sum += int(delay.Milliseconds())
|
||||
} else if real_count == 0 && i > count/2 {
|
||||
return -1, fmt.Errorf("ping average failed")
|
||||
}
|
||||
|
||||
}
|
||||
return time.Duration(sum / real_count * int(time.Millisecond)), nil
|
||||
}
|
||||
|
||||
func (s *HiddifyService) Ping(url string) (time.Duration, error) {
|
||||
startTime := time.Now()
|
||||
_, err := s.ContentFromURL("HEAD", url, 4*time.Second)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
duration := time.Since(startTime)
|
||||
return duration, nil
|
||||
}
|
||||
@@ -6,10 +6,11 @@ import (
|
||||
|
||||
pb "github.com/hiddify/hiddify-core/hiddifyrpc"
|
||||
"github.com/sagernet/sing/common/observable"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func NewObserver[T any](listenerBufferSize int) *observable.Observer[T] {
|
||||
return observable.NewObserver[T](&observable.Subscriber[T]{}, listenerBufferSize)
|
||||
return observable.NewObserver(observable.NewSubscriber[T](listenerBufferSize), listenerBufferSize)
|
||||
}
|
||||
|
||||
var logObserver = NewObserver[pb.LogMessage](10)
|
||||
@@ -17,29 +18,24 @@ var logObserver = NewObserver[pb.LogMessage](10)
|
||||
func Log(level pb.LogLevel, typ pb.LogType, message string) {
|
||||
if level != pb.LogLevel_DEBUG {
|
||||
fmt.Printf("%s %s %s\n", level, typ, message)
|
||||
|
||||
}
|
||||
logObserver.Emit(pb.LogMessage{
|
||||
Level: level,
|
||||
Type: typ,
|
||||
Message: message,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (s *CoreService) LogListener(stream pb.Core_LogListenerServer) error {
|
||||
logSub, _, _ := logObserver.Subscribe()
|
||||
func (s *CoreService) LogListener(req *pb.Empty, stream grpc.ServerStreamingServer[pb.LogMessage]) error {
|
||||
logSub, stopch, _ := logObserver.Subscribe()
|
||||
defer logObserver.UnSubscribe(logSub)
|
||||
|
||||
stopch := make(chan int)
|
||||
go func() {
|
||||
stream.Recv()
|
||||
close(stopch)
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-stream.Context().Done():
|
||||
return nil
|
||||
case <-stopch:
|
||||
return nil
|
||||
case info := <-logSub:
|
||||
stream.Send(&info)
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
|
||||
@@ -68,7 +68,7 @@ func readAndBuildConfig(hiddifySettingPath string, configPath string, defaultCon
|
||||
}
|
||||
|
||||
if hiddifySettingPath != "" {
|
||||
hiddifyconfig, err = readHiddifyOptionsAt(hiddifySettingPath)
|
||||
hiddifyconfig, err = ReadHiddifyOptionsAt(hiddifySettingPath)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func readConfigContent(configPath string) (ConfigResult, error) {
|
||||
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")
|
||||
req.Header.Set("User-Agent", "HiddifyNext/2.3.1 ("+runtime.GOOS+") like ClashMeta v2ray sing-box")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making GET request:", err)
|
||||
@@ -222,7 +222,7 @@ func readConfigBytes(content []byte) (*option.Options, error) {
|
||||
return &options, nil
|
||||
}
|
||||
|
||||
func readHiddifyOptionsAt(path string) (*config.HiddifyOptions, error) {
|
||||
func ReadHiddifyOptionsAt(path string) (*config.HiddifyOptions, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user