fix error response for web APIs

This commit is contained in:
ginuerzh 2024-06-04 22:05:13 +08:00
parent 754b2fdeac
commit 118ee91c95
31 changed files with 730 additions and 249 deletions

View File

@ -169,6 +169,10 @@ func registerConfig(config *gin.RouterGroup) {
config.PUT("/observers/:observer", updateObserver)
config.DELETE("/observers/:observer", deleteObserver)
config.POST("/recorders", createRecorder)
config.PUT("/recorders/:recorder", updateRecorder)
config.DELETE("/recorders/:recorder", deleteRecorder)
config.POST("/sds", createSD)
config.PUT("/sds/:sd", updateSD)
config.DELETE("/sds/:sd", deleteSD)

View File

@ -144,7 +144,7 @@ func saveConfig(ctx *gin.Context) {
if err != nil {
writeError(ctx, &Error{
statusCode: http.StatusInternalServerError,
Code: 40005,
Code: ErrCodeSaveConfigFailed,
Msg: fmt.Sprintf("create file: %s", err.Error()),
})
return
@ -154,8 +154,8 @@ func saveConfig(ctx *gin.Context) {
if err := config.Global().Write(f, req.Format); err != nil {
writeError(ctx, &Error{
statusCode: http.StatusInternalServerError,
Code: 40006,
Msg: fmt.Sprintf("write: %s", err.Error()),
Code: ErrCodeSaveConfigFailed,
Msg: fmt.Sprintf("save config: %s", err.Error()),
})
return
}

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createAdmission(ctx *gin.Context) {
var req createAdmissionRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "admission name is required"))
return
}
if registry.AdmissionRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("admission %s already exists", name)))
return
}
v := parser.ParseAdmission(&req.Data)
if err := registry.AdmissionRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.AdmissionRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("admission %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateAdmission(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.AdmissionRegistry().IsRegistered(req.Admission) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Admission)
if !registry.AdmissionRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("admission %s not found", name)))
return
}
req.Data.Name = req.Admission
req.Data.Name = name
v := parser.ParseAdmission(&req.Data)
registry.AdmissionRegistry().Unregister(req.Admission)
registry.AdmissionRegistry().Unregister(name)
if err := registry.AdmissionRegistry().Register(req.Admission, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.AdmissionRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("admission %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Admissions {
if c.Admissions[i].Name == req.Admission {
if c.Admissions[i].Name == name {
c.Admissions[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteAdmission(ctx *gin.Context) {
var req deleteAdmissionRequest
ctx.ShouldBindUri(&req)
if !registry.AdmissionRegistry().IsRegistered(req.Admission) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Admission)
if !registry.AdmissionRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("admission %s not found", name)))
return
}
registry.AdmissionRegistry().Unregister(req.Admission)
registry.AdmissionRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
admissiones := c.Admissions
c.Admissions = nil
for _, s := range admissiones {
if s.Name == req.Admission {
if s.Name == name {
continue
}
c.Admissions = append(c.Admissions, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,14 +37,20 @@ func createAuther(ctx *gin.Context) {
var req createAutherRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "auther name is required"))
return
}
if registry.AutherRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("auther %s already exists", name)))
return
}
v := parser.ParseAuther(&req.Data)
if err := registry.AutherRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.AutherRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("auther %s already exists", name)))
return
}
@ -86,24 +94,26 @@ func updateAuther(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.AutherRegistry().IsRegistered(req.Auther) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Auther)
if !registry.AutherRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("auther %s not found", name)))
return
}
req.Data.Name = req.Auther
req.Data.Name = name
v := parser.ParseAuther(&req.Data)
registry.AutherRegistry().Unregister(req.Auther)
registry.AutherRegistry().Unregister(name)
if err := registry.AutherRegistry().Register(req.Auther, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.AutherRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("auther %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Authers {
if c.Authers[i].Name == req.Auther {
if c.Authers[i].Name == name {
c.Authers[i] = &req.Data
break
}
@ -143,17 +153,19 @@ func deleteAuther(ctx *gin.Context) {
var req deleteAutherRequest
ctx.ShouldBindUri(&req)
if !registry.AutherRegistry().IsRegistered(req.Auther) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Auther)
if !registry.AutherRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("auther %s not found", name)))
return
}
registry.AutherRegistry().Unregister(req.Auther)
registry.AutherRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
authers := c.Authers
c.Authers = nil
for _, s := range authers {
if s.Name == req.Auther {
if s.Name == name {
continue
}
c.Authers = append(c.Authers, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createBypass(ctx *gin.Context) {
var req createBypassRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "bypass name is required"))
return
}
if registry.BypassRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("bypass %s already exists", name)))
return
}
v := parser.ParseBypass(&req.Data)
if err := registry.BypassRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.BypassRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("bypass %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateBypass(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.BypassRegistry().IsRegistered(req.Bypass) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Bypass)
if !registry.BypassRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("bypass %s not found", name)))
return
}
req.Data.Name = req.Bypass
req.Data.Name = name
v := parser.ParseBypass(&req.Data)
registry.BypassRegistry().Unregister(req.Bypass)
registry.BypassRegistry().Unregister(name)
if err := registry.BypassRegistry().Register(req.Bypass, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.BypassRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("bypass %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Bypasses {
if c.Bypasses[i].Name == req.Bypass {
if c.Bypasses[i].Name == name {
c.Bypasses[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteBypass(ctx *gin.Context) {
var req deleteBypassRequest
ctx.ShouldBindUri(&req)
if !registry.BypassRegistry().IsRegistered(req.Bypass) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Bypass)
if !registry.BypassRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("bypass %s not found", name)))
return
}
registry.BypassRegistry().Unregister(req.Bypass)
registry.BypassRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
bypasses := c.Bypasses
c.Bypasses = nil
for _, s := range bypasses {
if s.Name == req.Bypass {
if s.Name == name {
continue
}
c.Bypasses = append(c.Bypasses, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/core/logger"
@ -36,19 +38,25 @@ func createChain(ctx *gin.Context) {
var req createChainRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "chain name is required"))
return
}
if registry.ChainRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("chain %s already exists", name)))
return
}
v, err := parser.ParseChain(&req.Data, logger.Default())
if err != nil {
writeError(ctx, ErrCreate)
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create chain %s failed: %s", name, err.Error())))
return
}
if err := registry.ChainRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.ChainRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("chain %s already exists", name)))
return
}
@ -93,29 +101,31 @@ func updateChain(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.ChainRegistry().IsRegistered(req.Chain) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Chain)
if !registry.ChainRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("chain %s not found", name)))
return
}
req.Data.Name = req.Chain
req.Data.Name = name
v, err := parser.ParseChain(&req.Data, logger.Default())
if err != nil {
writeError(ctx, ErrCreate)
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create chain %s failed: %s", name, err.Error())))
return
}
registry.ChainRegistry().Unregister(req.Chain)
registry.ChainRegistry().Unregister(name)
if err := registry.ChainRegistry().Register(req.Chain, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.ChainRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("chain %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Chains {
if c.Chains[i].Name == req.Chain {
if c.Chains[i].Name == name {
c.Chains[i] = &req.Data
break
}
@ -155,17 +165,19 @@ func deleteChain(ctx *gin.Context) {
var req deleteChainRequest
ctx.ShouldBindUri(&req)
if !registry.ChainRegistry().IsRegistered(req.Chain) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Chain)
if !registry.ChainRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("chain %s not found", name)))
return
}
registry.ChainRegistry().Unregister(req.Chain)
registry.ChainRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
chains := c.Chains
c.Chains = nil
for _, s := range chains {
if s.Name == req.Chain {
if s.Name == name {
continue
}
c.Chains = append(c.Chains, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,20 @@ func createConnLimiter(ctx *gin.Context) {
var req createConnLimiterRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
return
}
if registry.ConnLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
return
}
v := parser.ParseConnLimiter(&req.Data)
if err := registry.ConnLimiterRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.ConnLimiterRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create limmiter %s failed: %s", name, err.Error())))
return
}
@ -87,25 +94,27 @@ func updateConnLimiter(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.ConnLimiterRegistry().IsRegistered(req.Limiter) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Limiter)
if !registry.ConnLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
return
}
req.Data.Name = req.Limiter
req.Data.Name = name
v := parser.ParseConnLimiter(&req.Data)
registry.ConnLimiterRegistry().Unregister(req.Limiter)
registry.ConnLimiterRegistry().Unregister(name)
if err := registry.ConnLimiterRegistry().Register(req.Limiter, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.ConnLimiterRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.CLimiters {
if c.CLimiters[i].Name == req.Limiter {
if c.CLimiters[i].Name == name {
c.CLimiters[i] = &req.Data
break
}
@ -145,17 +154,19 @@ func deleteConnLimiter(ctx *gin.Context) {
var req deleteConnLimiterRequest
ctx.ShouldBindUri(&req)
if !registry.ConnLimiterRegistry().IsRegistered(req.Limiter) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Limiter)
if !registry.ConnLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
return
}
registry.ConnLimiterRegistry().Unregister(req.Limiter)
registry.ConnLimiterRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
limiteres := c.CLimiters
c.CLimiters = nil
for _, s := range limiteres {
if s.Name == req.Limiter {
if s.Name == name {
continue
}
c.CLimiters = append(c.CLimiters, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/core/logger"
@ -36,19 +38,25 @@ func createHop(ctx *gin.Context) {
var req createHopRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "hop name is required"))
return
}
if registry.HopRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hop %s already exists", name)))
return
}
v, err := parser.ParseHop(&req.Data, logger.Default())
if err != nil {
writeError(ctx, ErrCreate)
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create hop %s failed: %s", name, err.Error())))
return
}
if err := registry.HopRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.HopRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hop %s already exists", name)))
return
}
@ -93,29 +101,30 @@ func updateHop(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.HopRegistry().IsRegistered(req.Hop) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Hop)
if !registry.HopRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hop %s not found", name)))
return
}
req.Data.Name = req.Hop
req.Data.Name = name
v, err := parser.ParseHop(&req.Data, logger.Default())
if err != nil {
writeError(ctx, ErrCreate)
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create hop %s failed: %s", name, err.Error())))
return
}
registry.HopRegistry().Unregister(req.Hop)
registry.HopRegistry().Unregister(name)
if err := registry.HopRegistry().Register(req.Hop, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.HopRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hop %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Hops {
if c.Hops[i].Name == req.Hop {
if c.Hops[i].Name == name {
c.Hops[i] = &req.Data
break
}
@ -155,17 +164,19 @@ func deleteHop(ctx *gin.Context) {
var req deleteHopRequest
ctx.ShouldBindUri(&req)
if !registry.HopRegistry().IsRegistered(req.Hop) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Hop)
if !registry.HopRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hop %s not found", name)))
return
}
registry.HopRegistry().Unregister(req.Hop)
registry.HopRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
hops := c.Hops
c.Hops = nil
for _, s := range hops {
if s.Name == req.Hop {
if s.Name == name {
continue
}
c.Hops = append(c.Hops, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createHosts(ctx *gin.Context) {
var req createHostsRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "hosts name is required"))
return
}
if registry.HostsRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hosts %s already exists", name)))
return
}
v := parser.ParseHostMapper(&req.Data)
if err := registry.HostsRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.HostsRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hosts %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateHosts(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.HostsRegistry().IsRegistered(req.Hosts) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Hosts)
if !registry.HostsRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hosts %s not found", name)))
return
}
req.Data.Name = req.Hosts
req.Data.Name = name
v := parser.ParseHostMapper(&req.Data)
registry.HostsRegistry().Unregister(req.Hosts)
registry.HostsRegistry().Unregister(name)
if err := registry.HostsRegistry().Register(req.Hosts, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.HostsRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hosts %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Hosts {
if c.Hosts[i].Name == req.Hosts {
if c.Hosts[i].Name == name {
c.Hosts[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteHosts(ctx *gin.Context) {
var req deleteHostsRequest
ctx.ShouldBindUri(&req)
if !registry.HostsRegistry().IsRegistered(req.Hosts) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Hosts)
if !registry.HostsRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hosts %s not found", name)))
return
}
registry.HostsRegistry().Unregister(req.Hosts)
registry.HostsRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
hosts := c.Hosts
c.Hosts = nil
for _, s := range hosts {
if s.Name == req.Hosts {
if s.Name == name {
continue
}
c.Hosts = append(c.Hosts, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createIngress(ctx *gin.Context) {
var req createIngressRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "ingress name is required"))
return
}
if registry.IngressRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("ingress %s already exists", name)))
return
}
v := parser.ParseIngress(&req.Data)
if err := registry.IngressRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.IngressRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("ingress %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateIngress(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.IngressRegistry().IsRegistered(req.Ingress) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Ingress)
if !registry.IngressRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("ingress %s not found", name)))
return
}
req.Data.Name = req.Ingress
req.Data.Name = name
v := parser.ParseIngress(&req.Data)
registry.IngressRegistry().Unregister(req.Ingress)
registry.IngressRegistry().Unregister(name)
if err := registry.IngressRegistry().Register(req.Ingress, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.IngressRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("ingress %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Ingresses {
if c.Ingresses[i].Name == req.Ingress {
if c.Ingresses[i].Name == name {
c.Ingresses[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteIngress(ctx *gin.Context) {
var req deleteIngressRequest
ctx.ShouldBindUri(&req)
if !registry.IngressRegistry().IsRegistered(req.Ingress) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Ingress)
if !registry.IngressRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("ingress %s not found", name)))
return
}
registry.IngressRegistry().Unregister(req.Ingress)
registry.IngressRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
ingresses := c.Ingresses
c.Ingresses = nil
for _, s := range ingresses {
if s.Name == req.Ingress {
if s.Name == name {
continue
}
c.Ingresses = append(c.Ingresses, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createLimiter(ctx *gin.Context) {
var req createLimiterRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
return
}
if registry.TrafficLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
return
}
v := parser.ParseTrafficLimiter(&req.Data)
if err := registry.TrafficLimiterRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.TrafficLimiterRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateLimiter(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.TrafficLimiterRegistry().IsRegistered(req.Limiter) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Limiter)
if !registry.TrafficLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
return
}
req.Data.Name = req.Limiter
req.Data.Name = name
v := parser.ParseTrafficLimiter(&req.Data)
registry.TrafficLimiterRegistry().Unregister(req.Limiter)
registry.TrafficLimiterRegistry().Unregister(name)
if err := registry.TrafficLimiterRegistry().Register(req.Limiter, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.TrafficLimiterRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Limiters {
if c.Limiters[i].Name == req.Limiter {
if c.Limiters[i].Name == name {
c.Limiters[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteLimiter(ctx *gin.Context) {
var req deleteLimiterRequest
ctx.ShouldBindUri(&req)
if !registry.TrafficLimiterRegistry().IsRegistered(req.Limiter) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Limiter)
if !registry.TrafficLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
return
}
registry.TrafficLimiterRegistry().Unregister(req.Limiter)
registry.TrafficLimiterRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
limiteres := c.Limiters
c.Limiters = nil
for _, s := range limiteres {
if s.Name == req.Limiter {
if s.Name == name {
continue
}
c.Limiters = append(c.Limiters, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createObserver(ctx *gin.Context) {
var req createObserverRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "observer name is required"))
return
}
if registry.ObserverRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("observer %s already exists", name)))
return
}
v := parser.ParseObserver(&req.Data)
if err := registry.ObserverRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.ObserverRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("observer %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateObserver(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.ObserverRegistry().IsRegistered(req.Observer) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Observer)
if !registry.ObserverRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("observer %s not found", name)))
return
}
req.Data.Name = req.Observer
req.Data.Name = name
v := parser.ParseObserver(&req.Data)
registry.ObserverRegistry().Unregister(req.Observer)
registry.ObserverRegistry().Unregister(name)
if err := registry.ObserverRegistry().Register(req.Observer, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.ObserverRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("observer %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Observers {
if c.Observers[i].Name == req.Observer {
if c.Observers[i].Name == name {
c.Observers[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteObserver(ctx *gin.Context) {
var req deleteObserverRequest
ctx.ShouldBindUri(&req)
if !registry.ObserverRegistry().IsRegistered(req.Observer) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Observer)
if !registry.ObserverRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("observer %s not found", name)))
return
}
registry.ObserverRegistry().Unregister(req.Observer)
registry.ObserverRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
observers := c.Observers
c.Observers = nil
for _, s := range observers {
if s.Name == req.Observer {
if s.Name == name {
continue
}
c.Observers = append(c.Observers, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createRateLimiter(ctx *gin.Context) {
var req createRateLimiterRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
return
}
if registry.RateLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
return
}
v := parser.ParseRateLimiter(&req.Data)
if err := registry.RateLimiterRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.RateLimiterRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateRateLimiter(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.RateLimiterRegistry().IsRegistered(req.Limiter) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Limiter)
if !registry.RateLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
return
}
req.Data.Name = req.Limiter
req.Data.Name = name
v := parser.ParseRateLimiter(&req.Data)
registry.RateLimiterRegistry().Unregister(req.Limiter)
registry.RateLimiterRegistry().Unregister(name)
if err := registry.RateLimiterRegistry().Register(req.Limiter, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.RateLimiterRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.RLimiters {
if c.RLimiters[i].Name == req.Limiter {
if c.RLimiters[i].Name == name {
c.RLimiters[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteRateLimiter(ctx *gin.Context) {
var req deleteRateLimiterRequest
ctx.ShouldBindUri(&req)
if !registry.RateLimiterRegistry().IsRegistered(req.Limiter) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Limiter)
if !registry.RateLimiterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
return
}
registry.RateLimiterRegistry().Unregister(req.Limiter)
registry.RateLimiterRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
limiteres := c.RLimiters
c.RLimiters = nil
for _, s := range limiteres {
if s.Name == req.Limiter {
if s.Name == name {
continue
}
c.RLimiters = append(c.RLimiters, s)

180
api/config_recorder.go Normal file
View File

@ -0,0 +1,180 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
parser "github.com/go-gost/x/config/parsing/recorder"
"github.com/go-gost/x/registry"
)
// swagger:parameters createRecorderRequest
type createRecorderRequest struct {
// in: body
Data config.RecorderConfig `json:"data"`
}
// successful operation.
// swagger:response createRecorderResponse
type createRecorderResponse struct {
Data Response
}
func createRecorder(ctx *gin.Context) {
// swagger:route POST /config/recorders Recorder createRecorderRequest
//
// Create a new recorder, the name of the recorder must be unique in recorder list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createRecorderResponse
var req createRecorderRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "recorder name is required"))
return
}
if registry.RecorderRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("recorder %s already exists", name)))
return
}
v := parser.ParseRecorder(&req.Data)
if err := registry.RecorderRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("recorder %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
c.Recorders = append(c.Recorders, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateRecorderRequest
type updateRecorderRequest struct {
// in: path
// required: true
Recorder string `uri:"recorder" json:"recorder"`
// in: body
Data config.RecorderConfig `json:"data"`
}
// successful operation.
// swagger:response updateRecorderResponse
type updateRecorderResponse struct {
Data Response
}
func updateRecorder(ctx *gin.Context) {
// swagger:route PUT /config/recorders/{recorder} Recorder updateRecorderRequest
//
// Update recorder by name, the recorder must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateRecorderResponse
var req updateRecorderRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Recorder)
if !registry.RecorderRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("recorder %s not found", name)))
return
}
req.Data.Name = name
v := parser.ParseRecorder(&req.Data)
registry.RecorderRegistry().Unregister(name)
if err := registry.RecorderRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("recorder %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Recorders {
if c.Recorders[i].Name == name {
c.Recorders[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteRecorderRequest
type deleteRecorderRequest struct {
// in: path
// required: true
Recorder string `uri:"recorder" json:"recorder"`
}
// successful operation.
// swagger:response deleteRecorderResponse
type deleteRecorderResponse struct {
Data Response
}
func deleteRecorder(ctx *gin.Context) {
// swagger:route DELETE /config/recorders/{recorder} Recorder deleteRecorderRequest
//
// Delete recorder by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteRecorderResponse
var req deleteRecorderRequest
ctx.ShouldBindUri(&req)
name := strings.TrimSpace(req.Recorder)
if !registry.RecorderRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("recorder %s not found", name)))
return
}
registry.RecorderRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
recorders := c.Recorders
c.Recorders = nil
for _, s := range recorders {
if s.Name == name {
continue
}
c.Recorders = append(c.Recorders, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,19 +37,25 @@ func createResolver(ctx *gin.Context) {
var req createResolverRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "resolver name is required"))
return
}
if registry.ResolverRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("resolver %s already exists", name)))
return
}
v, err := parser.ParseResolver(&req.Data)
if err != nil {
writeError(ctx, ErrCreate)
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create resolver %s failed: %s", name, err.Error())))
return
}
if err := registry.ResolverRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.ResolverRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("resolver %s already exists", name)))
return
}
@ -91,29 +99,31 @@ func updateResolver(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.ResolverRegistry().IsRegistered(req.Resolver) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Resolver)
if !registry.ResolverRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("resolver %s not found", name)))
return
}
req.Data.Name = req.Resolver
req.Data.Name = name
v, err := parser.ParseResolver(&req.Data)
if err != nil {
writeError(ctx, ErrCreate)
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create resolver %s failed: %s", name, err.Error())))
return
}
registry.ResolverRegistry().Unregister(req.Resolver)
registry.ResolverRegistry().Unregister(name)
if err := registry.ResolverRegistry().Register(req.Resolver, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.ResolverRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("resolver %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Resolvers {
if c.Resolvers[i].Name == req.Resolver {
if c.Resolvers[i].Name == name {
c.Resolvers[i] = &req.Data
break
}
@ -153,17 +163,19 @@ func deleteResolver(ctx *gin.Context) {
var req deleteResolverRequest
ctx.ShouldBindUri(&req)
if !registry.ResolverRegistry().IsRegistered(req.Resolver) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Resolver)
if !registry.ResolverRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("resolver %s not found", name)))
return
}
registry.ResolverRegistry().Unregister(req.Resolver)
registry.ResolverRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
resolvers := c.Resolvers
c.Resolvers = nil
for _, s := range resolvers {
if s.Name == req.Resolver {
if s.Name == name {
continue
}
c.Resolvers = append(c.Resolvers, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createRouter(ctx *gin.Context) {
var req createRouterRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "router name is required"))
return
}
if registry.RouterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("router %s already exists", name)))
return
}
v := parser.ParseRouter(&req.Data)
if err := registry.RouterRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.RouterRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("router %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateRouter(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.RouterRegistry().IsRegistered(req.Router) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Router)
if !registry.RouterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("router %s not found", name)))
return
}
req.Data.Name = req.Router
req.Data.Name = name
v := parser.ParseRouter(&req.Data)
registry.RouterRegistry().Unregister(req.Router)
registry.RouterRegistry().Unregister(name)
if err := registry.RouterRegistry().Register(req.Router, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.RouterRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("router %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.Routers {
if c.Routers[i].Name == req.Router {
if c.Routers[i].Name == name {
c.Routers[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteRouter(ctx *gin.Context) {
var req deleteRouterRequest
ctx.ShouldBindUri(&req)
if !registry.RouterRegistry().IsRegistered(req.Router) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.Router)
if !registry.RouterRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("router %s not found", name)))
return
}
registry.RouterRegistry().Unregister(req.Router)
registry.RouterRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
routeres := c.Routers
c.Routers = nil
for _, s := range routeres {
if s.Name == req.Router {
if s.Name == name {
continue
}
c.Routers = append(c.Routers, s)

View File

@ -1,7 +1,9 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
@ -35,15 +37,21 @@ func createSD(ctx *gin.Context) {
var req createSDRequest
ctx.ShouldBindJSON(&req.Data)
if req.Data.Name == "" {
writeError(ctx, ErrInvalid)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "sd name is required"))
return
}
if registry.SDRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("sd %s already exists", name)))
return
}
v := parser.ParseSD(&req.Data)
if err := registry.SDRegistry().Register(req.Data.Name, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.SDRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("sd %s already exists", name)))
return
}
@ -87,25 +95,27 @@ func updateSD(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
if !registry.SDRegistry().IsRegistered(req.SD) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.SD)
if !registry.SDRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("sd %s not found", name)))
return
}
req.Data.Name = req.SD
req.Data.Name = name
v := parser.ParseSD(&req.Data)
registry.SDRegistry().Unregister(req.SD)
registry.SDRegistry().Unregister(name)
if err := registry.SDRegistry().Register(req.SD, v); err != nil {
writeError(ctx, ErrDup)
if err := registry.SDRegistry().Register(name, v); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("sd %s already exists", name)))
return
}
config.OnUpdate(func(c *config.Config) error {
for i := range c.SDs {
if c.SDs[i].Name == req.SD {
if c.SDs[i].Name == name {
c.SDs[i] = &req.Data
break
}
@ -145,17 +155,19 @@ func deleteSD(ctx *gin.Context) {
var req deleteSDRequest
ctx.ShouldBindUri(&req)
if !registry.SDRegistry().IsRegistered(req.SD) {
writeError(ctx, ErrNotFound)
name := strings.TrimSpace(req.SD)
if !registry.SDRegistry().IsRegistered(name) {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("sd %s not found", name)))
return
}
registry.SDRegistry().Unregister(req.SD)
registry.SDRegistry().Unregister(name)
config.OnUpdate(func(c *config.Config) error {
sds := c.SDs
c.SDs = nil
for _, s := range sds {
if s.Name == req.SD {
if s.Name == name {
continue
}
c.SDs = append(c.SDs, s)

View File

@ -102,28 +102,28 @@ func updateService(ctx *gin.Context) {
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
service := strings.TrimSpace(req.Service)
name := strings.TrimSpace(req.Service)
old := registry.ServiceRegistry().Get(service)
old := registry.ServiceRegistry().Get(name)
if old == nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("service %s not found", service)))
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("service %s not found", name)))
return
}
old.Close()
req.Data.Name = service
req.Data.Name = name
svc, err := parser.ParseService(&req.Data)
if err != nil {
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create service %s failed: %s", service, err.Error())))
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create service %s failed: %s", name, err.Error())))
return
}
registry.ServiceRegistry().Unregister(req.Service)
registry.ServiceRegistry().Unregister(name)
if err := registry.ServiceRegistry().Register(req.Service, svc); err != nil {
if err := registry.ServiceRegistry().Register(name, svc); err != nil {
svc.Close()
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("service %s already exists", service)))
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("service %s already exists", name)))
return
}
@ -131,7 +131,7 @@ func updateService(ctx *gin.Context) {
config.OnUpdate(func(c *config.Config) error {
for i := range c.Services {
if c.Services[i].Name == req.Service {
if c.Services[i].Name == name {
c.Services[i] = &req.Data
break
}
@ -171,22 +171,22 @@ func deleteService(ctx *gin.Context) {
var req deleteServiceRequest
ctx.ShouldBindUri(&req)
service := strings.TrimSpace(req.Service)
name := strings.TrimSpace(req.Service)
svc := registry.ServiceRegistry().Get(service)
svc := registry.ServiceRegistry().Get(name)
if svc == nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("service %s not found", service)))
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("service %s not found", name)))
return
}
registry.ServiceRegistry().Unregister(service)
registry.ServiceRegistry().Unregister(name)
svc.Close()
config.OnUpdate(func(c *config.Config) error {
services := c.Services
c.Services = nil
for _, s := range services {
if s.Name == req.Service {
if s.Name == name {
continue
}
c.Services = append(c.Services, s)

View File

@ -37,7 +37,11 @@ func mwBasicAuth(auther auth.Authenticator) gin.HandlerFunc {
u, p, _ := c.Request.BasicAuth()
if _, ok := auther.Authenticate(c, u, p); !ok {
c.Writer.Header().Set("WWW-Authenticate", "Basic")
c.AbortWithStatus(http.StatusUnauthorized)
c.JSON(http.StatusUnauthorized, Response{
Code: http.StatusUnauthorized,
Msg: "Unauthorized",
})
c.Abort()
}
}
}

View File

@ -306,7 +306,10 @@ definitions:
type: string
type: array
x-go-name: Bypasses
filter:
$ref: '#/definitions/NodeFilterConfig'
host:
description: DEPRECATED by filter.host
type: string
x-go-name: Host
http:
@ -322,9 +325,11 @@ definitions:
type: string
x-go-name: Network
path:
description: DEPRECATED by filter.path
type: string
x-go-name: Path
protocol:
description: DEPRECATED by filter.protocol
type: string
x-go-name: Protocol
tls:
@ -333,7 +338,12 @@ definitions:
x-go-package: github.com/go-gost/x/config
ForwarderConfig:
properties:
hop:
description: the referenced hop name
type: string
x-go-name: Hop
name:
description: DEPRECATED by hop field
type: string
x-go-name: Name
nodes:
@ -705,8 +715,6 @@ definitions:
addr:
type: string
x-go-name: Addr
auth:
$ref: '#/definitions/AuthConfig'
bypass:
type: string
x-go-name: Bypass
@ -719,9 +727,8 @@ definitions:
$ref: '#/definitions/ConnectorConfig'
dialer:
$ref: '#/definitions/DialerConfig'
host:
type: string
x-go-name: Host
filter:
$ref: '#/definitions/NodeFilterConfig'
hosts:
type: string
x-go-name: Hosts
@ -740,12 +747,6 @@ definitions:
network:
type: string
x-go-name: Network
path:
type: string
x-go-name: Path
protocol:
type: string
x-go-name: Protocol
resolver:
type: string
x-go-name: Resolver
@ -755,6 +756,19 @@ definitions:
$ref: '#/definitions/TLSNodeConfig'
type: object
x-go-package: github.com/go-gost/x/config
NodeFilterConfig:
properties:
host:
type: string
x-go-name: Host
path:
type: string
x-go-name: Path
protocol:
type: string
x-go-name: Protocol
type: object
x-go-package: github.com/go-gost/x/config
ObserverConfig:
properties:
name:
@ -1762,6 +1776,64 @@ paths:
summary: Update observer by name, the observer must already exist.
tags:
- Observer
/config/recorders:
post:
operationId: createRecorderRequest
parameters:
- in: body
name: data
schema:
$ref: '#/definitions/RecorderConfig'
x-go-name: Data
responses:
"200":
$ref: '#/responses/createRecorderResponse'
security:
- basicAuth:
- '[]'
summary: Create a new recorder, the name of the recorder must be unique in recorder list.
tags:
- Recorder
/config/recorders/{recorder}:
delete:
operationId: deleteRecorderRequest
parameters:
- in: path
name: recorder
required: true
type: string
x-go-name: Recorder
responses:
"200":
$ref: '#/responses/deleteRecorderResponse'
security:
- basicAuth:
- '[]'
summary: Delete recorder by name.
tags:
- Recorder
put:
operationId: updateRecorderRequest
parameters:
- in: path
name: recorder
required: true
type: string
x-go-name: Recorder
- in: body
name: data
schema:
$ref: '#/definitions/RecorderConfig'
x-go-name: Data
responses:
"200":
$ref: '#/responses/updateRecorderResponse'
security:
- basicAuth:
- '[]'
summary: Update recorder by name, the recorder must already exist.
tags:
- Recorder
/config/resolvers:
post:
operationId: createResolverRequest
@ -2121,6 +2193,12 @@ responses:
Data: {}
schema:
$ref: '#/definitions/Response'
createRecorderResponse:
description: successful operation.
headers:
Data: {}
schema:
$ref: '#/definitions/Response'
createResolverResponse:
description: successful operation.
headers:
@ -2211,6 +2289,12 @@ responses:
Data: {}
schema:
$ref: '#/definitions/Response'
deleteRecorderResponse:
description: successful operation.
headers:
Data: {}
schema:
$ref: '#/definitions/Response'
deleteResolverResponse:
description: successful operation.
headers:
@ -2313,6 +2397,12 @@ responses:
Data: {}
schema:
$ref: '#/definitions/Response'
updateRecorderResponse:
description: successful operation.
headers:
Data: {}
schema:
$ref: '#/definitions/Response'
updateResolverResponse:
description: successful operation.
headers:

View File

@ -297,9 +297,9 @@ type RedisRecorder struct {
}
type RecorderObject struct {
Name string `json:"name"`
Record string `json:"record"`
Metadata map[string]any
Name string `json:"name"`
Record string `json:"record"`
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
}
type LimiterConfig struct {

View File

@ -94,6 +94,10 @@ func (p *grpcPlugin) Select(ctx context.Context, opts ...hop.SelectOption) *chai
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}

View File

@ -71,6 +71,10 @@ func (p *grpcPlugin) Lookup(ctx context.Context, network, host string, opts ...h
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}

View File

@ -82,6 +82,10 @@ func (p *grpcPlugin) SetRule(ctx context.Context, rule *ingress.Rule, opts ...in
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}

View File

@ -95,6 +95,10 @@ func (p *grpcPlugin) Out(ctx context.Context, key string, opts ...traffic.Option
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}

View File

@ -33,6 +33,7 @@ func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) observer.Obs
conn, err := plugin.NewGRPCConn(addr, &options)
if err != nil {
log.Error(err)
return nil
}
p := &grpcPlugin{

View File

@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/go-gost/core/logger"
"github.com/go-gost/core/observer"
@ -58,6 +59,9 @@ func NewHTTPPlugin(name string, url string, opts ...plugin.Option) observer.Obse
opt(&options)
}
if !strings.HasPrefix(url, "http") {
url = "http://" + url
}
return &httpPlugin{
url: url,
client: plugin.NewHTTPClient(&options),

View File

@ -69,6 +69,10 @@ func (p *grpcPlugin) Record(ctx context.Context, b []byte, opts ...recorder.Reco
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}

View File

@ -70,6 +70,10 @@ func (p *grpcPlugin) Resolve(ctx context.Context, network, host string, opts ...
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}

View File

@ -63,6 +63,10 @@ func (p *grpcPlugin) GetRoute(ctx context.Context, dst net.IP, opts ...router.Op
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}

View File

@ -127,6 +127,10 @@ func (p *grpcPlugin) Get(ctx context.Context, name string) ([]*sd.Service, error
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}