168 lines
4.0 KiB
Go
168 lines
4.0 KiB
Go
// Filename: internal/domain/upstream/handler.go
|
|
package upstream
|
|
|
|
import (
|
|
"gemini-balancer/internal/errors"
|
|
"gemini-balancer/internal/models"
|
|
"gemini-balancer/internal/response"
|
|
"net/url"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type Handler struct {
|
|
service *Service
|
|
}
|
|
|
|
func NewHandler(service *Service) *Handler {
|
|
return &Handler{service: service}
|
|
}
|
|
|
|
// ------ DTOs and Validation ------
|
|
type CreateUpstreamRequest struct {
|
|
URL string `json:"url" binding:"required"`
|
|
Weight int `json:"weight" binding:"omitempty,gte=1,lte=1000"`
|
|
Status string `json:"status" binding:"omitempty,oneof=active inactive"`
|
|
Description string `json:"description"`
|
|
}
|
|
type UpdateUpstreamRequest struct {
|
|
URL *string `json:"url"`
|
|
Weight *int `json:"weight" binding:"omitempty,gte=1,lte=1000"`
|
|
Status *string `json:"status" binding:"omitempty,oneof=active inactive"`
|
|
Description *string `json:"description"`
|
|
}
|
|
|
|
func isValidURL(rawURL string) bool {
|
|
u, err := url.ParseRequestURI(rawURL)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return u.Scheme == "http" || u.Scheme == "https"
|
|
}
|
|
|
|
// --- Handler ---
|
|
|
|
func (h *Handler) CreateUpstream(c *gin.Context) {
|
|
var req CreateUpstreamRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, errors.NewAPIError(errors.ErrInvalidJSON, err.Error()))
|
|
return
|
|
}
|
|
if !isValidURL(req.URL) {
|
|
response.Error(c, errors.NewAPIError(errors.ErrValidation, "Invalid URL format"))
|
|
return
|
|
}
|
|
|
|
upstream := models.UpstreamEndpoint{
|
|
URL: req.URL,
|
|
Weight: req.Weight,
|
|
Status: req.Status,
|
|
Description: req.Description,
|
|
}
|
|
|
|
if err := h.service.Create(&upstream); err != nil {
|
|
response.Error(c, errors.ParseDBError(err))
|
|
return
|
|
}
|
|
response.Created(c, upstream)
|
|
}
|
|
|
|
func (h *Handler) ListUpstreams(c *gin.Context) {
|
|
upstreams, err := h.service.List()
|
|
if err != nil {
|
|
response.Error(c, errors.ParseDBError(err))
|
|
return
|
|
}
|
|
response.Success(c, upstreams)
|
|
}
|
|
|
|
func (h *Handler) GetUpstream(c *gin.Context) {
|
|
id, err := strconv.Atoi(c.Param("id"))
|
|
if err != nil {
|
|
response.Error(c, errors.NewAPIError(errors.ErrBadRequest, "Invalid ID format"))
|
|
return
|
|
}
|
|
|
|
upstream, err := h.service.GetByID(id)
|
|
if err != nil {
|
|
response.Error(c, errors.ParseDBError(err))
|
|
return
|
|
}
|
|
response.Success(c, upstream)
|
|
}
|
|
|
|
func (h *Handler) UpdateUpstream(c *gin.Context) {
|
|
id, err := strconv.Atoi(c.Param("id"))
|
|
if err != nil {
|
|
response.Error(c, errors.NewAPIError(errors.ErrBadRequest, "Invalid ID format"))
|
|
return
|
|
}
|
|
var req UpdateUpstreamRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, errors.NewAPIError(errors.ErrInvalidJSON, err.Error()))
|
|
return
|
|
}
|
|
|
|
upstream, err := h.service.GetByID(id)
|
|
if err != nil {
|
|
response.Error(c, errors.ParseDBError(err))
|
|
return
|
|
}
|
|
|
|
if req.URL != nil {
|
|
if !isValidURL(*req.URL) {
|
|
response.Error(c, errors.NewAPIError(errors.ErrValidation, "Invalid URL format"))
|
|
return
|
|
}
|
|
upstream.URL = *req.URL
|
|
}
|
|
if req.Weight != nil {
|
|
upstream.Weight = *req.Weight
|
|
}
|
|
if req.Status != nil {
|
|
upstream.Status = *req.Status
|
|
}
|
|
if req.Description != nil {
|
|
upstream.Description = *req.Description
|
|
}
|
|
|
|
if err := h.service.Update(upstream); err != nil {
|
|
response.Error(c, errors.ParseDBError(err))
|
|
return
|
|
}
|
|
response.Success(c, upstream)
|
|
}
|
|
|
|
func (h *Handler) DeleteUpstream(c *gin.Context) {
|
|
id, err := strconv.Atoi(c.Param("id"))
|
|
if err != nil {
|
|
response.Error(c, errors.NewAPIError(errors.ErrBadRequest, "Invalid ID format"))
|
|
return
|
|
}
|
|
|
|
rowsAffected, err := h.service.Delete(id)
|
|
if err != nil {
|
|
response.Error(c, errors.ParseDBError(err))
|
|
return
|
|
}
|
|
if rowsAffected == 0 {
|
|
response.Error(c, errors.ErrResourceNotFound)
|
|
return
|
|
}
|
|
response.NoContent(c)
|
|
}
|
|
|
|
// RegisterRoutes
|
|
|
|
func (h *Handler) RegisterRoutes(rg *gin.RouterGroup) {
|
|
upstreamRoutes := rg.Group("/upstreams")
|
|
{
|
|
upstreamRoutes.POST("/", h.CreateUpstream)
|
|
upstreamRoutes.GET("/", h.ListUpstreams)
|
|
upstreamRoutes.GET("/:id", h.GetUpstream)
|
|
upstreamRoutes.PUT("/:id", h.UpdateUpstream)
|
|
upstreamRoutes.DELETE("/:id", h.DeleteUpstream)
|
|
}
|
|
}
|