restful-api.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package restful_api
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "github.com/v2fly/v2ray-core/v4/common/net"
  5. "github.com/v2fly/v2ray-core/v4/transport/internet"
  6. "net/http"
  7. "strings"
  8. )
  9. type StatsUser struct {
  10. uuid string `form:"uuid" binging:"required_without=email,uuid4"`
  11. email string `form:"email" binging:"required_without=uuid,email"`
  12. }
  13. func (r *restfulService) statsUser(c *gin.Context) {
  14. var statsUser StatsUser
  15. if err := c.BindQuery(&statsUser); err != nil {
  16. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  17. }
  18. c.JSON(http.StatusOK, gin.H{
  19. "uplink": 1,
  20. "downlink": 1,
  21. })
  22. }
  23. type Stats struct {
  24. tag string `form:"tag" binging:"required,alpha,min=1,max=255"`
  25. }
  26. type StatsBound struct { // Better name?
  27. Uplink int64 `json:"uplink"`
  28. Downlink int64 `json:"downlink"`
  29. }
  30. type StatsResponse struct {
  31. Inbound StatsBound `json:"inbound"`
  32. Outbound StatsBound `json:"outbound"`
  33. }
  34. func (r *restfulService) statsRequest(c *gin.Context) {
  35. var stats Stats
  36. if err := c.BindQuery(&stats); err != nil {
  37. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  38. }
  39. response := StatsResponse{
  40. Inbound: StatsBound{
  41. Uplink: 1,
  42. Downlink: 1,
  43. },
  44. Outbound: StatsBound{
  45. Uplink: 1,
  46. Downlink: 1,
  47. }}
  48. c.JSON(http.StatusOK, response)
  49. }
  50. func (r *restfulService) loggerReboot(c *gin.Context) {
  51. c.JSON(http.StatusOK, gin.H{})
  52. }
  53. func (r *restfulService) TokenAuthMiddleware() gin.HandlerFunc {
  54. return func(c *gin.Context) {
  55. auth := c.GetHeader("Authorization")
  56. const prefix = "Bearer "
  57. if !strings.HasPrefix(auth, prefix) {
  58. c.JSON(http.StatusUnauthorized, "unauthorized")
  59. c.Abort()
  60. return
  61. }
  62. auth = strings.TrimPrefix(auth, prefix)
  63. if auth != r.config.AuthToken { // tip: Bearer: token123
  64. c.JSON(http.StatusUnauthorized, "unauthorized")
  65. c.Abort()
  66. return
  67. }
  68. c.Next()
  69. }
  70. }
  71. func (r *restfulService) start() error {
  72. r.Engine = gin.New()
  73. r.GET("/ping", func(c *gin.Context) {
  74. c.JSON(200, gin.H{
  75. "message": "pong",
  76. })
  77. })
  78. v1 := r.Group("/v1")
  79. v1.Use(r.TokenAuthMiddleware())
  80. {
  81. v1.GET("/stats/user", r.statsUser)
  82. v1.GET("/stats", r.statsRequest)
  83. v1.POST("/logger/reboot", r.loggerReboot)
  84. }
  85. var listener net.Listener
  86. var err error
  87. address := net.ParseAddress(r.config.ListenAddr)
  88. switch {
  89. case address.Family().IsIP():
  90. listener, err = internet.ListenSystem(r.ctx, &net.TCPAddr{IP: address.IP(), Port: int(r.config.ListenPort)}, nil)
  91. case strings.EqualFold(address.Domain(), "localhost"):
  92. listener, err = internet.ListenSystem(r.ctx, &net.TCPAddr{IP: net.IP{127, 0, 0, 1}, Port: int(r.config.ListenPort)}, nil)
  93. default:
  94. return newError("restful api cannot listen on the address: ", address)
  95. }
  96. if err != nil {
  97. return newError("restful api cannot listen on the port ", r.config.ListenPort).Base(err)
  98. }
  99. r.listener = listener
  100. go func() {
  101. if err := r.RunListener(listener); err != nil {
  102. newError("unable to serve restful api").WriteToLog()
  103. }
  104. }()
  105. return nil
  106. }