mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-20 00:04:24 +00:00
Add api command
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/daemon"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
var commandAPIUsbipStatus = &cobra.Command{
|
||||
Use: "status",
|
||||
Short: "Print the shared USB devices",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runAPIUsbipStatus()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
commandAPIUsbipStatus.Flags().StringVar(&commandAPIUsbipStatusFlagService, "service", "", "Restrict to one usbip-server tag")
|
||||
commandAPIUsbip.AddCommand(commandAPIUsbipStatus)
|
||||
}
|
||||
|
||||
func runAPIUsbipStatus() error {
|
||||
clientConn, client, err := createAPIClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clientConn.Close()
|
||||
ctx, cancel := context.WithCancel(globalCtx)
|
||||
defer cancel()
|
||||
servers, err := fetchUsbipServers(ctx, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if commandAPIUsbipStatusFlagService != "" {
|
||||
server, findErr := resolveUsbipServer(servers, commandAPIUsbipStatusFlagService)
|
||||
if findErr != nil {
|
||||
return findErr
|
||||
}
|
||||
servers = []*daemon.USBIPServerStatus{server}
|
||||
}
|
||||
for index, server := range servers {
|
||||
if len(servers) > 1 {
|
||||
if index > 0 {
|
||||
os.Stdout.WriteString("\n")
|
||||
}
|
||||
os.Stdout.WriteString(server.GetServerTag() + "\n")
|
||||
}
|
||||
table := tableWriter{
|
||||
header: []string{"BUSID", "VID:PID", "PRODUCT", "STATE"},
|
||||
emptyMessage: "no shared devices",
|
||||
}
|
||||
for _, device := range server.GetDevices() {
|
||||
table.addRow(
|
||||
device.GetBusId(),
|
||||
usbipVendorProduct(uint16(device.GetDescriptor_().GetVendorId()), uint16(device.GetDescriptor_().GetProductId())),
|
||||
device.GetDescriptor_().GetProduct(),
|
||||
usbipDeviceStateString(device.GetState()),
|
||||
)
|
||||
}
|
||||
table.flush()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SubscribeUSBIPServerStatus never completes: with no dynamic usbip-server it sends
|
||||
// a single empty update and then blocks until the client cancels.
|
||||
func fetchUsbipServers(ctx context.Context, client daemon.StartedServiceClient) ([]*daemon.USBIPServerStatus, error) {
|
||||
stream, err := client.SubscribeUSBIPServerStatus(ctx, &emptypb.Empty{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update, err := stream.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return update.GetServers(), nil
|
||||
}
|
||||
|
||||
func resolveUsbipServer(servers []*daemon.USBIPServerStatus, tag string) (*daemon.USBIPServerStatus, error) {
|
||||
if tag != "" {
|
||||
index := slices.IndexFunc(servers, func(it *daemon.USBIPServerStatus) bool {
|
||||
return it.GetServerTag() == tag
|
||||
})
|
||||
if index == -1 {
|
||||
return nil, E.New("usbip-server not found: ", tag, usbipServerTagHint(servers))
|
||||
}
|
||||
return servers[index], nil
|
||||
}
|
||||
switch len(servers) {
|
||||
case 0:
|
||||
return nil, E.New("no usbip-server found")
|
||||
case 1:
|
||||
return servers[0], nil
|
||||
default:
|
||||
return nil, E.New("multiple usbip-servers found, select one with --service", usbipServerTagHint(servers))
|
||||
}
|
||||
}
|
||||
|
||||
func usbipServerTagHint(servers []*daemon.USBIPServerStatus) string {
|
||||
if len(servers) == 0 {
|
||||
return " (no usbip-server with dynamic provider found)"
|
||||
}
|
||||
return " (known tags: " + strings.Join(common.Map(servers, func(it *daemon.USBIPServerStatus) string {
|
||||
return it.GetServerTag()
|
||||
}), ", ") + ")"
|
||||
}
|
||||
|
||||
func usbipVendorProduct(vendorID uint16, productID uint16) string {
|
||||
return fmt.Sprintf("%04x:%04x", vendorID, productID)
|
||||
}
|
||||
|
||||
func usbipDeviceStateString(state daemon.USBDeviceState) string {
|
||||
return strings.ToLower(strings.TrimPrefix(state.String(), "USB_DEVICE_STATE_"))
|
||||
}
|
||||
Reference in New Issue
Block a user