141 lines
4.5 KiB
Go
141 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/sagernet/sing-box/common/networkquality"
|
|
"github.com/sagernet/sing-box/common/stun"
|
|
"github.com/sagernet/sing-box/daemon"
|
|
"github.com/sagernet/sing-box/experimental/libbox"
|
|
"github.com/sagernet/sing-box/include"
|
|
"github.com/sagernet/sing-box/option"
|
|
"github.com/sagernet/sing-box/schema"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
|
)
|
|
|
|
var _ ApplicationServiceServer = (*applicationService)(nil)
|
|
|
|
type applicationService struct {
|
|
UnimplementedApplicationServiceServer
|
|
startedService *daemon.StartedService
|
|
}
|
|
|
|
func (s *applicationService) CheckConfig(ctx context.Context, request *ConfigContent) (*emptypb.Empty, error) {
|
|
err := s.startedService.CheckConfig(ctx, request.Content)
|
|
if err != nil {
|
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
|
}
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func (s *applicationService) FormatConfig(ctx context.Context, request *ConfigContent) (*ConfigContent, error) {
|
|
content, err := s.startedService.FormatConfig(ctx, request.Content)
|
|
if err != nil {
|
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
|
}
|
|
return &ConfigContent{Content: content}, nil
|
|
}
|
|
|
|
func (s *applicationService) GenerateConfigSchema(ctx context.Context, request *emptypb.Empty) (*ConfigContent, error) {
|
|
content, err := schema.Generate(include.Context(context.Background()), reflect.TypeFor[option.Options]())
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &ConfigContent{Content: string(content)}, nil
|
|
}
|
|
|
|
func (s *applicationService) EncodeProfile(ctx context.Context, request *ProfileContent) (*ProfileData, error) {
|
|
content := libbox.ProfileContent{
|
|
Name: request.Name,
|
|
Type: int32(request.Type),
|
|
Config: request.Config,
|
|
RemotePath: request.RemotePath,
|
|
AutoUpdate: request.AutoUpdate,
|
|
AutoUpdateInterval: request.AutoUpdateInterval,
|
|
LastUpdated: request.LastUpdated,
|
|
}
|
|
return &ProfileData{Data: content.Encode()}, nil
|
|
}
|
|
|
|
func (s *applicationService) DecodeProfile(ctx context.Context, request *ProfileData) (*ProfileContent, error) {
|
|
content, err := libbox.DecodeProfileContent(request.Data)
|
|
if err != nil {
|
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
|
}
|
|
return &ProfileContent{
|
|
Type: ProfileContent_Type(content.Type),
|
|
Name: content.Name,
|
|
Config: content.Config,
|
|
RemotePath: content.RemotePath,
|
|
AutoUpdate: content.AutoUpdate,
|
|
AutoUpdateInterval: content.AutoUpdateInterval,
|
|
LastUpdated: content.LastUpdated,
|
|
}, nil
|
|
}
|
|
|
|
func (s *applicationService) ArchiveReport(ctx context.Context, request *ArchiveReportRequest) (*emptypb.Empty, error) {
|
|
err := libbox.CreateZipArchive(request.SourcePath, request.DestinationPath, request.Encrypt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func (s *applicationService) StartStandaloneNetworkQualityTest(
|
|
request *StandaloneNetworkQualityTestRequest,
|
|
server grpc.ServerStreamingServer[daemon.NetworkQualityTestProgress],
|
|
) error {
|
|
httpClient := networkquality.NewHTTPClient(nil)
|
|
defer httpClient.CloseIdleConnections()
|
|
|
|
measurementClientFactory, err := networkquality.NewOptionalHTTP3Factory(nil, request.Http3)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
result, err := networkquality.Run(networkquality.Options{
|
|
ConfigURL: request.ConfigUrl,
|
|
HTTPClient: httpClient,
|
|
NewMeasurementClient: measurementClientFactory,
|
|
Serial: request.Serial,
|
|
MaxRuntime: time.Duration(request.MaxRuntimeSeconds) * time.Second,
|
|
Context: server.Context(),
|
|
OnProgress: func(progress networkquality.Progress) {
|
|
_ = server.Send(daemon.NewNetworkQualityTestProgress(progress))
|
|
},
|
|
})
|
|
if err != nil {
|
|
return server.Send(&daemon.NetworkQualityTestProgress{
|
|
IsFinal: true,
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
return server.Send(daemon.NewNetworkQualityTestResult(result))
|
|
}
|
|
|
|
func (s *applicationService) StartStandaloneSTUNTest(
|
|
request *StandaloneSTUNTestRequest,
|
|
server grpc.ServerStreamingServer[daemon.STUNTestProgress],
|
|
) error {
|
|
result, err := stun.Run(stun.Options{
|
|
Server: request.Server,
|
|
Context: server.Context(),
|
|
OnProgress: func(progress stun.Progress) {
|
|
_ = server.Send(daemon.NewSTUNTestProgress(progress))
|
|
},
|
|
})
|
|
if err != nil {
|
|
return server.Send(&daemon.STUNTestProgress{
|
|
IsFinal: true,
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
return server.Send(daemon.NewSTUNTestResult(result))
|
|
}
|