mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 11:27:17 +08:00
feat: Rsync 插件
This commit is contained in:
@@ -27,3 +27,13 @@ type S3fsMount struct {
|
||||
Bucket string `json:"bucket"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type RsyncModule struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Comment string `json:"comment"`
|
||||
ReadOnly bool `json:"read_only"`
|
||||
AuthUser string `json:"auth_user"`
|
||||
Secret string `json:"secret"`
|
||||
HostsAllow string `json:"hosts_allow"`
|
||||
}
|
||||
|
||||
331
app/http/controllers/plugins/rsync_controller.go
Normal file
331
app/http/controllers/plugins/rsync_controller.go
Normal file
@@ -0,0 +1,331 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
|
||||
"panel/app/http/controllers"
|
||||
commonrequests "panel/app/http/requests/common"
|
||||
requests "panel/app/http/requests/plugins/rsync"
|
||||
"panel/app/services"
|
||||
"panel/pkg/tools"
|
||||
)
|
||||
|
||||
type RsyncController struct {
|
||||
setting services.Setting
|
||||
}
|
||||
|
||||
func NewRsyncController() *RsyncController {
|
||||
return &RsyncController{
|
||||
setting: services.NewSettingImpl(),
|
||||
}
|
||||
}
|
||||
|
||||
// Status
|
||||
//
|
||||
// @Summary 服务状态
|
||||
// @Description 获取 Rsync 服务状态
|
||||
// @Tags 插件-Rsync
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} controllers.SuccessResponse
|
||||
// @Router /plugins/rsync/status [get]
|
||||
func (r *RsyncController) Status(ctx http.Context) http.Response {
|
||||
status, err := tools.ServiceStatus("rsyncd")
|
||||
if err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败")
|
||||
}
|
||||
|
||||
return controllers.Success(ctx, status)
|
||||
}
|
||||
|
||||
// Restart
|
||||
//
|
||||
// @Summary 重启服务
|
||||
// @Description 重启 Rsync 服务
|
||||
// @Tags 插件-Rsync
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} controllers.SuccessResponse
|
||||
// @Router /plugins/rsync/restart [post]
|
||||
func (r *RsyncController) Restart(ctx http.Context) http.Response {
|
||||
if err := tools.ServiceRestart("rsyncd"); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, "重启服务失败")
|
||||
}
|
||||
|
||||
return controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// Start
|
||||
//
|
||||
// @Summary 启动服务
|
||||
// @Description 启动 Rsync 服务
|
||||
// @Tags 插件-Rsync
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} controllers.SuccessResponse
|
||||
// @Router /plugins/rsync/start [post]
|
||||
func (r *RsyncController) Start(ctx http.Context) http.Response {
|
||||
if err := tools.ServiceStart("rsyncd"); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, "启动服务失败")
|
||||
}
|
||||
|
||||
return controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// Stop
|
||||
//
|
||||
// @Summary 停止服务
|
||||
// @Description 停止 Rsync 服务
|
||||
// @Tags 插件-Rsync
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} controllers.SuccessResponse
|
||||
// @Router /plugins/rsync/stop [post]
|
||||
func (r *RsyncController) Stop(ctx http.Context) http.Response {
|
||||
if err := tools.ServiceStop("rsyncd"); err != nil {
|
||||
return nil
|
||||
}
|
||||
status, err := tools.ServiceStatus("rsyncd")
|
||||
if err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败")
|
||||
}
|
||||
|
||||
return controllers.Success(ctx, !status)
|
||||
}
|
||||
|
||||
// List
|
||||
//
|
||||
// @Summary 列出模块
|
||||
// @Description 列出所有 Rsync 模块
|
||||
// @Tags 插件-Rsync
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param data body commonrequests.Paginate true "request"
|
||||
// @Success 200 {object} controllers.SuccessResponse
|
||||
// @Router /plugins/rsync/modules [get]
|
||||
func (r *RsyncController) List(ctx http.Context) http.Response {
|
||||
var paginateRequest commonrequests.Paginate
|
||||
sanitize := controllers.Sanitize(ctx, &paginateRequest)
|
||||
if sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
|
||||
config, err := tools.Read("/etc/rsyncd.conf")
|
||||
if err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
var modules []RsyncModule
|
||||
lines := strings.Split(config, "\n")
|
||||
var currentModule *RsyncModule
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
||||
if currentModule != nil {
|
||||
modules = append(modules, *currentModule)
|
||||
}
|
||||
moduleName := line[1 : len(line)-1]
|
||||
secret, err := tools.Exec("grep -E '^" + moduleName + ":.*$' /etc/rsyncd.secrets | awk '{print $2}'")
|
||||
if err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, "获取模块"+moduleName+"的密钥失败")
|
||||
}
|
||||
currentModule = &RsyncModule{
|
||||
Name: moduleName,
|
||||
Secret: secret,
|
||||
}
|
||||
} else if currentModule != nil {
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) == 2 {
|
||||
key := strings.TrimSpace(parts[0])
|
||||
value := strings.TrimSpace(parts[1])
|
||||
|
||||
switch key {
|
||||
case "path":
|
||||
currentModule.Path = value
|
||||
case "comment":
|
||||
currentModule.Comment = value
|
||||
case "read only":
|
||||
currentModule.ReadOnly = value == "yes" || value == "true"
|
||||
case "auth users":
|
||||
currentModule.AuthUser = value
|
||||
case "hosts allow":
|
||||
currentModule.HostsAllow = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentModule != nil {
|
||||
modules = append(modules, *currentModule)
|
||||
}
|
||||
|
||||
startIndex := (paginateRequest.Page - 1) * paginateRequest.Limit
|
||||
endIndex := paginateRequest.Page * paginateRequest.Limit
|
||||
if startIndex > len(modules) {
|
||||
return controllers.Success(ctx, http.Json{
|
||||
"total": 0,
|
||||
"items": []RsyncModule{},
|
||||
})
|
||||
}
|
||||
if endIndex > len(modules) {
|
||||
endIndex = len(modules)
|
||||
}
|
||||
pagedModules := modules[startIndex:endIndex]
|
||||
if pagedModules == nil {
|
||||
pagedModules = []RsyncModule{}
|
||||
}
|
||||
|
||||
return controllers.Success(ctx, http.Json{
|
||||
"total": len(modules),
|
||||
"items": pagedModules,
|
||||
})
|
||||
}
|
||||
|
||||
// Add
|
||||
//
|
||||
// @Summary 添加模块
|
||||
// @Description 添加 Rsync 模块
|
||||
// @Tags 插件-Rsync
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param data body requests.Add true "request"
|
||||
// @Success 200 {object} controllers.SuccessResponse
|
||||
// @Router /plugins/rsync/modules [post]
|
||||
func (r *RsyncController) Add(ctx http.Context) http.Response {
|
||||
var addRequest requests.Add
|
||||
sanitize := controllers.Sanitize(ctx, &addRequest)
|
||||
if sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
|
||||
conf := `
|
||||
# ` + addRequest.Name + `-START
|
||||
[` + addRequest.Name + `]
|
||||
path = ` + addRequest.Path + `
|
||||
comment = ` + addRequest.Comment + `
|
||||
read only = no
|
||||
auth users = ` + addRequest.AuthUser + `
|
||||
hosts allow = ` + addRequest.HostsAllow + `
|
||||
secrets file = /etc/rsyncd.secrets
|
||||
# ` + addRequest.Name + `-END
|
||||
`
|
||||
|
||||
if err := tools.WriteAppend("/etc/rsyncd.conf", conf); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
if err := tools.WriteAppend("/etc/rsyncd.secrets", addRequest.Name+":"+addRequest.Secret); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
if err := tools.ServiceRestart("rsyncd"); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// Delete
|
||||
//
|
||||
// @Summary 删除模块
|
||||
// @Description 删除 Rsync 模块
|
||||
// @Tags 插件-Rsync
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param name query string true "模块名称"
|
||||
// @Success 200 {object} controllers.SuccessResponse
|
||||
// @Router /plugins/rsync/modules [delete]
|
||||
func (r *RsyncController) Delete(ctx http.Context) http.Response {
|
||||
name := ctx.Request().Input("name")
|
||||
if len(name) == 0 {
|
||||
return controllers.Error(ctx, http.StatusUnprocessableEntity, "name 不能为空")
|
||||
}
|
||||
|
||||
config, err := tools.Read("/etc/rsyncd.conf")
|
||||
if err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
if !strings.Contains(config, "["+name+"]") {
|
||||
return controllers.Error(ctx, http.StatusUnprocessableEntity, "模块 "+name+" 不存在")
|
||||
}
|
||||
|
||||
module := tools.Cut(config, "# "+name+"-START", "# "+name+"-END")
|
||||
config = strings.Replace(config, "\n# "+name+"-START"+module+"# "+name+"-END", "", -1)
|
||||
|
||||
if err = tools.Write("/etc/rsyncd.conf", config, 0644); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
if out, err := tools.Exec("sed -i '/^" + name + ":.*$/d' /etc/rsyncd.secrets"); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, out)
|
||||
}
|
||||
|
||||
if err = tools.ServiceRestart("rsyncd"); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// Update
|
||||
//
|
||||
// @Summary 更新模块
|
||||
// @Description 更新 Rsync 模块
|
||||
// @Tags 插件-Rsync
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param data body requests.Update true "request"
|
||||
// @Success 200 {object} controllers.SuccessResponse
|
||||
// @Router /plugins/rsync/modules [put]
|
||||
func (r *RsyncController) Update(ctx http.Context) http.Response {
|
||||
var updateRequest requests.Update
|
||||
sanitize := controllers.Sanitize(ctx, &updateRequest)
|
||||
if sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
|
||||
config, err := tools.Read("/etc/rsyncd.conf")
|
||||
if err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
if !strings.Contains(config, "["+updateRequest.Name+"]") {
|
||||
return controllers.Error(ctx, http.StatusUnprocessableEntity, "模块 "+updateRequest.Name+" 不存在")
|
||||
}
|
||||
|
||||
newConf := `# ` + updateRequest.Name + `-START
|
||||
[` + updateRequest.Name + `]
|
||||
path = ` + updateRequest.Path + `
|
||||
comment = ` + updateRequest.Comment + `
|
||||
read only = no
|
||||
auth users = ` + updateRequest.AuthUser + `
|
||||
hosts allow = ` + updateRequest.HostsAllow + `
|
||||
secrets file = /etc/rsyncd.secrets
|
||||
# ` + updateRequest.Name + `-END
|
||||
`
|
||||
|
||||
module := tools.Cut(config, "# "+updateRequest.Name+"-START", "# "+updateRequest.Name+"-END")
|
||||
config = strings.Replace(config, "# "+updateRequest.Name+"-START"+module+"# "+updateRequest.Name+"-END", newConf, -1)
|
||||
|
||||
if err = tools.Write("/etc/rsyncd.conf", config, 0644); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
if out, err := tools.Exec("sed -i '/^" + updateRequest.Name + ":.*$/d' /etc/rsyncd.secrets"); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, out)
|
||||
}
|
||||
if err := tools.WriteAppend("/etc/rsyncd.secrets", updateRequest.Name+":"+updateRequest.Secret); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
if err = tools.ServiceRestart("rsyncd"); err != nil {
|
||||
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return controllers.Success(ctx, nil)
|
||||
}
|
||||
42
app/http/requests/plugins/rsync/add.go
Normal file
42
app/http/requests/plugins/rsync/add.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/contracts/validation"
|
||||
)
|
||||
|
||||
type Add struct {
|
||||
Name string `form:"name" json:"name"`
|
||||
Path string `form:"path" json:"path"`
|
||||
Comment string `form:"comment" json:"comment"`
|
||||
AuthUser string `form:"auth_user" json:"auth_user"`
|
||||
Secret string `form:"secret" json:"secret"`
|
||||
HostsAllow string `form:"hosts_allow" json:"hosts_allow"`
|
||||
}
|
||||
|
||||
func (r *Add) Authorize(ctx http.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Add) Rules(ctx http.Context) map[string]string {
|
||||
return map[string]string{
|
||||
"name": "required|regex:^[a-zA-Z0-9-_]+$",
|
||||
"path": "regex:^/[a-zA-Z0-9_-]+(\\/[a-zA-Z0-9_-]+)*$",
|
||||
"comment": "string",
|
||||
"auth_user": "required|regex:^[a-zA-Z0-9-_]+$",
|
||||
"secret": "required|min_len:8",
|
||||
"hosts_allow": "string",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Add) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Add) Attributes(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Add) PrepareForValidation(ctx http.Context, data validation.Data) error {
|
||||
return nil
|
||||
}
|
||||
42
app/http/requests/plugins/rsync/update.go
Normal file
42
app/http/requests/plugins/rsync/update.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/contracts/validation"
|
||||
)
|
||||
|
||||
type Update struct {
|
||||
Name string `form:"name" json:"name"`
|
||||
Path string `form:"path" json:"path"`
|
||||
Comment string `form:"comment" json:"comment"`
|
||||
AuthUser string `form:"auth_user" json:"auth_user"`
|
||||
Secret string `form:"secret" json:"secret"`
|
||||
HostsAllow string `form:"hosts_allow" json:"hosts_allow"`
|
||||
}
|
||||
|
||||
func (r *Update) Authorize(ctx http.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Update) Rules(ctx http.Context) map[string]string {
|
||||
return map[string]string{
|
||||
"name": "required|regex:^[a-zA-Z0-9-_]+$",
|
||||
"path": "regex:^/[a-zA-Z0-9_-]+(\\/[a-zA-Z0-9_-]+)*$",
|
||||
"comment": "string",
|
||||
"auth_user": "required|regex:^[a-zA-Z0-9-_]+$",
|
||||
"secret": "required|min_len:8",
|
||||
"hosts_allow": "string",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Update) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Update) Attributes(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Update) PrepareForValidation(ctx http.Context, data validation.Data) error {
|
||||
return nil
|
||||
}
|
||||
13
app/plugins/rsync/rsync.go
Normal file
13
app/plugins/rsync/rsync.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package rsync
|
||||
|
||||
var (
|
||||
Name = "Rsync"
|
||||
Description = "Rsync 是一款提供快速增量文件传输的开源工具。"
|
||||
Slug = "rsync"
|
||||
Version = "3.2.7"
|
||||
Requires = []string{}
|
||||
Excludes = []string{}
|
||||
Install = `bash /www/panel/scripts/rsync/install.sh`
|
||||
Uninstall = `bash /www/panel/scripts/rsync/uninstall.sh`
|
||||
Update = `bash /www/panel/scripts/rsync/install.sh`
|
||||
)
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"panel/app/plugins/postgresql16"
|
||||
"panel/app/plugins/pureftpd"
|
||||
"panel/app/plugins/redis"
|
||||
"panel/app/plugins/rsync"
|
||||
"panel/app/plugins/s3fs"
|
||||
"panel/app/plugins/supervisor"
|
||||
"panel/app/plugins/toolbox"
|
||||
@@ -229,6 +230,17 @@ func (r *PluginImpl) All() []PanelPlugin {
|
||||
Uninstall: fail2ban.Uninstall,
|
||||
Update: fail2ban.Update,
|
||||
})
|
||||
p = append(p, PanelPlugin{
|
||||
Name: rsync.Name,
|
||||
Description: rsync.Description,
|
||||
Slug: rsync.Slug,
|
||||
Version: rsync.Version,
|
||||
Requires: rsync.Requires,
|
||||
Excludes: rsync.Excludes,
|
||||
Install: rsync.Install,
|
||||
Uninstall: rsync.Uninstall,
|
||||
Update: rsync.Update,
|
||||
})
|
||||
p = append(p, PanelPlugin{
|
||||
Name: toolbox.Name,
|
||||
Description: toolbox.Description,
|
||||
|
||||
346
docs/docs.go
346
docs/docs.go
@@ -920,7 +920,7 @@ const docTemplate = `{
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/requests.Update"
|
||||
"$ref": "#/definitions/panel_app_http_requests_setting.Update"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1295,7 +1295,7 @@ const docTemplate = `{
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/requests.Add"
|
||||
"$ref": "#/definitions/panel_app_http_requests_website.Add"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1661,6 +1661,242 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/modules": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "列出所有 Rsync 模块",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "列出模块",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/commonrequests.Paginate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "更新 Rsync 模块",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "更新模块",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/panel_app_http_requests_plugins_rsync.Update"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "添加 Rsync 模块",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "添加模块",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/panel_app_http_requests_plugins_rsync.Add"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "删除 Rsync 模块",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "删除模块",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "模块名称",
|
||||
"name": "name",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/restart": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "重启 Rsync 服务",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "重启服务",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/start": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "启动 Rsync 服务",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "启动服务",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/status": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "获取 Rsync 服务状态",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "服务状态",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/stop": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "停止 Rsync 服务",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "停止服务",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/swagger": {
|
||||
"get": {
|
||||
"description": "Swagger UI",
|
||||
@@ -1905,7 +2141,82 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.Add": {
|
||||
"panel_app_http_requests_plugins_rsync.Add": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth_user": {
|
||||
"type": "string"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"hosts_allow": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel_app_http_requests_plugins_rsync.Update": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth_user": {
|
||||
"type": "string"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"hosts_allow": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel_app_http_requests_setting.Update": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"backup_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"entrance": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"port": {
|
||||
"type": "integer"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"website_path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel_app_http_requests_website.Add": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"db": {
|
||||
@@ -2135,35 +2446,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.Update": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"backup_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"entrance": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"port": {
|
||||
"type": "integer"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"website_path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.UserStore": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -913,7 +913,7 @@
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/requests.Update"
|
||||
"$ref": "#/definitions/panel_app_http_requests_setting.Update"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/requests.Add"
|
||||
"$ref": "#/definitions/panel_app_http_requests_website.Add"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1654,6 +1654,242 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/modules": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "列出所有 Rsync 模块",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "列出模块",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/commonrequests.Paginate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "更新 Rsync 模块",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "更新模块",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/panel_app_http_requests_plugins_rsync.Update"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "添加 Rsync 模块",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "添加模块",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/panel_app_http_requests_plugins_rsync.Add"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "删除 Rsync 模块",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "删除模块",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "模块名称",
|
||||
"name": "name",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/restart": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "重启 Rsync 服务",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "重启服务",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/start": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "启动 Rsync 服务",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "启动服务",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/status": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "获取 Rsync 服务状态",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "服务状态",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/rsync/stop": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "停止 Rsync 服务",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"插件-Rsync"
|
||||
],
|
||||
"summary": "停止服务",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/swagger": {
|
||||
"get": {
|
||||
"description": "Swagger UI",
|
||||
@@ -1898,7 +2134,82 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.Add": {
|
||||
"panel_app_http_requests_plugins_rsync.Add": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth_user": {
|
||||
"type": "string"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"hosts_allow": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel_app_http_requests_plugins_rsync.Update": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth_user": {
|
||||
"type": "string"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"hosts_allow": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel_app_http_requests_setting.Update": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"backup_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"entrance": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"port": {
|
||||
"type": "integer"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"website_path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel_app_http_requests_website.Add": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"db": {
|
||||
@@ -2128,35 +2439,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.Update": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"backup_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"entrance": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"port": {
|
||||
"type": "integer"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"website_path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.UserStore": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -151,7 +151,56 @@ definitions:
|
||||
updated_at:
|
||||
type: string
|
||||
type: object
|
||||
requests.Add:
|
||||
panel_app_http_requests_plugins_rsync.Add:
|
||||
properties:
|
||||
auth_user:
|
||||
type: string
|
||||
comment:
|
||||
type: string
|
||||
hosts_allow:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
secret:
|
||||
type: string
|
||||
type: object
|
||||
panel_app_http_requests_plugins_rsync.Update:
|
||||
properties:
|
||||
auth_user:
|
||||
type: string
|
||||
comment:
|
||||
type: string
|
||||
hosts_allow:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
secret:
|
||||
type: string
|
||||
type: object
|
||||
panel_app_http_requests_setting.Update:
|
||||
properties:
|
||||
backup_path:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
entrance:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
username:
|
||||
type: string
|
||||
website_path:
|
||||
type: string
|
||||
type: object
|
||||
panel_app_http_requests_website.Add:
|
||||
properties:
|
||||
db:
|
||||
type: boolean
|
||||
@@ -301,25 +350,6 @@ definitions:
|
||||
waf_mode:
|
||||
type: string
|
||||
type: object
|
||||
requests.Update:
|
||||
properties:
|
||||
backup_path:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
entrance:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
username:
|
||||
type: string
|
||||
website_path:
|
||||
type: string
|
||||
type: object
|
||||
requests.UserStore:
|
||||
properties:
|
||||
ca:
|
||||
@@ -990,7 +1020,7 @@ paths:
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/requests.Update'
|
||||
$ref: '#/definitions/panel_app_http_requests_setting.Update'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -1213,7 +1243,7 @@ paths:
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/requests.Add'
|
||||
$ref: '#/definitions/panel_app_http_requests_website.Add'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -1443,6 +1473,150 @@ paths:
|
||||
summary: 更新备注
|
||||
tags:
|
||||
- 网站管理
|
||||
/plugins/rsync/modules:
|
||||
delete:
|
||||
description: 删除 Rsync 模块
|
||||
parameters:
|
||||
- description: 模块名称
|
||||
in: query
|
||||
name: name
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 删除模块
|
||||
tags:
|
||||
- 插件-Rsync
|
||||
get:
|
||||
description: 列出所有 Rsync 模块
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/commonrequests.Paginate'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 列出模块
|
||||
tags:
|
||||
- 插件-Rsync
|
||||
post:
|
||||
description: 添加 Rsync 模块
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/panel_app_http_requests_plugins_rsync.Add'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 添加模块
|
||||
tags:
|
||||
- 插件-Rsync
|
||||
put:
|
||||
description: 更新 Rsync 模块
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/panel_app_http_requests_plugins_rsync.Update'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 更新模块
|
||||
tags:
|
||||
- 插件-Rsync
|
||||
/plugins/rsync/restart:
|
||||
post:
|
||||
description: 重启 Rsync 服务
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 重启服务
|
||||
tags:
|
||||
- 插件-Rsync
|
||||
/plugins/rsync/start:
|
||||
post:
|
||||
description: 启动 Rsync 服务
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 启动服务
|
||||
tags:
|
||||
- 插件-Rsync
|
||||
/plugins/rsync/status:
|
||||
get:
|
||||
description: 获取 Rsync 服务状态
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 服务状态
|
||||
tags:
|
||||
- 插件-Rsync
|
||||
/plugins/rsync/stop:
|
||||
post:
|
||||
description: 停止 Rsync 服务
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 停止服务
|
||||
tags:
|
||||
- 插件-Rsync
|
||||
/swagger:
|
||||
get:
|
||||
description: Swagger UI
|
||||
|
||||
@@ -29,6 +29,22 @@ func Write(path string, data string, permission os.FileMode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteAppend 追加写入文件
|
||||
func WriteAppend(path string, data string) error {
|
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = file.WriteString(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read 读取文件
|
||||
func Read(path string) (string, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
|
||||
@@ -18,11 +18,11 @@ func TestSystemHelperTestSuite(t *testing.T) {
|
||||
suite.Run(t, &SystemHelperTestSuite{})
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestWrite() {
|
||||
func (s *SystemHelperTestSuite) WriteCreatesFileWithCorrectContent() {
|
||||
filePath, _ := TempFile("testfile")
|
||||
|
||||
s.Nil(Write(filePath.Name(), "test data", 0644))
|
||||
s.FileExists(filePath.Name())
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
content, _ := Read(filePath.Name())
|
||||
s.Equal("test data", content)
|
||||
@@ -30,27 +30,108 @@ func (s *SystemHelperTestSuite) TestWrite() {
|
||||
s.Nil(Remove(filePath.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestRead() {
|
||||
func (s *SystemHelperTestSuite) WriteCreatesDirectoriesIfNeeded() {
|
||||
filePath, _ := TempFile("testdir/testfile")
|
||||
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
content, _ := Read(filePath.Name())
|
||||
s.Equal("test data", content)
|
||||
s.Nil(filePath.Close())
|
||||
s.Nil(Remove(filePath.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) WriteFailsIfDirectoryCannotBeCreated() {
|
||||
filePath := "/nonexistent/testfile"
|
||||
|
||||
err := Write(filePath, "test data", 0644)
|
||||
s.NotNil(err)
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) WriteFailsIfFileCannotBeWritten() {
|
||||
filePath, _ := TempFile("testfile")
|
||||
s.Nil(filePath.Close())
|
||||
s.Nil(Chmod(filePath.Name(), 0400))
|
||||
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.NotNil(err)
|
||||
|
||||
s.Nil(Chmod(filePath.Name(), 0644))
|
||||
s.Nil(Remove(filePath.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) WriteAppendSuccessfullyAppendsDataToFile() {
|
||||
filePath, _ := TempFile("testfile")
|
||||
|
||||
err := Write(filePath.Name(), "initial data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
err = WriteAppend(filePath.Name(), " appended data")
|
||||
s.Nil(err)
|
||||
|
||||
content, _ := Read(filePath.Name())
|
||||
s.Equal("initial data appended data", content)
|
||||
s.Nil(filePath.Close())
|
||||
s.Nil(Remove(filePath.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) WriteAppendCreatesFileIfNotExists() {
|
||||
filePath, _ := TempFile("testfile")
|
||||
s.Nil(filePath.Close())
|
||||
s.Nil(Remove(filePath.Name()))
|
||||
|
||||
err := WriteAppend(filePath.Name(), "test data")
|
||||
s.Nil(err)
|
||||
|
||||
content, _ := Read(filePath.Name())
|
||||
s.Equal("test data", content)
|
||||
s.Nil(Remove(filePath.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) WriteAppendReturnsErrorIfPathIsADirectory() {
|
||||
dirPath, _ := TempDir("testdir")
|
||||
|
||||
err := WriteAppend(dirPath, "test data")
|
||||
s.NotNil(err)
|
||||
|
||||
s.Nil(Remove(dirPath))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) ReadSuccessfullyReadsFileContent() {
|
||||
filePath, _ := TempFile("testfile")
|
||||
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
data, err := Read(filePath.Name())
|
||||
content, err := Read(filePath.Name())
|
||||
s.Nil(err)
|
||||
s.Equal("test data", data)
|
||||
s.Equal("test data", content)
|
||||
|
||||
s.Nil(filePath.Close())
|
||||
s.Nil(Remove(filePath.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestRemove() {
|
||||
file, _ := TempFile("testfile")
|
||||
file.Close()
|
||||
func (s *SystemHelperTestSuite) ReadReturnsErrorForNonExistentFile() {
|
||||
_, err := Read("/nonexistent/testfile")
|
||||
s.NotNil(err)
|
||||
}
|
||||
|
||||
err := Write(file.Name(), "test data", 0644)
|
||||
func (s *SystemHelperTestSuite) RemoveSuccessfullyRemovesFile() {
|
||||
filePath, _ := TempFile("testfile")
|
||||
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.Nil(Remove(file.Name()))
|
||||
err = Remove(filePath.Name())
|
||||
s.Nil(err)
|
||||
|
||||
s.False(Exists(filePath.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) RemoveReturnsErrorForNonExistentFile() {
|
||||
err := Remove("/nonexistent/testfile")
|
||||
s.NotNil(err)
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestExec() {
|
||||
|
||||
@@ -282,6 +282,16 @@ func Plugin() {
|
||||
route.Post("whiteList", fail2banController.SetWhiteList)
|
||||
route.Get("whiteList", fail2banController.GetWhiteList)
|
||||
})
|
||||
r.Prefix("rsync").Group(func(route route.Router) {
|
||||
rsyncController := plugins.NewRsyncController()
|
||||
route.Get("status", rsyncController.Status)
|
||||
route.Post("start", rsyncController.Start)
|
||||
route.Post("stop", rsyncController.Stop)
|
||||
route.Post("restart", rsyncController.Restart)
|
||||
route.Get("modules", rsyncController.List)
|
||||
route.Post("modules", rsyncController.Add)
|
||||
route.Delete("modules", rsyncController.Delete)
|
||||
})
|
||||
r.Prefix("toolbox").Group(func(route route.Router) {
|
||||
toolboxController := plugins.NewToolBoxController()
|
||||
route.Get("dns", toolboxController.GetDNS)
|
||||
|
||||
79
scripts/rsync/install.sh
Normal file
79
scripts/rsync/install.sh
Normal file
@@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright (C) 2022 - now HaoZi Technology Co., Ltd.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
|
||||
|
||||
if [ "${OS}" == "centos" ]; then
|
||||
dnf install -y rsync
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
apt-get install -y rsync
|
||||
else
|
||||
echo -e $HR
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 写入配置
|
||||
cat > /etc/rsyncd.conf << EOF
|
||||
uid = root
|
||||
gid = root
|
||||
port = 873
|
||||
use chroot = no
|
||||
read only = no
|
||||
dont compress = *.jpg *.jpeg *.png *.gif *.webp *.avif *.mp4 *.avi *.mov *.mkv *.mp3 *.wav *.aac *.flac *.zip *.rar *.7z *.gz *.tgz *.tar *.pdf *.epub *.iso *.exe *.apk *.dmg *.rpm *.deb *.msi
|
||||
hosts allow = 127.0.0.1/32 ::1/128
|
||||
# hosts deny =
|
||||
max connections = 100
|
||||
timeout = 1800
|
||||
lock file = /var/run/rsync.lock
|
||||
pid file = /var/run/rsyncd.pid
|
||||
log file = /var/log/rsyncd.log
|
||||
|
||||
EOF
|
||||
|
||||
touch /etc/rsyncd.secrets
|
||||
chmod 600 /etc/rsyncd.conf
|
||||
chmod 600 /etc/rsyncd.secrets
|
||||
|
||||
# 写入服务文件
|
||||
cat > /etc/systemd/system/rsyncd.service << EOF
|
||||
[Unit]
|
||||
Description=fast remote file copy program daemon
|
||||
After=network-online.target remote-fs.target nss-lookup.target
|
||||
Wants=network-online.target
|
||||
ConditionPathExists=/etc/rsyncd.conf
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/rsync --daemon --no-detach "\$OPTIONS"
|
||||
ExecReload=/bin/kill -HUP \$MAINPID
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable rsyncd.service
|
||||
systemctl restart rsyncd.service
|
||||
|
||||
panel writePlugin rsync 3.2.7
|
||||
34
scripts/rsync/uninstall.sh
Normal file
34
scripts/rsync/uninstall.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright (C) 2022 - now HaoZi Technology Co., Ltd.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
|
||||
|
||||
if [ "${OS}" == "centos" ]; then
|
||||
dnf remove -y rsync
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
apt-get purge -y rsync
|
||||
else
|
||||
echo -e $HR
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
panel deletePlugin rsync
|
||||
34
scripts/rsync/update.sh
Normal file
34
scripts/rsync/update.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright (C) 2022 - now HaoZi Technology Co., Ltd.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
|
||||
|
||||
if [ "${OS}" == "centos" ]; then
|
||||
dnf update -y rsync
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
apt-get install --only-upgrade -y rsync
|
||||
else
|
||||
echo -e $HR
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
panel writePlugin rsync 3.2.7
|
||||
Reference in New Issue
Block a user