api.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package all
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "strings"
  7. "time"
  8. "github.com/golang/protobuf/proto"
  9. "google.golang.org/grpc"
  10. logService "github.com/v2fly/v2ray-core/v4/app/log/command"
  11. statsService "github.com/v2fly/v2ray-core/v4/app/stats/command"
  12. "github.com/v2fly/v2ray-core/v4/commands/base"
  13. )
  14. // cmdAPI calls an API in an V2Ray process
  15. var cmdAPI = &base.Command{
  16. UsageLine: "{{.Exec}} api [-server 127.0.0.1:8080] <action> <parameter>",
  17. Short: "Call V2Ray API",
  18. Long: `
  19. Call V2Ray API, API calls in this command have a timeout to the server of 3 seconds.
  20. The following methods are currently supported:
  21. LoggerService.RestartLogger
  22. StatsService.GetStats
  23. StatsService.QueryStats
  24. Examples:
  25. {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 LoggerService.RestartLogger ''
  26. {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 StatsService.QueryStats 'pattern: "" reset: false'
  27. {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 StatsService.GetStats 'name: "inbound>>>statin>>>traffic>>>downlink" reset: false'
  28. {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 StatsService.GetSysStats ''
  29. `,
  30. }
  31. func init() {
  32. cmdAPI.Run = executeAPI // break init loop
  33. }
  34. var (
  35. apiServerAddrPtr = cmdAPI.Flag.String("server", "127.0.0.1:8080", "")
  36. )
  37. func executeAPI(cmd *base.Command, args []string) {
  38. unnamedArgs := cmdAPI.Flag.Args()
  39. if len(unnamedArgs) < 2 {
  40. base.Fatalf("service name or request not specified.")
  41. }
  42. service, method := getServiceMethod(unnamedArgs[0])
  43. handler, found := serivceHandlerMap[strings.ToLower(service)]
  44. if !found {
  45. base.Fatalf("unknown service: %s", service)
  46. }
  47. ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
  48. defer cancel()
  49. conn, err := grpc.DialContext(ctx, *apiServerAddrPtr, grpc.WithInsecure(), grpc.WithBlock())
  50. if err != nil {
  51. base.Fatalf("failed to dial %s", *apiServerAddrPtr)
  52. }
  53. defer conn.Close()
  54. response, err := handler(ctx, conn, method, unnamedArgs[1])
  55. if err != nil {
  56. base.Fatalf("failed to call service %s: %s", unnamedArgs[0], err)
  57. }
  58. fmt.Println(response)
  59. }
  60. func getServiceMethod(s string) (string, string) {
  61. ss := strings.Split(s, ".")
  62. service := ss[0]
  63. var method string
  64. if len(ss) > 1 {
  65. method = ss[1]
  66. }
  67. return service, method
  68. }
  69. type serviceHandler func(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error)
  70. var serivceHandlerMap = map[string]serviceHandler{
  71. "statsservice": callStatsService,
  72. "loggerservice": callLogService,
  73. }
  74. func callLogService(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error) {
  75. client := logService.NewLoggerServiceClient(conn)
  76. switch strings.ToLower(method) {
  77. case "restartlogger":
  78. r := &logService.RestartLoggerRequest{}
  79. resp, err := client.RestartLogger(ctx, r)
  80. if err != nil {
  81. return "", err
  82. }
  83. return proto.MarshalTextString(resp), nil
  84. default:
  85. return "", errors.New("Unknown method: " + method)
  86. }
  87. }
  88. func callStatsService(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error) {
  89. client := statsService.NewStatsServiceClient(conn)
  90. switch strings.ToLower(method) {
  91. case "getstats":
  92. r := &statsService.GetStatsRequest{}
  93. if err := proto.UnmarshalText(request, r); err != nil {
  94. return "", err
  95. }
  96. resp, err := client.GetStats(ctx, r)
  97. if err != nil {
  98. return "", err
  99. }
  100. return proto.MarshalTextString(resp), nil
  101. case "querystats":
  102. r := &statsService.QueryStatsRequest{}
  103. if err := proto.UnmarshalText(request, r); err != nil {
  104. return "", err
  105. }
  106. resp, err := client.QueryStats(ctx, r)
  107. if err != nil {
  108. return "", err
  109. }
  110. return proto.MarshalTextString(resp), nil
  111. case "getsysstats":
  112. // SysStatsRequest is an empty message
  113. r := &statsService.SysStatsRequest{}
  114. resp, err := client.GetSysStats(ctx, r)
  115. if err != nil {
  116. return "", err
  117. }
  118. return proto.MarshalTextString(resp), nil
  119. default:
  120. return "", errors.New("Unknown method: " + method)
  121. }
  122. }