🆕为实现数据迁移以及备份新增配置导出

This commit is contained in:
coward 2024-09-20 17:26:41 +08:00
parent c3ef51e87f
commit edaf9ba770
11 changed files with 247 additions and 3 deletions

View File

@ -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
View File

@ -0,0 +1 @@
package cron

View File

@ -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) {
}

View File

@ -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) // 导出配置文件
}
}

View File

@ -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"`
}

View File

@ -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"
}

View File

@ -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
View 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
View File

@ -0,0 +1,5 @@
import { request } from '@/utils'
export default {
exportConfig: () => request.get('/setting/export'), // 获取当前登陆用户信息
}

View 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>

View File

@ -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>