Add api command

This commit is contained in:
世界
2026-08-30 17:41:45 +08:00
parent fcee5656b9
commit bd059fc8aa
51 changed files with 5413 additions and 4 deletions
+107
View File
@@ -0,0 +1,107 @@
package main
import (
"os"
"strings"
"github.com/sagernet/sing-box/daemon"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var (
commandAPIFlagURL string
commandAPIFlagSecret string
commandAPIServerURL string
)
var commandAPI = &cobra.Command{
Use: "api <command>",
Short: "API service client",
DisableFlagParsing: true,
Run: func(cmd *cobra.Command, args []string) {
err := runAPI(args)
if err != nil {
log.Fatal(err)
}
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
targetCommand, remainingArgs, err := commandAPIRoot.Find(args)
if err != nil || len(remainingArgs) > 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return common.Map(common.Filter(targetCommand.Commands(), func(it *cobra.Command) bool {
return it.IsAvailableCommand() && strings.HasPrefix(it.Name(), toComplete)
}), func(it *cobra.Command) string {
return it.Name() + "\t" + it.Short
}), cobra.ShellCompDirectiveNoFileComp
},
}
var commandAPIRoot = &cobra.Command{
Use: "api",
Short: "API service client",
SilenceUsage: true,
SilenceErrors: true,
CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
}
func init() {
commandAPIRoot.PersistentFlags().StringVar(&commandAPIFlagURL, "url", "", "API service URL (default: $BOX_API_URL)")
commandAPIRoot.PersistentFlags().StringVar(&commandAPIFlagSecret, "secret", "", "API service secret (default: $BOX_API_SECRET)")
mainCommand.AddCommand(commandAPI)
}
func runAPI(args []string) error {
commandAPIRoot.SetArgs(append([]string{}, args...))
err := commandAPIRoot.Execute()
if err == nil {
return nil
}
grpcStatus, isStatus := status.FromError(err)
if !isStatus {
return err
}
switch grpcStatus.Code() {
case codes.Unavailable:
return E.New("failed to connect to API service at ", commandAPIServerURL, ": ", grpcStatus.Message())
case codes.Unknown:
return E.New(grpcStatus.Message())
case codes.Unimplemented:
return E.New(grpcStatus.Code().String(), ": ", grpcStatus.Message(), " (client API version ", daemon.APIVersion, ")")
default:
return E.New(grpcStatus.Code().String(), ": ", grpcStatus.Message())
}
}
func createAPIClient() (*grpc.ClientConn, daemon.StartedServiceClient, error) {
serverURL := commandAPIFlagURL
if serverURL == "" {
serverURL = os.Getenv("BOX_API_URL")
}
if serverURL == "" {
return nil, nil, E.New("missing API service URL, set --url or BOX_API_URL")
}
if !strings.Contains(serverURL, "://") {
serverURL = "http://" + serverURL
}
commandAPIServerURL = serverURL
secret := commandAPIFlagSecret
if secret == "" {
secret = os.Getenv("BOX_API_SECRET")
}
clientConn, err := daemon.NewRemoteClient(daemon.RemoteClientOptions{
ServerURL: serverURL,
Secret: secret,
})
if err != nil {
return nil, nil, err
}
return clientConn, daemon.NewStartedServiceClient(clientConn), nil
}