add reload for web api
This commit is contained in:
+13
-83
@@ -2,13 +2,11 @@ package api
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/core/auth"
|
||||
"github.com/go-gost/core/service"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -21,55 +19,17 @@ type Response struct {
|
||||
Msg string `json:"msg,omitempty"`
|
||||
}
|
||||
|
||||
type options struct {
|
||||
accessLog bool
|
||||
pathPrefix string
|
||||
auther auth.Authenticator
|
||||
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
|
||||
func Register(r *gin.Engine, opts *Options) {
|
||||
if opts == nil {
|
||||
opts = &Options{}
|
||||
}
|
||||
|
||||
var options options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
r := gin.New()
|
||||
r.Use(
|
||||
cors.New((cors.Config{
|
||||
AllowAllOrigins: true,
|
||||
@@ -79,55 +39,25 @@ func NewService(network, addr string, opts ...Option) (service.Service, error) {
|
||||
})),
|
||||
gin.Recovery(),
|
||||
)
|
||||
if options.accessLog {
|
||||
if opts.AccessLog {
|
||||
r.Use(mwLogger())
|
||||
}
|
||||
|
||||
router := r.Group("")
|
||||
if options.pathPrefix != "" {
|
||||
router = router.Group(options.pathPrefix)
|
||||
if opts.PathPrefix != "" {
|
||||
router = router.Group(opts.PathPrefix)
|
||||
}
|
||||
|
||||
router.StaticFS("/docs", http.FS(swaggerDoc))
|
||||
|
||||
config := router.Group("/config")
|
||||
config.Use(mwBasicAuth(options.auther))
|
||||
registerConfig(config)
|
||||
config.Use(mwBasicAuth(opts.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
|
||||
}
|
||||
}
|
||||
|
||||
func registerConfig(config *gin.RouterGroup) {
|
||||
config.GET("", getConfig)
|
||||
config.POST("", saveConfig)
|
||||
|
||||
config.POST("/reload", reloadConfig)
|
||||
|
||||
config.POST("/services", createService)
|
||||
config.PUT("/services/:service", updateService)
|
||||
config.DELETE("/services/:service", deleteService)
|
||||
|
||||
@@ -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",
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+103
-8
@@ -41,7 +41,7 @@ definitions:
|
||||
reload:
|
||||
$ref: '#/definitions/Duration'
|
||||
reverse:
|
||||
description: DEPRECATED by whitelist since beta.4
|
||||
description: 'Deprecated: use whitelist instead'
|
||||
type: boolean
|
||||
x-go-name: Reverse
|
||||
whitelist:
|
||||
@@ -102,7 +102,7 @@ definitions:
|
||||
reload:
|
||||
$ref: '#/definitions/Duration'
|
||||
reverse:
|
||||
description: DEPRECATED by whitelist since beta.4
|
||||
description: 'Deprecated: use whitelist instead'
|
||||
type: boolean
|
||||
x-go-name: Reverse
|
||||
whitelist:
|
||||
@@ -309,11 +309,13 @@ definitions:
|
||||
filter:
|
||||
$ref: '#/definitions/NodeFilterConfig'
|
||||
host:
|
||||
description: DEPRECATED by filter.host
|
||||
description: 'Deprecated: use matcher instead'
|
||||
type: string
|
||||
x-go-name: Host
|
||||
http:
|
||||
$ref: '#/definitions/HTTPNodeConfig'
|
||||
matcher:
|
||||
$ref: '#/definitions/NodeMatcherConfig'
|
||||
metadata:
|
||||
additionalProperties: {}
|
||||
type: object
|
||||
@@ -325,11 +327,11 @@ definitions:
|
||||
type: string
|
||||
x-go-name: Network
|
||||
path:
|
||||
description: DEPRECATED by filter.path
|
||||
description: 'Deprecated: use matcher instead'
|
||||
type: string
|
||||
x-go-name: Path
|
||||
protocol:
|
||||
description: DEPRECATED by filter.protocol
|
||||
description: 'Deprecated: use matcher instead'
|
||||
type: string
|
||||
x-go-name: Protocol
|
||||
tls:
|
||||
@@ -343,7 +345,7 @@ definitions:
|
||||
type: string
|
||||
x-go-name: Hop
|
||||
name:
|
||||
description: DEPRECATED by hop field
|
||||
description: 'Deprecated: use hop instead'
|
||||
type: string
|
||||
x-go-name: Name
|
||||
nodes:
|
||||
@@ -355,6 +357,17 @@ definitions:
|
||||
$ref: '#/definitions/SelectorConfig'
|
||||
type: object
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
HTTPBodyRewriteConfig:
|
||||
properties:
|
||||
Match:
|
||||
type: string
|
||||
Replacement:
|
||||
type: string
|
||||
Type:
|
||||
description: filter by MIME types
|
||||
type: string
|
||||
type: object
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
HTTPLoader:
|
||||
properties:
|
||||
timeout:
|
||||
@@ -371,20 +384,52 @@ definitions:
|
||||
header:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: 'Deprecated: use requestHeader instead'
|
||||
type: object
|
||||
x-go-name: Header
|
||||
host:
|
||||
description: rewrite host header
|
||||
type: string
|
||||
x-go-name: Host
|
||||
requestHeader:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: additional request header
|
||||
type: object
|
||||
x-go-name: RequestHeader
|
||||
responseHeader:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: additional response header
|
||||
type: object
|
||||
x-go-name: ResponseHeader
|
||||
rewrite:
|
||||
description: 'Deprecated: use rewriteURL instead'
|
||||
items:
|
||||
$ref: '#/definitions/HTTPURLRewriteConfig'
|
||||
type: array
|
||||
x-go-name: Rewrite
|
||||
rewriteBody:
|
||||
description: rewrite response body
|
||||
items:
|
||||
$ref: '#/definitions/HTTPBodyRewriteConfig'
|
||||
type: array
|
||||
x-go-name: RewriteBody
|
||||
rewriteURL:
|
||||
description: rewrite URL
|
||||
items:
|
||||
$ref: '#/definitions/HTTPURLRewriteConfig'
|
||||
type: array
|
||||
x-go-name: RewriteURL
|
||||
type: object
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
HTTPRecorder:
|
||||
properties:
|
||||
header:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
x-go-name: Header
|
||||
timeout:
|
||||
$ref: '#/definitions/Duration'
|
||||
url:
|
||||
@@ -458,6 +503,10 @@ definitions:
|
||||
interface:
|
||||
type: string
|
||||
x-go-name: Interface
|
||||
metadata:
|
||||
additionalProperties: {}
|
||||
type: object
|
||||
x-go-name: Metadata
|
||||
name:
|
||||
type: string
|
||||
x-go-name: Name
|
||||
@@ -737,6 +786,8 @@ definitions:
|
||||
interface:
|
||||
type: string
|
||||
x-go-name: Interface
|
||||
matcher:
|
||||
$ref: '#/definitions/NodeMatcherConfig'
|
||||
metadata:
|
||||
additionalProperties: {}
|
||||
type: object
|
||||
@@ -744,6 +795,9 @@ definitions:
|
||||
name:
|
||||
type: string
|
||||
x-go-name: Name
|
||||
netns:
|
||||
type: string
|
||||
x-go-name: Netns
|
||||
network:
|
||||
type: string
|
||||
x-go-name: Network
|
||||
@@ -769,6 +823,17 @@ definitions:
|
||||
x-go-name: Protocol
|
||||
type: object
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
NodeMatcherConfig:
|
||||
properties:
|
||||
priority:
|
||||
format: int64
|
||||
type: integer
|
||||
x-go-name: Priority
|
||||
rule:
|
||||
type: string
|
||||
x-go-name: Rule
|
||||
type: object
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
ObserverConfig:
|
||||
properties:
|
||||
name:
|
||||
@@ -821,9 +886,10 @@ definitions:
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
RecorderObject:
|
||||
properties:
|
||||
Metadata:
|
||||
metadata:
|
||||
additionalProperties: {}
|
||||
type: object
|
||||
x-go-name: Metadata
|
||||
name:
|
||||
type: string
|
||||
x-go-name: Name
|
||||
@@ -850,6 +916,9 @@ definitions:
|
||||
type:
|
||||
type: string
|
||||
x-go-name: Type
|
||||
username:
|
||||
type: string
|
||||
x-go-name: Username
|
||||
type: object
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
RedisRecorder:
|
||||
@@ -870,6 +939,9 @@ definitions:
|
||||
type:
|
||||
type: string
|
||||
x-go-name: Type
|
||||
username:
|
||||
type: string
|
||||
x-go-name: Username
|
||||
type: object
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
ResolverConfig:
|
||||
@@ -983,7 +1055,7 @@ definitions:
|
||||
type: string
|
||||
x-go-name: Hosts
|
||||
interface:
|
||||
description: DEPRECATED by metadata.interface since beta.5
|
||||
description: 'Deprecated: use metadata.interface instead'
|
||||
type: string
|
||||
x-go-name: Interface
|
||||
limiter:
|
||||
@@ -1139,6 +1211,11 @@ definitions:
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
TLSOptions:
|
||||
properties:
|
||||
alpn:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
x-go-name: ALPN
|
||||
cipherSuites:
|
||||
items:
|
||||
type: string
|
||||
@@ -1834,6 +1911,18 @@ paths:
|
||||
summary: Update recorder by name, the recorder must already exist.
|
||||
tags:
|
||||
- Recorder
|
||||
/config/reload:
|
||||
post:
|
||||
operationId: reloadConfigRequest
|
||||
responses:
|
||||
"200":
|
||||
$ref: '#/responses/reloadConfigResponse'
|
||||
security:
|
||||
- basicAuth:
|
||||
- '[]'
|
||||
summary: Hot reload config.
|
||||
tags:
|
||||
- Reload
|
||||
/config/resolvers:
|
||||
post:
|
||||
operationId: createResolverRequest
|
||||
@@ -2325,6 +2414,12 @@ responses:
|
||||
Config: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Config'
|
||||
reloadConfigResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
saveConfigResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
|
||||
Reference in New Issue
Block a user