This commit is contained in:
qaq
2025-06-17 12:17:33 +08:00
parent 4a6b2c8e0f
commit 9fa968d07c
648 changed files with 64968 additions and 1621 deletions
+132
View File
@@ -0,0 +1,132 @@
package api
import (
"embed"
"net/http"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/go-gost/core/auth"
)
var (
//go:embed swagger.yaml
swaggerDoc embed.FS
)
type Response struct {
Code int `json:"code,omitempty"`
Msg string `json:"msg,omitempty"`
}
type Options struct {
AccessLog bool
PathPrefix string
Auther auth.Authenticator
}
func Register(r *gin.Engine, opts *Options) {
if opts == nil {
opts = &Options{}
}
r.Use(
cors.New((cors.Config{
AllowAllOrigins: true,
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"*"},
AllowPrivateNetwork: true,
})),
gin.Recovery(),
)
if opts.AccessLog {
r.Use(mwLogger())
}
router := r.Group("")
if opts.PathPrefix != "" {
router = router.Group(opts.PathPrefix)
}
router.StaticFS("/docs", http.FS(swaggerDoc))
config := router.Group("/config")
config.Use(mwBasicAuth(opts.Auther))
config.GET("", getConfig)
config.POST("", saveConfig)
config.POST("/reload", reloadConfig)
config.POST("/services", createService)
config.PUT("/services/:service", updateService)
config.DELETE("/services/:service", deleteService)
config.POST("/services/:service/pause", pauseService)
config.POST("/services/:service/resume", resumeService)
config.GET("/services/:service/status", getServiceStatus)
config.POST("/services/batch", createServices)
config.PUT("/services/batch", updateServices)
config.DELETE("/services/batch", deleteServices)
config.POST("/services/batch/pause", pauseServices)
config.POST("/services/batch/resume", resumeServices)
config.POST("/chains", createChain)
config.PUT("/chains/:chain", updateChain)
config.DELETE("/chains/:chain", deleteChain)
config.POST("/hops", createHop)
config.PUT("/hops/:hop", updateHop)
config.DELETE("/hops/:hop", deleteHop)
config.POST("/authers", createAuther)
config.PUT("/authers/:auther", updateAuther)
config.DELETE("/authers/:auther", deleteAuther)
config.POST("/admissions", createAdmission)
config.PUT("/admissions/:admission", updateAdmission)
config.DELETE("/admissions/:admission", deleteAdmission)
config.POST("/bypasses", createBypass)
config.PUT("/bypasses/:bypass", updateBypass)
config.DELETE("/bypasses/:bypass", deleteBypass)
config.POST("/resolvers", createResolver)
config.PUT("/resolvers/:resolver", updateResolver)
config.DELETE("/resolvers/:resolver", deleteResolver)
config.POST("/hosts", createHosts)
config.PUT("/hosts/:hosts", updateHosts)
config.DELETE("/hosts/:hosts", deleteHosts)
config.POST("/ingresses", createIngress)
config.PUT("/ingresses/:ingress", updateIngress)
config.DELETE("/ingresses/:ingress", deleteIngress)
config.POST("/routers", createRouter)
config.PUT("/routers/:router", updateRouter)
config.DELETE("/routers/:router", deleteRouter)
config.POST("/observers", createObserver)
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)
config.POST("/limiters", createLimiter)
config.PUT("/limiters/:limiter", updateLimiter)
config.DELETE("/limiters/:limiter", deleteLimiter)
config.POST("/climiters", createConnLimiter)
config.PUT("/climiters/:limiter", updateConnLimiter)
config.DELETE("/climiters/:limiter", deleteConnLimiter)
config.POST("/rlimiters", createRateLimiter)
config.PUT("/rlimiters/:limiter", updateRateLimiter)
config.DELETE("/rlimiters/:limiter", deleteRateLimiter)
}
+166
View File
@@ -0,0 +1,166 @@
package api
import (
"bytes"
"fmt"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/go-gost/core/observer/stats"
"github.com/go-gost/x/config"
"github.com/go-gost/x/registry"
"github.com/go-gost/x/service"
)
type serviceStatus interface {
Status() *service.Status
}
// swagger:parameters getConfigRequest
type getConfigRequest struct {
// output format, one of yaml|json, default is json.
// in: query
Format string `form:"format" json:"format"`
}
// successful operation.
// swagger:response getConfigResponse
type getConfigResponse struct {
Config *config.Config
}
func getConfig(ctx *gin.Context) {
// swagger:route GET /config Config getConfigRequest
//
// Get current config.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: getConfigResponse
var req getConfigRequest
ctx.ShouldBindQuery(&req)
config.OnUpdate(func(c *config.Config) error {
for _, svc := range c.Services {
if svc == nil {
continue
}
s := registry.ServiceRegistry().Get(svc.Name)
ss, ok := s.(serviceStatus)
if ok && ss != nil {
status := ss.Status()
svc.Status = &config.ServiceStatus{
CreateTime: status.CreateTime().Unix(),
State: string(status.State()),
}
if st := status.Stats(); st != nil {
svc.Status.Stats = &config.ServiceStats{
TotalConns: st.Get(stats.KindTotalConns),
CurrentConns: st.Get(stats.KindCurrentConns),
TotalErrs: st.Get(stats.KindTotalErrs),
InputBytes: st.Get(stats.KindInputBytes),
OutputBytes: st.Get(stats.KindOutputBytes),
}
}
for _, ev := range status.Events() {
if !ev.Time.IsZero() {
svc.Status.Events = append(svc.Status.Events, config.ServiceEvent{
Time: ev.Time.Unix(),
Msg: ev.Message,
})
}
}
}
}
return nil
})
var resp getConfigResponse
resp.Config = config.Global()
buf := &bytes.Buffer{}
switch req.Format {
case "yaml":
default:
req.Format = "json"
}
resp.Config.Write(buf, req.Format)
contentType := "application/json"
if req.Format == "yaml" {
contentType = "text/x-yaml"
}
ctx.Data(http.StatusOK, contentType, buf.Bytes())
}
// swagger:parameters saveConfigRequest
type saveConfigRequest struct {
// output format, one of yaml|json, default is yaml.
// in: query
Format string `form:"format" json:"format"`
// file path, default is gost.yaml|gost.json in current working directory.
// in: query
Path string `form:"path" json:"path"`
}
// successful operation.
// swagger:response saveConfigResponse
type saveConfigResponse struct {
Data Response
}
func saveConfig(ctx *gin.Context) {
// swagger:route POST /config Config saveConfigRequest
//
// Save current config to file (gost.yaml or gost.json).
//
// Security:
// basicAuth: []
//
// Responses:
// 200: saveConfigResponse
var req saveConfigRequest
ctx.ShouldBindQuery(&req)
file := "gost.yaml"
switch req.Format {
case "json":
file = "gost.json"
default:
req.Format = "yaml"
}
if req.Path != "" {
file = req.Path
}
f, err := os.Create(file)
if err != nil {
writeError(ctx, &Error{
statusCode: http.StatusInternalServerError,
Code: ErrCodeSaveConfigFailed,
Msg: fmt.Sprintf("create file: %s", err.Error()),
})
return
}
defer f.Close()
if err := config.Global().Write(f, req.Format); err != nil {
writeError(ctx, &Error{
statusCode: http.StatusInternalServerError,
Code: ErrCodeSaveConfigFailed,
Msg: fmt.Sprintf("save config: %s", err.Error()),
})
return
}
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/admission"
"github.com/go-gost/x/registry"
)
// swagger:parameters createAdmissionRequest
type createAdmissionRequest struct {
// in: body
Data config.AdmissionConfig `json:"data"`
}
// successful operation.
// swagger:response createAdmissionResponse
type createAdmissionResponse struct {
Data Response
}
func createAdmission(ctx *gin.Context) {
// swagger:route POST /config/admissions Admission createAdmissionRequest
//
// Create a new admission, the name of admission must be unique in admission list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createAdmissionResponse
var req createAdmissionRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "admission name is required"))
return
}
req.Data.Name = name
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(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 {
c.Admissions = append(c.Admissions, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateAdmissionRequest
type updateAdmissionRequest struct {
// in: path
// required: true
Admission string `uri:"admission" json:"admission"`
// in: body
Data config.AdmissionConfig `json:"data"`
}
// successful operation.
// swagger:response updateAdmissionResponse
type updateAdmissionResponse struct {
Data Response
}
func updateAdmission(ctx *gin.Context) {
// swagger:route PUT /config/admissions/{admission} Admission updateAdmissionRequest
//
// Update admission by name, the admission must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateAdmissionResponse
var req updateAdmissionRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseAdmission(&req.Data)
registry.AdmissionRegistry().Unregister(name)
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 == name {
c.Admissions[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteAdmissionRequest
type deleteAdmissionRequest struct {
// in: path
// required: true
Admission string `uri:"admission" json:"admission"`
}
// successful operation.
// swagger:response deleteAdmissionResponse
type deleteAdmissionResponse struct {
Data Response
}
func deleteAdmission(ctx *gin.Context) {
// swagger:route DELETE /config/admissions/{admission} Admission deleteAdmissionRequest
//
// Delete admission by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteAdmissionResponse
var req deleteAdmissionRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
admissiones := c.Admissions
c.Admissions = nil
for _, s := range admissiones {
if s.Name == name {
continue
}
c.Admissions = append(c.Admissions, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+180
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/auth"
"github.com/go-gost/x/registry"
)
// swagger:parameters createAutherRequest
type createAutherRequest struct {
// in: body
Data config.AutherConfig `json:"data"`
}
// successful operation.
// swagger:response createAutherResponse
type createAutherResponse struct {
Data Response
}
func createAuther(ctx *gin.Context) {
// swagger:route POST /config/authers Auther createAutherRequest
//
// Create a new auther, the name of the auther must be unique in auther list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createAutherResponse
var req createAutherRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "auther name is required"))
return
}
req.Data.Name = name
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(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 {
c.Authers = append(c.Authers, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateAutherRequest
type updateAutherRequest struct {
// in: path
// required: true
Auther string `uri:"auther" json:"auther"`
// in: body
Data config.AutherConfig `json:"data"`
}
// successful operation.
// swagger:response updateAutherResponse
type updateAutherResponse struct {
Data Response
}
func updateAuther(ctx *gin.Context) {
// swagger:route PUT /config/authers/{auther} Auther updateAutherRequest
//
// Update auther by name, the auther must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateAutherResponse
var req updateAutherRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseAuther(&req.Data)
registry.AutherRegistry().Unregister(name)
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 == name {
c.Authers[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteAutherRequest
type deleteAutherRequest struct {
// in: path
// required: true
Auther string `uri:"auther" json:"auther"`
}
// successful operation.
// swagger:response deleteAutherResponse
type deleteAutherResponse struct {
Data Response
}
func deleteAuther(ctx *gin.Context) {
// swagger:route DELETE /config/authers/{auther} Auther deleteAutherRequest
//
// Delete auther by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteAutherResponse
var req deleteAutherRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
authers := c.Authers
c.Authers = nil
for _, s := range authers {
if s.Name == name {
continue
}
c.Authers = append(c.Authers, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/bypass"
"github.com/go-gost/x/registry"
)
// swagger:parameters createBypassRequest
type createBypassRequest struct {
// in: body
Data config.BypassConfig `json:"data"`
}
// successful operation.
// swagger:response createBypassResponse
type createBypassResponse struct {
Data Response
}
func createBypass(ctx *gin.Context) {
// swagger:route POST /config/bypasses Bypass createBypassRequest
//
// Create a new bypass, the name of bypass must be unique in bypass list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createBypassResponse
var req createBypassRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "bypass name is required"))
return
}
req.Data.Name = name
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(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 {
c.Bypasses = append(c.Bypasses, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateBypassRequest
type updateBypassRequest struct {
// in: path
// required: true
Bypass string `uri:"bypass" json:"bypass"`
// in: body
Data config.BypassConfig `json:"data"`
}
// successful operation.
// swagger:response updateBypassResponse
type updateBypassResponse struct {
Data Response
}
func updateBypass(ctx *gin.Context) {
// swagger:route PUT /config/bypasses/{bypass} Bypass updateBypassRequest
//
// Update bypass by name, the bypass must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateBypassResponse
var req updateBypassRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseBypass(&req.Data)
registry.BypassRegistry().Unregister(name)
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 == name {
c.Bypasses[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteBypassRequest
type deleteBypassRequest struct {
// in: path
// required: true
Bypass string `uri:"bypass" json:"bypass"`
}
// successful operation.
// swagger:response deleteBypassResponse
type deleteBypassResponse struct {
Data Response
}
func deleteBypass(ctx *gin.Context) {
// swagger:route DELETE /config/bypasses/{bypass} Bypass deleteBypassRequest
//
// Delete bypass by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteBypassResponse
var req deleteBypassRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
bypasses := c.Bypasses
c.Bypasses = nil
for _, s := range bypasses {
if s.Name == name {
continue
}
c.Bypasses = append(c.Bypasses, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+192
View File
@@ -0,0 +1,192 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/core/logger"
"github.com/go-gost/x/config"
parser "github.com/go-gost/x/config/parsing/chain"
"github.com/go-gost/x/registry"
)
// swagger:parameters createChainRequest
type createChainRequest struct {
// in: body
Data config.ChainConfig `json:"data"`
}
// successful operation.
// swagger:response createChainResponse
type createChainResponse struct {
Data Response
}
func createChain(ctx *gin.Context) {
// swagger:route POST /config/chains Chain createChainRequest
//
// Create a new chain, the name of chain must be unique in chain list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createChainResponse
var req createChainRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "chain name is required"))
return
}
req.Data.Name = name
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, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create chain %s failed: %s", name, err.Error())))
return
}
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 {
c.Chains = append(c.Chains, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateChainRequest
type updateChainRequest struct {
// in: path
// required: true
// chain name
Chain string `uri:"chain" json:"chain"`
// in: body
Data config.ChainConfig `json:"data"`
}
// successful operation.
// swagger:response updateChainResponse
type updateChainResponse struct {
Data Response
}
func updateChain(ctx *gin.Context) {
// swagger:route PUT /config/chains/{chain} Chain updateChainRequest
//
// Update chain by name, the chain must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateChainResponse
var req updateChainRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v, err := parser.ParseChain(&req.Data, logger.Default())
if err != nil {
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create chain %s failed: %s", name, err.Error())))
return
}
registry.ChainRegistry().Unregister(name)
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 == name {
c.Chains[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteChainRequest
type deleteChainRequest struct {
// in: path
// required: true
Chain string `uri:"chain" json:"chain"`
}
// successful operation.
// swagger:response deleteChainResponse
type deleteChainResponse struct {
Data Response
}
func deleteChain(ctx *gin.Context) {
// swagger:route DELETE /config/chains/{chain} Chain deleteChainRequest
//
// Delete chain by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteChainResponse
var req deleteChainRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
chains := c.Chains
c.Chains = nil
for _, s := range chains {
if s.Name == name {
continue
}
c.Chains = append(c.Chains, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+181
View File
@@ -0,0 +1,181 @@
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/limiter"
"github.com/go-gost/x/registry"
)
// swagger:parameters createConnLimiterRequest
type createConnLimiterRequest struct {
// in: body
Data config.LimiterConfig `json:"data"`
}
// successful operation.
// swagger:response createConnLimiterResponse
type createConnLimiterResponse struct {
Data Response
}
func createConnLimiter(ctx *gin.Context) {
// swagger:route POST /config/climiters Limiter createConnLimiterRequest
//
// Create a new conn limiter, the name of limiter must be unique in limiter list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createConnLimiterResponse
var req createConnLimiterRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
return
}
req.Data.Name = name
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(name, v); err != nil {
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create limmiter %s failed: %s", name, err.Error())))
return
}
config.OnUpdate(func(c *config.Config) error {
c.CLimiters = append(c.CLimiters, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateConnLimiterRequest
type updateConnLimiterRequest struct {
// in: path
// required: true
Limiter string `uri:"limiter" json:"limiter"`
// in: body
Data config.LimiterConfig `json:"data"`
}
// successful operation.
// swagger:response updateConnLimiterResponse
type updateConnLimiterResponse struct {
Data Response
}
func updateConnLimiter(ctx *gin.Context) {
// swagger:route PUT /config/climiters/{limiter} Limiter updateConnLimiterRequest
//
// Update conn limiter by name, the limiter must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateConnLimiterResponse
var req updateConnLimiterRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseConnLimiter(&req.Data)
registry.ConnLimiterRegistry().Unregister(name)
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 == name {
c.CLimiters[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteConnLimiterRequest
type deleteConnLimiterRequest struct {
// in: path
// required: true
Limiter string `uri:"limiter" json:"limiter"`
}
// successful operation.
// swagger:response deleteConnLimiterResponse
type deleteConnLimiterResponse struct {
Data Response
}
func deleteConnLimiter(ctx *gin.Context) {
// swagger:route DELETE /config/climiters/{limiter} Limiter deleteConnLimiterRequest
//
// Delete conn limiter by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteConnLimiterResponse
var req deleteConnLimiterRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
limiteres := c.CLimiters
c.CLimiters = nil
for _, s := range limiteres {
if s.Name == name {
continue
}
c.CLimiters = append(c.CLimiters, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+191
View File
@@ -0,0 +1,191 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-gost/core/logger"
"github.com/go-gost/x/config"
parser "github.com/go-gost/x/config/parsing/hop"
"github.com/go-gost/x/registry"
)
// swagger:parameters createHopRequest
type createHopRequest struct {
// in: body
Data config.HopConfig `json:"data"`
}
// successful operation.
// swagger:response createHopResponse
type createHopResponse struct {
Data Response
}
func createHop(ctx *gin.Context) {
// swagger:route POST /config/hops Hop createHopRequest
//
// Create a new hop, the name of hop must be unique in hop list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createHopResponse
var req createHopRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "hop name is required"))
return
}
req.Data.Name = name
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, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create hop %s failed: %s", name, err.Error())))
return
}
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 {
c.Hops = append(c.Hops, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateHopRequest
type updateHopRequest struct {
// in: path
// required: true
// hop name
Hop string `uri:"hop" json:"hop"`
// in: body
Data config.HopConfig `json:"data"`
}
// successful operation.
// swagger:response updateHopResponse
type updateHopResponse struct {
Data Response
}
func updateHop(ctx *gin.Context) {
// swagger:route PUT /config/hops/{hop} Hop updateHopRequest
//
// Update hop by name, the hop must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateHopResponse
var req updateHopRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v, err := parser.ParseHop(&req.Data, logger.Default())
if err != nil {
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create hop %s failed: %s", name, err.Error())))
return
}
registry.HopRegistry().Unregister(name)
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 == name {
c.Hops[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteHopRequest
type deleteHopRequest struct {
// in: path
// required: true
Hop string `uri:"hop" json:"hop"`
}
// successful operation.
// swagger:response deleteHopResponse
type deleteHopResponse struct {
Data Response
}
func deleteHop(ctx *gin.Context) {
// swagger:route DELETE /config/hops/{hop} Hop deleteHopRequest
//
// Delete hop by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteHopResponse
var req deleteHopRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
hops := c.Hops
c.Hops = nil
for _, s := range hops {
if s.Name == name {
continue
}
c.Hops = append(c.Hops, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/hosts"
"github.com/go-gost/x/registry"
)
// swagger:parameters createHostsRequest
type createHostsRequest struct {
// in: body
Data config.HostsConfig `json:"data"`
}
// successful operation.
// swagger:response createHostsResponse
type createHostsesponse struct {
Data Response
}
func createHosts(ctx *gin.Context) {
// swagger:route POST /config/hosts Hosts createHostsRequest
//
// Create a new hosts, the name of the hosts must be unique in hosts list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createHostsResponse
var req createHostsRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "hosts name is required"))
return
}
req.Data.Name = name
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(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 {
c.Hosts = append(c.Hosts, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateHostsRequest
type updateHostsRequest struct {
// in: path
// required: true
Hosts string `uri:"hosts" json:"hosts"`
// in: body
Data config.HostsConfig `json:"data"`
}
// successful operation.
// swagger:response updateHostsResponse
type updateHostsResponse struct {
Data Response
}
func updateHosts(ctx *gin.Context) {
// swagger:route PUT /config/hosts/{hosts} Hosts updateHostsRequest
//
// Update hosts by name, the hosts must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateHostsResponse
var req updateHostsRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseHostMapper(&req.Data)
registry.HostsRegistry().Unregister(name)
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 == name {
c.Hosts[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteHostsRequest
type deleteHostsRequest struct {
// in: path
// required: true
Hosts string `uri:"hosts" json:"hosts"`
}
// successful operation.
// swagger:response deleteHostsResponse
type deleteHostsResponse struct {
Data Response
}
func deleteHosts(ctx *gin.Context) {
// swagger:route DELETE /config/hosts/{hosts} Hosts deleteHostsRequest
//
// Delete hosts by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteHostsResponse
var req deleteHostsRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
hosts := c.Hosts
c.Hosts = nil
for _, s := range hosts {
if s.Name == name {
continue
}
c.Hosts = append(c.Hosts, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/ingress"
"github.com/go-gost/x/registry"
)
// swagger:parameters createIngressRequest
type createIngressRequest struct {
// in: body
Data config.IngressConfig `json:"data"`
}
// successful operation.
// swagger:response createIngressResponse
type createIngressResponse struct {
Data Response
}
func createIngress(ctx *gin.Context) {
// swagger:route POST /config/ingresses Ingress createIngressRequest
//
// Create a new ingress, the name of the ingress must be unique in ingress list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createIngressResponse
var req createIngressRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "ingress name is required"))
return
}
req.Data.Name = name
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(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 {
c.Ingresses = append(c.Ingresses, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateIngressRequest
type updateIngressRequest struct {
// in: path
// required: true
Ingress string `uri:"ingress" json:"ingress"`
// in: body
Data config.IngressConfig `json:"data"`
}
// successful operation.
// swagger:response updateIngressResponse
type updateIngressResponse struct {
Data Response
}
func updateIngress(ctx *gin.Context) {
// swagger:route PUT /config/ingresses/{ingress} Ingress updateIngressRequest
//
// Update ingress by name, the ingress must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateIngressResponse
var req updateIngressRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseIngress(&req.Data)
registry.IngressRegistry().Unregister(name)
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 == name {
c.Ingresses[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteIngressRequest
type deleteIngressRequest struct {
// in: path
// required: true
Ingress string `uri:"ingress" json:"ingress"`
}
// successful operation.
// swagger:response deleteIngressResponse
type deleteIngressResponse struct {
Data Response
}
func deleteIngress(ctx *gin.Context) {
// swagger:route DELETE /config/ingresses/{ingress} Ingress deleteIngressRequest
//
// Delete ingress by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteIngressResponse
var req deleteIngressRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
ingresses := c.Ingresses
c.Ingresses = nil
for _, s := range ingresses {
if s.Name == name {
continue
}
c.Ingresses = append(c.Ingresses, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/limiter"
"github.com/go-gost/x/registry"
)
// swagger:parameters createLimiterRequest
type createLimiterRequest struct {
// in: body
Data config.LimiterConfig `json:"data"`
}
// successful operation.
// swagger:response createLimiterResponse
type createLimiterResponse struct {
Data Response
}
func createLimiter(ctx *gin.Context) {
// swagger:route POST /config/limiters Limiter createLimiterRequest
//
// Create a new limiter, the name of limiter must be unique in limiter list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createLimiterResponse
var req createLimiterRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
return
}
req.Data.Name = name
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(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 {
c.Limiters = append(c.Limiters, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateLimiterRequest
type updateLimiterRequest struct {
// in: path
// required: true
Limiter string `uri:"limiter" json:"limiter"`
// in: body
Data config.LimiterConfig `json:"data"`
}
// successful operation.
// swagger:response updateLimiterResponse
type updateLimiterResponse struct {
Data Response
}
func updateLimiter(ctx *gin.Context) {
// swagger:route PUT /config/limiters/{limiter} Limiter updateLimiterRequest
//
// Update limiter by name, the limiter must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateLimiterResponse
var req updateLimiterRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseTrafficLimiter(&req.Data)
registry.TrafficLimiterRegistry().Unregister(name)
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 == name {
c.Limiters[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteLimiterRequest
type deleteLimiterRequest struct {
// in: path
// required: true
Limiter string `uri:"limiter" json:"limiter"`
}
// successful operation.
// swagger:response deleteLimiterResponse
type deleteLimiterResponse struct {
Data Response
}
func deleteLimiter(ctx *gin.Context) {
// swagger:route DELETE /config/limiters/{limiter} Limiter deleteLimiterRequest
//
// Delete limiter by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteLimiterResponse
var req deleteLimiterRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
limiteres := c.Limiters
c.Limiters = nil
for _, s := range limiteres {
if s.Name == name {
continue
}
c.Limiters = append(c.Limiters, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/observer"
"github.com/go-gost/x/registry"
)
// swagger:parameters createObserverRequest
type createObserverRequest struct {
// in: body
Data config.ObserverConfig `json:"data"`
}
// successful operation.
// swagger:response createObserverResponse
type createObserverResponse struct {
Data Response
}
func createObserver(ctx *gin.Context) {
// swagger:route POST /config/observers Observer createObserverRequest
//
// Create a new observer, the name of the observer must be unique in observer list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createObserverResponse
var req createObserverRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "observer name is required"))
return
}
req.Data.Name = name
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(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 {
c.Observers = append(c.Observers, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateObserverRequest
type updateObserverRequest struct {
// in: path
// required: true
Observer string `uri:"observer" json:"observer"`
// in: body
Data config.ObserverConfig `json:"data"`
}
// successful operation.
// swagger:response updateObserverResponse
type updateObserverResponse struct {
Data Response
}
func updateObserver(ctx *gin.Context) {
// swagger:route PUT /config/observers/{observer} Observer updateObserverRequest
//
// Update observer by name, the observer must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateObserverResponse
var req updateObserverRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseObserver(&req.Data)
registry.ObserverRegistry().Unregister(name)
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 == name {
c.Observers[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteObserverRequest
type deleteObserverRequest struct {
// in: path
// required: true
Observer string `uri:"observer" json:"observer"`
}
// successful operation.
// swagger:response deleteObserverResponse
type deleteObserverResponse struct {
Data Response
}
func deleteObserver(ctx *gin.Context) {
// swagger:route DELETE /config/observers/{observer} Observer deleteObserverRequest
//
// Delete observer by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteObserverResponse
var req deleteObserverRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
observers := c.Observers
c.Observers = nil
for _, s := range observers {
if s.Name == name {
continue
}
c.Observers = append(c.Observers, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/limiter"
"github.com/go-gost/x/registry"
)
// swagger:parameters createRateLimiterRequest
type createRateLimiterRequest struct {
// in: body
Data config.LimiterConfig `json:"data"`
}
// successful operation.
// swagger:response createRateLimiterResponse
type createRateLimiterResponse struct {
Data Response
}
func createRateLimiter(ctx *gin.Context) {
// swagger:route POST /config/rlimiters Limiter createRateLimiterRequest
//
// Create a new rate limiter, the name of limiter must be unique in limiter list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createRateLimiterResponse
var req createRateLimiterRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
return
}
req.Data.Name = name
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(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 {
c.RLimiters = append(c.RLimiters, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateRateLimiterRequest
type updateRateLimiterRequest struct {
// in: path
// required: true
Limiter string `uri:"limiter" json:"limiter"`
// in: body
Data config.LimiterConfig `json:"data"`
}
// successful operation.
// swagger:response updateRateLimiterResponse
type updateRateLimiterResponse struct {
Data Response
}
func updateRateLimiter(ctx *gin.Context) {
// swagger:route PUT /config/rlimiters/{limiter} Limiter updateRateLimiterRequest
//
// Update rate limiter by name, the limiter must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateRateLimiterResponse
var req updateRateLimiterRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseRateLimiter(&req.Data)
registry.RateLimiterRegistry().Unregister(name)
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 == name {
c.RLimiters[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteRateLimiterRequest
type deleteRateLimiterRequest struct {
// in: path
// required: true
Limiter string `uri:"limiter" json:"limiter"`
}
// successful operation.
// swagger:response deleteRateLimiterResponse
type deleteRateLimiterResponse struct {
Data Response
}
func deleteRateLimiter(ctx *gin.Context) {
// swagger:route DELETE /config/rlimiters/{limiter} Limiter deleteRateLimiterRequest
//
// Delete rate limiter by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteRateLimiterResponse
var req deleteRateLimiterRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
limiteres := c.RLimiters
c.RLimiters = nil
for _, s := range limiteres {
if s.Name == name {
continue
}
c.RLimiters = append(c.RLimiters, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+181
View File
@@ -0,0 +1,181 @@
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
}
req.Data.Name = name
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",
})
}
+56
View File
@@ -0,0 +1,56 @@
package api
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/go-gost/x/config"
"github.com/go-gost/x/config/loader"
"github.com/go-gost/x/config/parsing/parser"
"github.com/go-gost/x/registry"
)
// swagger:parameters reloadConfigRequest
type reloadConfigRequest struct{}
// successful operation.
// swagger:response reloadConfigResponse
type reloadConfigResponse struct {
Data Response
}
func reloadConfig(ctx *gin.Context) {
// swagger:route POST /config/reload Reload reloadConfigRequest
//
// Hot reload config.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: reloadConfigResponse
cfg, err := parser.Parse()
if err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, err.Error()))
return
}
config.Set(cfg)
if err := loader.Load(cfg); err != nil {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, err.Error()))
return
}
for _, svc := range registry.ServiceRegistry().GetAll() {
svc := svc
go func() {
svc.Serve()
}()
}
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+190
View File
@@ -0,0 +1,190 @@
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/resolver"
"github.com/go-gost/x/registry"
)
// swagger:parameters createResolverRequest
type createResolverRequest struct {
// in: body
Data config.ResolverConfig `json:"data"`
}
// successful operation.
// swagger:response createResolverResponse
type createResolverResponse struct {
Data Response
}
func createResolver(ctx *gin.Context) {
// swagger:route POST /config/resolvers Resolver createResolverRequest
//
// Create a new resolver, the name of the resolver must be unique in resolver list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createResolverResponse
var req createResolverRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "resolver name is required"))
return
}
req.Data.Name = name
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, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create resolver %s failed: %s", name, err.Error())))
return
}
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 {
c.Resolvers = append(c.Resolvers, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateResolverRequest
type updateResolverRequest struct {
// in: path
// required: true
Resolver string `uri:"resolver" json:"resolver"`
// in: body
Data config.ResolverConfig `json:"data"`
}
// successful operation.
// swagger:response updateResolverResponse
type updateResolverResponse struct {
Data Response
}
func updateResolver(ctx *gin.Context) {
// swagger:route PUT /config/resolvers/{resolver} Resolver updateResolverRequest
//
// Update resolver by name, the resolver must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateResolverResponse
var req updateResolverRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v, err := parser.ParseResolver(&req.Data)
if err != nil {
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create resolver %s failed: %s", name, err.Error())))
return
}
registry.ResolverRegistry().Unregister(name)
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 == name {
c.Resolvers[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteResolverRequest
type deleteResolverRequest struct {
// in: path
// required: true
Resolver string `uri:"resolver" json:"resolver"`
}
// successful operation.
// swagger:response deleteResolverResponse
type deleteResolverResponse struct {
Data Response
}
func deleteResolver(ctx *gin.Context) {
// swagger:route DELETE /config/resolvers/{resolver} Resolver deleteResolverRequest
//
// Delete resolver by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteResolverResponse
var req deleteResolverRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
resolvers := c.Resolvers
c.Resolvers = nil
for _, s := range resolvers {
if s.Name == name {
continue
}
c.Resolvers = append(c.Resolvers, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/router"
"github.com/go-gost/x/registry"
)
// swagger:parameters createRouterRequest
type createRouterRequest struct {
// in: body
Data config.RouterConfig `json:"data"`
}
// successful operation.
// swagger:response createRouterResponse
type createRouterResponse struct {
Data Response
}
func createRouter(ctx *gin.Context) {
// swagger:route POST /config/routers Router createRouterRequest
//
// Create a new router, the name of the router must be unique in router list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createRouterResponse
var req createRouterRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "router name is required"))
return
}
req.Data.Name = name
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(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 {
c.Routers = append(c.Routers, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateRouterRequest
type updateRouterRequest struct {
// in: path
// required: true
Router string `uri:"router" json:"router"`
// in: body
Data config.RouterConfig `json:"data"`
}
// successful operation.
// swagger:response updateRouterResponse
type updateRouterResponse struct {
Data Response
}
func updateRouter(ctx *gin.Context) {
// swagger:route PUT /config/routers/{router} Router updateRouterRequest
//
// Update router by name, the router must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateRouterResponse
var req updateRouterRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseRouter(&req.Data)
registry.RouterRegistry().Unregister(name)
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 == name {
c.Routers[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteRouterRequest
type deleteRouterRequest struct {
// in: path
// required: true
Router string `uri:"router" json:"router"`
}
// successful operation.
// swagger:response deleteRouterResponse
type deleteRouterResponse struct {
Data Response
}
func deleteRouter(ctx *gin.Context) {
// swagger:route DELETE /config/routers/{router} Router deleteRouterRequest
//
// Delete router by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteRouterResponse
var req deleteRouterRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
routeres := c.Routers
c.Routers = nil
for _, s := range routeres {
if s.Name == name {
continue
}
c.Routers = append(c.Routers, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
+182
View File
@@ -0,0 +1,182 @@
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/sd"
"github.com/go-gost/x/registry"
)
// swagger:parameters createSDRequest
type createSDRequest struct {
// in: body
Data config.SDConfig `json:"data"`
}
// successful operation.
// swagger:response createSDResponse
type createSDResponse struct {
Data Response
}
func createSD(ctx *gin.Context) {
// swagger:route POST /config/sds SD createSDRequest
//
// Create a new SD, the name of the SD must be unique in SD list.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: createSDResponse
var req createSDRequest
ctx.ShouldBindJSON(&req.Data)
name := strings.TrimSpace(req.Data.Name)
if name == "" {
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "sd name is required"))
return
}
req.Data.Name = name
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(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 {
c.SDs = append(c.SDs, &req.Data)
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters updateSDRequest
type updateSDRequest struct {
// in: path
// required: true
SD string `uri:"sd" json:"sd"`
// in: body
Data config.SDConfig `json:"data"`
}
// successful operation.
// swagger:response updateSDResponse
type updateSDResponse struct {
Data Response
}
func updateSD(ctx *gin.Context) {
// swagger:route PUT /config/sds/{sd} SD updateSDRequest
//
// Update SD by name, the SD must already exist.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: updateSDResponse
var req updateSDRequest
ctx.ShouldBindUri(&req)
ctx.ShouldBindJSON(&req.Data)
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 = name
v := parser.ParseSD(&req.Data)
registry.SDRegistry().Unregister(name)
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 == name {
c.SDs[i] = &req.Data
break
}
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
// swagger:parameters deleteSDRequest
type deleteSDRequest struct {
// in: path
// required: true
SD string `uri:"sd" json:"sd"`
}
// successful operation.
// swagger:response deleteSDResponse
type deleteSDResponse struct {
Data Response
}
func deleteSD(ctx *gin.Context) {
// swagger:route DELETE /config/sds/{sd} SD deleteSDRequest
//
// Delete SD by name.
//
// Security:
// basicAuth: []
//
// Responses:
// 200: deleteSDResponse
var req deleteSDRequest
ctx.ShouldBindUri(&req)
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(name)
config.OnUpdate(func(c *config.Config) error {
sds := c.SDs
c.SDs = nil
for _, s := range sds {
if s.Name == name {
continue
}
c.SDs = append(c.SDs, s)
}
return nil
})
ctx.JSON(http.StatusOK, Response{
Msg: "OK",
})
}
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
// Documentation of Web API.
//
// Schemes: https, http
// BasePath: /
// Version: 1.0.0
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// SecurityDefinitions:
// basicAuth:
// type: basic
//
// swagger:meta
package api
+63
View File
@@ -0,0 +1,63 @@
package api
import (
"encoding/json"
"net/http"
"github.com/gin-gonic/gin"
)
var (
ErrInvalid = &Error{statusCode: http.StatusBadRequest, Code: 40001, Msg: "object invalid"}
ErrDup = &Error{statusCode: http.StatusBadRequest, Code: 40002, Msg: "object duplicated"}
ErrCreate = &Error{statusCode: http.StatusConflict, Code: 40003, Msg: "object creation failed"}
ErrNotFound = &Error{statusCode: http.StatusBadRequest, Code: 40004, Msg: "object not found"}
ErrSave = &Error{statusCode: http.StatusInternalServerError, Code: 40005, Msg: "save config failed"}
)
type ErrCode int
const (
ErrCodeInvalid = 40001
ErrCodeDup = 40002
ErrCodeFailed = 40003
ErrCodeNotFound = 40004
ErrCodeSaveConfigFailed = 40005
)
// Error is an api error.
type Error struct {
statusCode int
Code int `json:"code"`
Msg string `json:"msg"`
}
func NewError(status, code int, msg string) error {
return &Error{
statusCode: status,
Code: code,
Msg: msg,
}
}
func (e *Error) Error() string {
b, _ := json.Marshal(e)
return string(b)
}
func writeError(c *gin.Context, err error) {
// c.Set(HTTPResponseTag, err)
c.JSON(getStatusCode(err), err)
}
func getStatusCode(err error) int {
if err == nil {
return http.StatusOK
}
if e, ok := err.(*Error); ok {
if e.statusCode >= http.StatusOK && e.statusCode < 600 {
return e.statusCode
}
}
return http.StatusInternalServerError
}
+47
View File
@@ -0,0 +1,47 @@
package api
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/go-gost/core/auth"
"github.com/go-gost/core/logger"
)
func mwLogger() gin.HandlerFunc {
return func(ctx *gin.Context) {
// start time
startTime := time.Now()
// Processing request
ctx.Next()
duration := time.Since(startTime)
logger.Default().WithFields(map[string]any{
"kind": "api",
"method": ctx.Request.Method,
"uri": ctx.Request.RequestURI,
"code": ctx.Writer.Status(),
"client": ctx.ClientIP(),
"duration": duration,
}).Infof("| %3d | %13v | %15s | %-7s %s",
ctx.Writer.Status(), duration, ctx.ClientIP(), ctx.Request.Method, ctx.Request.RequestURI)
}
}
func mwBasicAuth(auther auth.Authenticator) gin.HandlerFunc {
return func(c *gin.Context) {
if auther == nil {
return
}
u, p, _ := c.Request.BasicAuth()
if _, ok := auther.Authenticate(c, u, p); !ok {
c.Writer.Header().Set("WWW-Authenticate", "Basic")
c.JSON(http.StatusUnauthorized, Response{
Code: http.StatusUnauthorized,
Msg: "Unauthorized",
})
c.Abort()
}
}
}
+96
View File
@@ -0,0 +1,96 @@
package service
import (
"net"
"net/http"
"github.com/gin-gonic/gin"
"github.com/go-gost/core/auth"
"github.com/go-gost/core/service"
"github.com/go-gost/x/api"
)
type options struct {
accessLog bool
pathPrefix string
auther auth.Authenticator
}
type Option func(*options)
func PathPrefixOption(pathPrefix string) Option {
return func(o *options) {
o.pathPrefix = pathPrefix
}
}
func AccessLogOption(enable bool) Option {
return func(o *options) {
o.accessLog = enable
}
}
func AutherOption(auther auth.Authenticator) Option {
return func(o *options) {
o.auther = auther
}
}
type server struct {
s *http.Server
ln net.Listener
cclose chan struct{}
}
func NewService(network, addr string, opts ...Option) (service.Service, error) {
if network == "" {
network = "tcp"
}
ln, err := net.Listen(network, addr)
if err != nil {
return nil, err
}
var options options
for _, opt := range opts {
opt(&options)
}
gin.SetMode(gin.ReleaseMode)
r := gin.New()
api.Register(r, &api.Options{
AccessLog: options.accessLog,
PathPrefix: options.pathPrefix,
Auther: options.auther,
})
return &server{
s: &http.Server{
Handler: r,
},
ln: ln,
cclose: make(chan struct{}),
}, nil
}
func (s *server) Serve() error {
return s.s.Serve(s.ln)
}
func (s *server) Addr() net.Addr {
return s.ln.Addr()
}
func (s *server) Close() error {
return s.s.Close()
}
func (s *server) IsClosed() bool {
select {
case <-s.cclose:
return true
default:
return false
}
}
File diff suppressed because it is too large Load Diff