v2ray-core/app/restful-api/restful-api.go

122 lines
2.7 KiB
Go
Raw Normal View History

2021-09-05 21:28:30 +08:00
package restful_api
import (
2021-09-08 01:23:08 +08:00
"encoding/json"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-playground/validator/v10"
"net"
2021-09-05 21:28:30 +08:00
"net/http"
2021-09-06 13:11:30 +01:00
"strings"
2021-09-05 21:28:30 +08:00
)
2021-09-08 01:23:08 +08:00
func JSONResponse(w http.ResponseWriter, data interface{}, code int) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(code)
_ = json.NewEncoder(w).Encode(data)
}
var validate *validator.Validate
2021-09-05 21:28:30 +08:00
type StatsUser struct {
2021-09-08 01:23:08 +08:00
uuid string `validate:"required_without=email,uuid4"`
email string `validate:"required_without=uuid,email"`
2021-09-05 21:28:30 +08:00
}
2021-09-08 01:23:08 +08:00
type StatsUserResponse struct {
Uplink int64 `json:"uplink"`
Downlink int64 `json:"downlink"`
}
func (rs *restfulService) statsUser(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
statsUser := &StatsUser{
uuid: query.Get("uuid"),
email: query.Get("email"),
2021-09-05 21:28:30 +08:00
}
2021-09-08 01:23:08 +08:00
if err := validate.Struct(statsUser); err != nil {
JSONResponse(w, http.StatusText(422), 422)
}
response := &StatsUserResponse{
Uplink: 0,
Downlink: 0,
}
JSONResponse(w, response, 200)
2021-09-05 21:28:30 +08:00
}
type Stats struct {
2021-09-08 01:23:08 +08:00
tag string `validate:"required,alpha,min=1,max=255"`
2021-09-05 21:28:30 +08:00
}
type StatsBound struct { // Better name?
Uplink int64 `json:"uplink"`
Downlink int64 `json:"downlink"`
}
type StatsResponse struct {
Inbound StatsBound `json:"inbound"`
Outbound StatsBound `json:"outbound"`
}
2021-09-08 01:23:08 +08:00
func (rs *restfulService) statsRequest(w http.ResponseWriter, r *http.Request) {
stats := &Stats{
tag: r.URL.Query().Get("tag"),
}
if err := validate.Struct(stats); err != nil {
JSONResponse(w, http.StatusText(422), 422)
2021-09-05 21:28:30 +08:00
}
response := StatsResponse{
Inbound: StatsBound{
Uplink: 1,
Downlink: 1,
},
Outbound: StatsBound{
Uplink: 1,
Downlink: 1,
}}
2021-09-08 01:23:08 +08:00
JSONResponse(w, response, 200)
2021-09-05 21:28:30 +08:00
}
2021-09-08 01:23:08 +08:00
func (rs *restfulService) TokenAuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
const prefix = "Bearer "
if !strings.HasPrefix(auth, prefix) {
2021-09-08 01:23:08 +08:00
JSONResponse(w, http.StatusText(403), 403)
2021-09-06 14:16:21 +01:00
return
}
auth = strings.TrimPrefix(auth, prefix)
2021-09-08 01:23:08 +08:00
if auth != rs.config.AuthToken {
JSONResponse(w, http.StatusText(403), 403)
2021-09-05 21:28:30 +08:00
return
}
2021-09-08 01:23:08 +08:00
next.ServeHTTP(w, r)
})
2021-09-05 21:28:30 +08:00
}
2021-09-08 01:23:08 +08:00
func (rs *restfulService) start() error {
r := chi.NewRouter()
r.Use(rs.TokenAuthMiddleware)
r.Use(middleware.Heartbeat("/ping"))
2021-09-06 13:11:30 +01:00
2021-09-08 01:23:08 +08:00
r.Route("/v1", func(r chi.Router) {
r.Get("/stats/user", rs.statsUser)
r.Get("/stats", rs.statsRequest)
2021-09-05 21:28:30 +08:00
})
2021-09-06 13:11:30 +01:00
go func() {
2021-09-08 01:23:08 +08:00
err := http.ListenAndServe(net.JoinHostPort(rs.config.ListenAddr, string(rs.config.ListenPort)), r)
if err != nil {
2021-09-06 13:11:30 +01:00
newError("unable to serve restful api").WriteToLog()
}
}()
2021-09-05 21:28:30 +08:00
return nil
}