🆕为实现数据迁移以及备份新增配置导出
This commit is contained in:
parent
c3ef51e87f
commit
edaf9ba770
@ -97,8 +97,8 @@ func (w WireguardComponent) GenerateClientFile(clientInfo *model.Client, server
|
||||
var outPath = "/tmp/" + fmt.Sprintf("%s.conf", clientInfo.Name)
|
||||
var templatePath = "./template/wg.client.conf"
|
||||
if os.Getenv("GIN_MODE") != "release" {
|
||||
outPath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\" + fmt.Sprintf("%s.conf", clientInfo.Name)
|
||||
templatePath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\wg.client.conf"
|
||||
outPath = "E:\\Workspace\\Go\\wireguard-ui\\template\\tmp\\" + fmt.Sprintf("%s.conf", clientInfo.Name)
|
||||
templatePath = "E:\\Workspace\\Go\\wireguard-ui\\template\\conf\\wg.client.conf"
|
||||
}
|
||||
|
||||
err = Template().Execute(templatePath, outPath, execData)
|
||||
|
1
cron/cron.go
Normal file
1
cron/cron.go
Normal file
@ -0,0 +1 @@
|
||||
package cron
|
@ -1,11 +1,13 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"gitee.ltd/lxh/logger/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"slices"
|
||||
"wireguard-ui/http/param"
|
||||
"wireguard-ui/http/response"
|
||||
"wireguard-ui/http/vo"
|
||||
"wireguard-ui/model"
|
||||
"wireguard-ui/script"
|
||||
"wireguard-ui/service"
|
||||
@ -113,3 +115,48 @@ func (setting) GetAllSetting(c *gin.Context) {
|
||||
func (setting) GetPublicAddr(c *gin.Context) {
|
||||
response.R(c).OkWithData(utils.Network().GetHostPublicIP())
|
||||
}
|
||||
|
||||
// Export
|
||||
// @description: 导出配置
|
||||
// @receiver setting
|
||||
// @param c
|
||||
func (setting) Export(c *gin.Context) {
|
||||
// 获取当前登陆用户
|
||||
var loginUser *vo.User
|
||||
if loginUser = GetCurrentLoginUser(c); c.IsAborted() {
|
||||
return
|
||||
}
|
||||
|
||||
if loginUser.Account != "admin" {
|
||||
response.R(c).FailedWithError("非法操作,你被捕啦!")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
data, err := service.Setting().Export()
|
||||
if err != nil {
|
||||
response.R(c).FailedWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 生成配置文件
|
||||
dataBytes, _ := json.Marshal(data)
|
||||
filepath, err := utils.FileUtils().GenerateFile("config.json", dataBytes)
|
||||
if err != nil {
|
||||
response.R(c).FailedWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Content-Type", "application/octet-stream")
|
||||
c.Header("Content-Disposition", "attachment; filename="+filepath)
|
||||
c.Header("Content-Transfer-Encoding", "binary")
|
||||
c.Header("Connection", "keep-alive")
|
||||
c.File(filepath)
|
||||
//if err = os.Remove(filepath); err != nil {
|
||||
// log.Errorf("删除临时文件失败: %s", err.Error())
|
||||
//}
|
||||
}
|
||||
|
||||
func (setting) Import(c *gin.Context) {
|
||||
|
||||
}
|
||||
|
@ -17,5 +17,6 @@ func SettingApi(r *gin.RouterGroup) {
|
||||
setting.GET("", api.Setting().GetSetting) // 获取指定配置
|
||||
setting.GET("/all", api.Setting().GetAllSetting) // 获取全部配置
|
||||
setting.GET("/public-addr", api.Setting().GetPublicAddr) // 获取公网IP
|
||||
setting.GET("/export", api.Setting().Export) // 导出配置文件
|
||||
}
|
||||
}
|
||||
|
@ -7,3 +7,46 @@ type SettingItem struct {
|
||||
Data string `json:"data"`
|
||||
Describe string `json:"describe"`
|
||||
}
|
||||
|
||||
type Export struct {
|
||||
Global Global `json:"global"`
|
||||
Server Server `json:"server"`
|
||||
Clients []Client `json:"clients"`
|
||||
}
|
||||
|
||||
type Global struct {
|
||||
MTU int `json:"MTU"`
|
||||
ConfigFilePath string `json:"configFilePath"`
|
||||
DnsServer []string `json:"dnsServer"`
|
||||
EndpointAddress string `json:"endpointAddress"`
|
||||
FirewallMark string `json:"firewallMark"`
|
||||
PersistentKeepalive int `json:"persistentKeepalive"`
|
||||
Table string `json:"table"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
IpScope []string `json:"ipScope"`
|
||||
ListenPort int `json:"listenPort"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
PostUpScript string `json:"postUpScript"`
|
||||
PostDownScript string `json:"postDownScript"`
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
SubnetRange string `json:"subnetRange"`
|
||||
IpAllocation []string `json:"ipAllocation"`
|
||||
AllowedIps []string `json:"allowedIps"`
|
||||
ExtraAllowedIps []string `json:"extraAllowedIps"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
UseServerDns int `json:"useServerDns"`
|
||||
Keys struct {
|
||||
PresharedKey string `json:"presharedKey"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
} `json:"keys"`
|
||||
Enabled int `json:"enabled"`
|
||||
OfflineMonitoring int `json:"offlineMonitoring"`
|
||||
}
|
||||
|
@ -22,3 +22,16 @@ type Client struct {
|
||||
func (Client) TableName() string {
|
||||
return "t_client"
|
||||
}
|
||||
|
||||
// Watcher
|
||||
// @description: 监听日志
|
||||
type Watcher struct {
|
||||
Base
|
||||
ClientId string `json:"clientId" gorm:"type:char(36);not null;comment:'客户端id'"`
|
||||
NotifyResult string `json:"notifyResult" gorm:"type:text;default null;comment:'通知结果'"`
|
||||
IsSend int `json:"isSend" gorm:"type:tinyint(1);default 0;comment:'是否已通知'"`
|
||||
}
|
||||
|
||||
func (Watcher) TableName() string {
|
||||
return "t_watcher"
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
gdb "wireguard-ui/global/client"
|
||||
"wireguard-ui/http/vo"
|
||||
"wireguard-ui/model"
|
||||
@ -84,3 +85,60 @@ func (s setting) GetAllSetting(blackList []string) (data []vo.SettingItem, err e
|
||||
err = s.Model(&model.Setting{}).Select("code, data, describe").Where("code not in ?", blackList).Find(&data).Error
|
||||
return
|
||||
}
|
||||
|
||||
// Export
|
||||
// @description: 导出
|
||||
// @receiver s
|
||||
// @return data
|
||||
// @return err
|
||||
func (s setting) Export() (data vo.Export, err error) {
|
||||
// 先查询global配置
|
||||
var gs, ss *model.Setting
|
||||
if err = s.Model(&model.Setting{}).Where("code = ?", "WG_SETTING").Take(&gs).Error; err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal([]byte(gs.Data), &data.Global); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 查询server配置
|
||||
if err = s.Model(&model.Setting{}).Where("code = ?", "WG_SERVER").Take(&ss).Error; err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal([]byte(ss.Data), &data.Server); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 查询client配置
|
||||
var clients []vo.ClientItem
|
||||
if err = s.Model(&model.Client{}).Select("id,name,email,ip_allocation as ip_allocation_str," +
|
||||
"allowed_ips as allowed_ips_str,extra_allowed_ips as extra_allowed_ips_str," +
|
||||
"endpoint,use_server_dns,keys as keys_str," +
|
||||
"enabled,offline_monitoring").Order("created_at DESC").Find(&clients).Error; err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i, v := range clients {
|
||||
if v.KeysStr != "" {
|
||||
_ = json.Unmarshal([]byte(v.KeysStr), &clients[i].Keys)
|
||||
}
|
||||
if v.IpAllocationStr != "" {
|
||||
clients[i].IpAllocation = strings.Split(v.IpAllocationStr, ",")
|
||||
}
|
||||
if v.AllowedIpsStr != "" {
|
||||
clients[i].AllowedIps = strings.Split(v.AllowedIpsStr, ",")
|
||||
} else {
|
||||
clients[i].AllowedIps = []string{}
|
||||
}
|
||||
if v.ExtraAllowedIpsStr != "" {
|
||||
clients[i].ExtraAllowedIps = strings.Split(v.ExtraAllowedIpsStr, ",")
|
||||
} else {
|
||||
clients[i].ExtraAllowedIps = []string{}
|
||||
}
|
||||
}
|
||||
|
||||
cj, _ := json.Marshal(clients)
|
||||
_ = json.Unmarshal(cj, &data.Clients)
|
||||
|
||||
return
|
||||
}
|
||||
|
28
utils/file.go
Normal file
28
utils/file.go
Normal file
@ -0,0 +1,28 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type fileUtils struct{}
|
||||
|
||||
func FileUtils() fileUtils {
|
||||
return fileUtils{}
|
||||
}
|
||||
|
||||
// GenerateFile
|
||||
// @description: 生成文件
|
||||
// @receiver fileUtils
|
||||
// @param filename 文件名称
|
||||
// @param content 文件内容
|
||||
// @return error
|
||||
func (fileUtils) GenerateFile(filename string, content []byte) (filepath string, err error) {
|
||||
path := "/tmp/"
|
||||
if os.Getenv("GIN_MODE") != "release" {
|
||||
path = "E:\\Workspace\\Go\\wireguard-ui\\template\\tmp\\"
|
||||
}
|
||||
filepath = fmt.Sprintf("%s%s", path, filename)
|
||||
err = os.WriteFile(filepath, content, 0777)
|
||||
return filepath, err
|
||||
}
|
5
web/src/api/setting.js
Normal file
5
web/src/api/setting.js
Normal file
@ -0,0 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
exportConfig: () => request.get('/setting/export'), // 获取当前登陆用户信息
|
||||
}
|
40
web/src/layout/components/header/components/Export.vue
Normal file
40
web/src/layout/components/header/components/Export.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<n-icon mr-20 size="18" style="cursor: pointer" @click="importConfig()">
|
||||
<icon-gg-import />
|
||||
</n-icon>
|
||||
<n-icon mr-20 size="18" style="cursor: pointer" @click="exportConfig()">
|
||||
<icon-ph-export-bold />
|
||||
</n-icon>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from '@/api/setting'
|
||||
// 导入
|
||||
function importConfig() {
|
||||
console.log('导入配置')
|
||||
}
|
||||
|
||||
// 导出
|
||||
function exportConfig() {
|
||||
$dialog.confirm({
|
||||
type: 'warning',
|
||||
title: '导出配置',
|
||||
content: `是否导出需要导出系统全部配置?`,
|
||||
async confirm() {
|
||||
api.exportConfig().then(response => {
|
||||
const blob = new Blob([JSON.stringify(response.data)], {
|
||||
type: "text/plain"
|
||||
});
|
||||
const link = document.createElement("a"); // 创建a标签
|
||||
link.download = "config.json"; // a标签添加属性
|
||||
link.style.display = "none";
|
||||
link.href = URL.createObjectURL(blob);
|
||||
document.body.appendChild(link);
|
||||
link.click(); // 执行下载
|
||||
URL.revokeObjectURL(link.href); // 释放url
|
||||
document.body.removeChild(link); // 释放标签
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
@ -3,7 +3,12 @@
|
||||
<MenuCollapse />
|
||||
<BreadCrumb ml-15 hidden sm:block />
|
||||
</div>
|
||||
<div ml-auto flex items-center>
|
||||
<div ml-auto flex items-center v-if="loginUser.account === 'admin'">
|
||||
<Export/>
|
||||
<FullScreen />
|
||||
<UserAvatar />
|
||||
</div>
|
||||
<div ml-auto flex items-center v-else>
|
||||
<FullScreen />
|
||||
<UserAvatar />
|
||||
</div>
|
||||
@ -14,4 +19,7 @@ import BreadCrumb from './components/BreadCrumb.vue'
|
||||
import MenuCollapse from './components/MenuCollapse.vue'
|
||||
import FullScreen from './components/FullScreen.vue'
|
||||
import UserAvatar from './components/UserAvatar.vue'
|
||||
import Export from './components/Export.vue'
|
||||
import { useUserStore } from '@/store'
|
||||
const loginUser = useUserStore()
|
||||
</script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user