From 86c76add171c101efbcb445cbd71104382888424 Mon Sep 17 00:00:00 2001 From: coward Date: Fri, 22 Mar 2024 10:42:36 +0800 Subject: [PATCH] =?UTF-8?q?:new:=E6=96=B0=E5=A2=9E=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E6=9C=8D=E5=8A=A1=E7=AB=AF=E3=80=81=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E6=8E=A7=E5=88=B6=E6=9C=8D=E5=8A=A1=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- command/wireguard.go | 64 ++++++++++++++++++++---------------------- component/wireguard.go | 56 +++++++++++++++++++++++++++++++++++- config/config.go | 9 +++--- config/wireguard.go | 5 ++++ go.mod | 5 ++-- go.sum | 5 ++-- http/api/client.go | 7 +++++ http/api/server.go | 24 ++++++++++++++++ http/param/client.go | 6 ++++ route/server.go | 5 ++-- 10 files changed, 142 insertions(+), 44 deletions(-) create mode 100644 config/wireguard.go diff --git a/command/wireguard.go b/command/wireguard.go index 54db1b0..b8b81eb 100644 --- a/command/wireguard.go +++ b/command/wireguard.go @@ -8,62 +8,60 @@ import ( "wireguard-dashboard/repository" ) -// RestartWireguard -// @description: 重启wireguard服务端 -func RestartWireguard() { - configPath, err := repository.System().GetServerSetting() +// getConfigFileName +// @description: 获取服务端配置文件名称 +// @return string +func getConfigFileName() string { + data, err := repository.System().GetServerSetting() if err != nil { log.Errorf("获取服务端配置失败: %v", err.Error()) - return + return "" } - if configPath.ConfigFilePath != "" { - configPath.ConfigFilePath = strings.Split(configPath.ConfigFilePath, "/")[len(strings.Split(configPath.ConfigFilePath, "/"))-1] + if data.ConfigFilePath != "" { + data.ConfigFilePath = strings.Split(data.ConfigFilePath, "/")[len(strings.Split(data.ConfigFilePath, "/"))-1] // 这里取到的是wg0.conf + data.ConfigFilePath = strings.Split(data.ConfigFilePath, ".conf")[0] // 这里取到的就是wg0 } - if err = exec.Command(fmt.Sprintf("wg-quick down %s", configPath.ConfigFilePath)).Run(); err != nil { - log.Errorf("停止wireguard服务端失败: %v", err.Error()) - } + return data.ConfigFilePath +} - if err = exec.Command(fmt.Sprintf("wg-quick up %s", configPath.ConfigFilePath)).Run(); err != nil { - log.Errorf("启动wireguard服务端失败: %v", err.Error()) +// RestartWireguard +// @description: 是否重启 +// @param isAsync // 是否异步执行 +func RestartWireguard(isAsync bool) { + if isAsync { + go func() { + StopWireguard() // 停止 + StartWireguard() // 启动 + }() + } else { + StopWireguard() // 停止 + StartWireguard() // 启动 } - return } // StopWireguard // @description: 停止服务端 func StopWireguard() { - configPath, err := repository.System().GetServerSetting() - if err != nil { - log.Errorf("获取服务端配置失败: %v", err.Error()) - return - } + configFileName := getConfigFileName() - if configPath.ConfigFilePath != "" { - configPath.ConfigFilePath = strings.Split(configPath.ConfigFilePath, "/")[len(strings.Split(configPath.ConfigFilePath, "/"))-1] - } - - if err = exec.Command(fmt.Sprintf("wg-quick down %s", configPath.ConfigFilePath)).Run(); err != nil { + if err := exec.Command(fmt.Sprintf("wg-quick down %s", configFileName)).Run(); err != nil { log.Errorf("停止wireguard服务端失败: %v", err.Error()) } + + return } // StartWireguard // @description: 启动服务端 func StartWireguard() { - configPath, err := repository.System().GetServerSetting() - if err != nil { - log.Errorf("获取服务端配置失败: %v", err.Error()) - return - } + configFileName := getConfigFileName() - if configPath.ConfigFilePath != "" { - configPath.ConfigFilePath = strings.Split(configPath.ConfigFilePath, "/")[len(strings.Split(configPath.ConfigFilePath, "/"))-1] - } - - if err = exec.Command(fmt.Sprintf("wg-quick up %s", configPath.ConfigFilePath)).Run(); err != nil { + if err := exec.Command(fmt.Sprintf("wg-quick up %s", configFileName)).Run(); err != nil { log.Errorf("启动wireguard服务端失败: %v", err.Error()) } + + return } diff --git a/component/wireguard.go b/component/wireguard.go index 9244695..0894edf 100644 --- a/component/wireguard.go +++ b/component/wireguard.go @@ -2,6 +2,9 @@ package component import ( "gitee.ltd/lxh/logger/log" + "gopkg.in/fsnotify.v1" + "wireguard-dashboard/command" + "wireguard-dashboard/config" "wireguard-dashboard/utils" ) @@ -15,7 +18,7 @@ func Wireguard() wireguard { // @description: 应用配置 // @receiver wireguard // @return err -func (wireguard) Apply(templateFilePath, configFilePath string, data any) (err error) { +func (w wireguard) Apply(templateFilePath, configFilePath string, data any) (err error) { parseTemplate, err := utils.Template().Parse(templateFilePath) if err != nil { @@ -29,5 +32,56 @@ func (wireguard) Apply(templateFilePath, configFilePath string, data any) (err e return err } + // 判断服务端重启规则 + switch config.Config.Wireguard.ListenConfig { + case "auto": + w.watchListConfig(configFilePath) + } + return nil } + +// watchListConfig +// @description: 监听配置文件变化 +// @receiver wireguard +// @return err +func (wireguard) watchListConfig(filePath string) { + go func() { + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Errorf("创建文件监控失败: %v", err.Error()) + return + } + + defer watcher.Close() + done := make(chan bool) + + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + + if event.Op == fsnotify.Write { + command.RestartWireguard(true) + } + + // 打印监听事件 + log.Errorf("监听事件是:%s", event.String()) + case _, ok := <-watcher.Errors: + if !ok { + return + } + } + } + }() + + if err = watcher.Add(filePath); err != nil { + log.Errorf("添加[%s]监听失败: %v", filePath, err.Error()) + return + } + <-done + }() +} diff --git a/config/config.go b/config/config.go index 7dd30b7..ad86753 100644 --- a/config/config.go +++ b/config/config.go @@ -3,8 +3,9 @@ package config var Config *config type config struct { - Http *http `yaml:"http"` - Database *database `yaml:"database"` - Redis *redis `yaml:"redis"` - File *file `yaml:"file"` + Http *http `yaml:"http"` + Database *database `yaml:"database"` + Redis *redis `yaml:"redis"` + File *file `yaml:"file"` + Wireguard wireguard `yaml:"wireguard"` } diff --git a/config/wireguard.go b/config/wireguard.go new file mode 100644 index 0000000..e694a6e --- /dev/null +++ b/config/wireguard.go @@ -0,0 +1,5 @@ +package config + +type wireguard struct { + ListenConfig string `json:"listenConfig" yaml:"listenConfig"` +} diff --git a/go.mod b/go.mod index aae12dc..3b07be7 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 require ( gitee.ltd/lxh/logger v1.0.15 github.com/cowardmrx/go_aliyun_oss v1.0.7 + github.com/dustin/go-humanize v1.0.1 github.com/gin-gonic/gin v1.9.1 github.com/go-resty/resty/v2 v2.11.0 github.com/golang-jwt/jwt/v5 v5.2.1 @@ -15,6 +16,7 @@ require ( github.com/spf13/cast v1.6.0 golang.org/x/crypto v0.21.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 + gopkg.in/fsnotify.v1 v1.4.7 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.5.4 gorm.io/driver/postgres v1.5.6 @@ -30,7 +32,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-kit/kit v0.12.0 // indirect @@ -69,7 +71,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect - github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/go.sum b/go.sum index fdd90dc..56ced7e 100644 --- a/go.sum +++ b/go.sum @@ -199,6 +199,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -626,8 +628,6 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= @@ -1273,6 +1273,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= diff --git a/http/api/client.go b/http/api/client.go index a02677c..2be3d55 100644 --- a/http/api/client.go +++ b/http/api/client.go @@ -91,6 +91,13 @@ func (clients) Delete(c *gin.Context) { return } + // 再同步一下配置文件 + go func() { + if err := queues.PutAsyncWireguardConfigFile(""); err != nil { + log.Errorf("[下线客户端]同步配置文件失败: %v", err.Error()) + } + }() + utils.GinResponse(c).OK() } diff --git a/http/api/server.go b/http/api/server.go index de070d4..8401588 100644 --- a/http/api/server.go +++ b/http/api/server.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "strings" + "wireguard-dashboard/command" "wireguard-dashboard/http/param" "wireguard-dashboard/model/entity" "wireguard-dashboard/queues" @@ -89,3 +90,26 @@ func (server) GetServer(c *gin.Context) { utils.GinResponse(c).OKWithData(data) } + +// ControlServer +// @description: 服务端控制器 +// @receiver server +// @param c +func (server) ControlServer(c *gin.Context) { + var p param.ControlServer + if err := c.ShouldBind(&p); err != nil { + utils.GinResponse(c).FailedWithErr("参数错误", err) + return + } + + switch p.Status { + case "START": + command.StartWireguard() + case "STOP": + command.StopWireguard() + case "RESTART": + command.RestartWireguard(false) + } + + utils.GinResponse(c).OK() +} diff --git a/http/param/client.go b/http/param/client.go index 07733d3..74382b7 100644 --- a/http/param/client.go +++ b/http/param/client.go @@ -31,3 +31,9 @@ type SaveClient struct { Keys *template_data.Keys `json:"keys" form:"keys" binding:"omitempty"` Enabled int `json:"enabled" form:"enabled" binding:"required,oneof=1 0"` } + +// ControlServer +// @description: 服务端控制 +type ControlServer struct { + Status string `json:"status" form:"status" binding:"required,oneof=START STOP RESTART"` +} diff --git a/route/server.go b/route/server.go index 3173fe7..ca68863 100644 --- a/route/server.go +++ b/route/server.go @@ -9,7 +9,8 @@ import ( func ServerApi(r *gin.RouterGroup) { apiGroup := r.Group("server", middleware.Authorization()) { - apiGroup.GET("", api.Server().GetServer) // 获取服务端信息 - apiGroup.POST("", middleware.Permission(), api.Server().SaveServer) // 新增/更新服务端信息 + apiGroup.GET("", api.Server().GetServer) // 获取服务端信息 + apiGroup.POST("", middleware.Permission(), api.Server().SaveServer) // 新增/更新服务端信息 + apiGroup.POST("control-server", middleware.Permission(), api.Server().ControlServer) // 服务端操作控制 } }