mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-30 03:25:41 +00:00
Add api command
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/common/networkquality"
|
||||
"github.com/sagernet/sing-box/daemon"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
commandAPINetworkQualityFlagConfigURL string
|
||||
commandAPINetworkQualityFlagSerial bool
|
||||
commandAPINetworkQualityFlagMaxRuntime int
|
||||
commandAPINetworkQualityFlagHTTP3 bool
|
||||
commandAPINetworkQualityFlagOutbound string
|
||||
)
|
||||
|
||||
var commandAPINetworkQuality = &cobra.Command{
|
||||
Use: "networkquality",
|
||||
Short: "Run a network quality test",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runAPINetworkQuality()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
commandAPINetworkQuality.Flags().StringVar(
|
||||
&commandAPINetworkQualityFlagConfigURL,
|
||||
"config-url", "",
|
||||
"Network quality test config URL (default: Apple mensura)",
|
||||
)
|
||||
commandAPINetworkQuality.Flags().BoolVar(
|
||||
&commandAPINetworkQualityFlagSerial,
|
||||
"serial", false,
|
||||
"Run download and upload tests sequentially instead of in parallel",
|
||||
)
|
||||
commandAPINetworkQuality.Flags().IntVar(
|
||||
&commandAPINetworkQualityFlagMaxRuntime,
|
||||
"max-runtime", int(networkquality.DefaultMaxRuntime/time.Second),
|
||||
"Network quality maximum runtime in seconds",
|
||||
)
|
||||
commandAPINetworkQuality.Flags().BoolVar(
|
||||
&commandAPINetworkQualityFlagHTTP3,
|
||||
"http3", false,
|
||||
"Use HTTP/3 (QUIC) for measurement traffic",
|
||||
)
|
||||
commandAPINetworkQuality.Flags().StringVarP(
|
||||
&commandAPINetworkQualityFlagOutbound,
|
||||
"outbound", "o", "",
|
||||
"Use specified tag instead of default outbound",
|
||||
)
|
||||
commandAPIRoot.AddCommand(commandAPINetworkQuality)
|
||||
}
|
||||
|
||||
func runAPINetworkQuality() error {
|
||||
clientConn, client, err := createAPIClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clientConn.Close()
|
||||
stream, err := client.StartNetworkQualityTest(globalCtx, &daemon.NetworkQualityTestRequest{
|
||||
ConfigURL: commandAPINetworkQualityFlagConfigURL,
|
||||
OutboundTag: commandAPINetworkQualityFlagOutbound,
|
||||
Serial: commandAPINetworkQualityFlagSerial,
|
||||
MaxRuntimeSeconds: int32(commandAPINetworkQualityFlagMaxRuntime),
|
||||
Http3: commandAPINetworkQualityFlagHTTP3,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writeStderrLine("==== NETWORK QUALITY TEST ====")
|
||||
for {
|
||||
progress, recvErr := stream.Recv()
|
||||
if recvErr != nil {
|
||||
return recvErr
|
||||
}
|
||||
if !progress.GetIsFinal() {
|
||||
writeNetworkQualityProgress(progress)
|
||||
continue
|
||||
}
|
||||
writeStderrLine("")
|
||||
if progress.GetError() != "" {
|
||||
return E.New(progress.GetError())
|
||||
}
|
||||
writeStderrLine(strings.Repeat("-", 40))
|
||||
fmt.Fprintf(os.Stdout, "Idle Latency: %d ms\n", progress.GetIdleLatencyMs())
|
||||
fmt.Fprintf(os.Stdout, "Download Capacity: %-20s Accuracy: %s\n",
|
||||
networkquality.FormatBitrate(progress.GetDownloadCapacity()),
|
||||
networkquality.Accuracy(progress.GetDownloadCapacityAccuracy()))
|
||||
fmt.Fprintf(os.Stdout, "Upload Capacity: %-20s Accuracy: %s\n",
|
||||
networkquality.FormatBitrate(progress.GetUploadCapacity()),
|
||||
networkquality.Accuracy(progress.GetUploadCapacityAccuracy()))
|
||||
fmt.Fprintf(os.Stdout, "Download Responsiveness: %-20s Accuracy: %s\n",
|
||||
fmt.Sprintf("%d RPM", progress.GetDownloadRPM()),
|
||||
networkquality.Accuracy(progress.GetDownloadRPMAccuracy()))
|
||||
fmt.Fprintf(os.Stdout, "Upload Responsiveness: %-20s Accuracy: %s\n",
|
||||
fmt.Sprintf("%d RPM", progress.GetUploadRPM()),
|
||||
networkquality.Accuracy(progress.GetUploadRPMAccuracy()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func writeNetworkQualityProgress(progress *daemon.NetworkQualityTestProgress) {
|
||||
if !commandAPINetworkQualityFlagSerial && networkquality.Phase(progress.GetPhase()) != networkquality.PhaseIdle {
|
||||
writeProgress(fmt.Sprintf("Download: %s RPM: %d Upload: %s RPM: %d",
|
||||
networkquality.FormatBitrate(progress.GetDownloadCapacity()), progress.GetDownloadRPM(),
|
||||
networkquality.FormatBitrate(progress.GetUploadCapacity()), progress.GetUploadRPM()))
|
||||
return
|
||||
}
|
||||
switch networkquality.Phase(progress.GetPhase()) {
|
||||
case networkquality.PhaseIdle:
|
||||
if progress.GetIdleLatencyMs() > 0 {
|
||||
writeProgress(fmt.Sprintf("Idle Latency: %d ms", progress.GetIdleLatencyMs()))
|
||||
} else {
|
||||
writeProgress("Measuring idle latency...")
|
||||
}
|
||||
case networkquality.PhaseDownload:
|
||||
writeProgress(fmt.Sprintf("Download: %s RPM: %d",
|
||||
networkquality.FormatBitrate(progress.GetDownloadCapacity()), progress.GetDownloadRPM()))
|
||||
case networkquality.PhaseUpload:
|
||||
writeProgress(fmt.Sprintf("Upload: %s RPM: %d",
|
||||
networkquality.FormatBitrate(progress.GetUploadCapacity()), progress.GetUploadRPM()))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user