bouncer/internal/admin/proxy.go

235 lines
5.4 KiB
Go

package admin
import (
"net/http"
"net/url"
"strconv"
"strings"
"forge.cadoles.com/cadoles/bouncer/internal/store"
"github.com/go-chi/chi/v5"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/api"
"gitlab.com/wpetit/goweb/logger"
)
type QueryProxyResponse struct {
Proxies []*store.ProxyHeader `json:"proxies"`
}
func (s *Server) queryProxy(w http.ResponseWriter, r *http.Request) {
limit, ok := getIntQueryParam(w, r, "limit", 10)
if !ok {
return
}
offset, ok := getIntQueryParam(w, r, "offset", 0)
if !ok {
return
}
options := []store.QueryProxyOptionFunc{
store.WithProxyQueryLimit(int(limit)),
store.WithProxyQueryOffset(int(offset)),
}
ids, ok := getStringableSliceValues[store.ProxyID](w, r, "ids", nil)
if !ok {
return
}
if ids != nil {
options = append(options, store.WithProxyQueryIDs(ids...))
}
ctx := r.Context()
proxies, err := s.proxyRepository.QueryProxy(
ctx,
options...,
)
if err != nil {
logger.Error(ctx, "could not list proxies", logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return
}
api.DataResponse(w, http.StatusOK, QueryProxyResponse{
Proxies: proxies,
})
}
type GetProxyResponse struct {
Proxy *store.Proxy `json:"proxy"`
}
func (s *Server) getProxy(w http.ResponseWriter, r *http.Request) {
proxyID, ok := getProxyID(w, r)
if !ok {
return
}
ctx := r.Context()
proxy, err := s.proxyRepository.GetProxy(ctx, proxyID)
if err != nil {
if errors.Is(err, store.ErrNotFound) {
api.ErrorResponse(w, http.StatusNotFound, api.ErrCodeNotFound, nil)
return
}
logger.Error(ctx, "could not get proxy", logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return
}
api.DataResponse(w, http.StatusOK, GetProxyResponse{
Proxy: proxy,
})
}
type DeleteProxyResponse struct {
ProxyID store.ProxyID `json:"proxyId"`
}
func (s *Server) deleteProxy(w http.ResponseWriter, r *http.Request) {
proxyID, ok := getProxyID(w, r)
if !ok {
return
}
ctx := r.Context()
if err := s.proxyRepository.DeleteProxy(ctx, proxyID); err != nil {
if errors.Is(err, store.ErrNotFound) {
api.ErrorResponse(w, http.StatusNotFound, api.ErrCodeNotFound, nil)
return
}
logger.Error(ctx, "could not delete proxy", logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return
}
api.DataResponse(w, http.StatusOK, DeleteProxyResponse{
ProxyID: proxyID,
})
}
type CreateProxyRequest struct {
To string `json:"to" validate:"required"`
From []string `json:"from" validate:"required"`
}
type CreateProxyResponse struct {
Proxy *store.Proxy `json:"proxy"`
}
func (s *Server) createProxy(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
createProxyReq := &CreateProxyRequest{}
if ok := api.Bind(w, r, createProxyReq); !ok {
return
}
to, err := url.Parse(createProxyReq.To)
if err != nil {
logger.Error(r.Context(), "could not parse to parameter", logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return
}
proxy, err := s.proxyRepository.CreateProxy(ctx, to, createProxyReq.From...)
if err != nil {
logger.Error(ctx, "could not update agent", logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return
}
api.DataResponse(w, http.StatusOK, struct {
Proxy *store.Proxy `json:"proxy"`
}{
Proxy: proxy,
})
}
type UpdateProxyRequest struct{}
func (s *Server) updateProxy(w http.ResponseWriter, r *http.Request) {
}
func getProxyID(w http.ResponseWriter, r *http.Request) (store.ProxyID, bool) {
rawProxyID := chi.URLParam(r, "proxyID")
proxyID, err := store.ParseProxyID(rawProxyID)
if err != nil {
logger.Error(r.Context(), "could not parse proxy id", logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return "", false
}
return proxyID, true
}
func getIntQueryParam(w http.ResponseWriter, r *http.Request, param string, defaultValue int64) (int64, bool) {
rawValue := r.URL.Query().Get(param)
if rawValue != "" {
value, err := strconv.ParseInt(rawValue, 10, 64)
if err != nil {
logger.Error(r.Context(), "could not parse int param", logger.F("param", param), logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return 0, false
}
return value, true
}
return defaultValue, true
}
func getStringSliceValues(w http.ResponseWriter, r *http.Request, param string, defaultValue []string) ([]string, bool) {
rawValue := r.URL.Query().Get(param)
if rawValue != "" {
values := strings.Split(rawValue, ",")
return values, true
}
return defaultValue, true
}
func getStringableSliceValues[T ~string](w http.ResponseWriter, r *http.Request, param string, defaultValue []T) ([]T, bool) {
rawValue := r.URL.Query().Get(param)
if rawValue != "" {
rawValues := strings.Split(rawValue, ",")
ids := make([]T, 0, len(rawValues))
for _, rv := range rawValues {
id, err := store.ParseID[T](rv)
if err != nil {
logger.Error(r.Context(), "could not parse ids slice param", logger.F("param", param), logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return nil, false
}
ids = append(ids, id)
}
return ids, true
}
return defaultValue, true
}