restful-api.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. }
  61. auth = strings.TrimPrefix(auth, prefix)
  62. if auth != r.config.AuthToken { // tip: Bearer: token123
  63. c.JSON(http.StatusUnauthorized, "unauthorized")
  64. c.Abort()
  65. return
  66. }
  67. c.Next()
  68. }
  69. }
  70. func (r *restfulService) start() error {
  71. r.Engine = gin.New()
  72. r.GET("/ping", func(c *gin.Context) {
  73. c.JSON(200, gin.H{
  74. "message": "pong",
  75. })
  76. })
  77. v1 := r.Group("/v1")
  78. v1.Use(r.TokenAuthMiddleware())
  79. {
  80. v1.GET("/stats/user", r.statsUser)
  81. v1.GET("/stats", r.statsRequest)
  82. v1.POST("/logger/reboot", r.loggerReboot)
  83. }
  84. var listener net.Listener
  85. var err error
  86. address := net.ParseAddress(r.config.ListenAddr)
  87. switch {
  88. case address.Family().IsIP():
  89. listener, err = internet.ListenSystem(r.ctx, &net.TCPAddr{IP: address.IP(), Port: int(r.config.ListenPort)}, nil)
  90. case strings.EqualFold(address.Domain(), "localhost"):
  91. listener, err = internet.ListenSystem(r.ctx, &net.TCPAddr{IP: net.IP{127, 0, 0, 1}, Port: int(r.config.ListenPort)}, nil)
  92. default:
  93. return newError("restful api cannot listen on the address: ", address)
  94. }
  95. if err != nil {
  96. return newError("restful api cannot listen on the port ", r.config.ListenPort).Base(err)
  97. }
  98. r.listener = listener
  99. go func() {
  100. if err := r.RunListener(listener); err != nil {
  101. newError("unable to serve restful api").WriteToLog()
  102. }
  103. }()
  104. return nil
  105. }