wireguard-dashboard/cli/tui/setting.go
2024-12-24 16:35:57 +08:00

441 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package tui
import (
"encoding/json"
"fmt"
"github.com/charmbracelet/bubbles/table"
"github.com/eiannone/keyboard"
"github.com/spf13/cast"
"strings"
"wireguard-ui/http/vo"
"wireguard-ui/model"
"wireguard-ui/service"
"wireguard-ui/utils"
)
type SettingComponent struct {
LoginUser *vo.User
Menu []string
Other *OtherSettingComponent
}
func NewSettingComponent(loginUser *vo.User) *SettingComponent {
return &SettingComponent{
LoginUser: loginUser,
Menu: []string{"[1] 服务端配置", "[2] 全局设置", "[3] 其他配置", "[q] 返回上一级菜单"},
Other: NewOtherSettingComponent(),
}
}
// Menus
// @description: 设置菜单
// @receiver s
func (s *SettingComponent) Menus() {
fmt.Println("")
for _, r := range s.Menu {
fmt.Println(" -> " + r)
}
chooseMenu := readInput("\n请选择: ")
switch chooseMenu {
case "1":
s.ServerSetting()
case "2":
s.GlobalSetting()
case "3":
s.Other.Menus(s)
case "q":
return
}
}
// ServerSetting
// @description: 服务端配置
// @receiver s
func (s *SettingComponent) ServerSetting() {
fmt.Println("\n服务端配置")
// 先读取一下服务端配置
servConf, err := service.Setting().GetByCode("WG_SERVER")
if err != nil {
fmt.Println("获取服务端配置失败: ", err)
return
}
type serverConf 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"`
}
// 解析出来好渲染
var conf serverConf
if err = json.Unmarshal([]byte(servConf.Data), &conf); err != nil {
fmt.Println("解析服务端配置失败: ", err)
return
}
ipScopeIn := readInput(fmt.Sprintf("请输入IP段多个采用 ',[英文逗号]' 分割,不填写默认当前值,下同,当前值[%s] ", strings.Replace(strings.Join(conf.IpScope, ","), " ", "", -1)))
listenPortIn := readInput(fmt.Sprintf("请输入监听端口,当前值[%d] ", conf.ListenPort))
privateKeyIn := readInput(fmt.Sprintf("请输入私钥,当前值[%s] ", conf.PrivateKey))
publicKeyIn := readInput(fmt.Sprintf("请输入公钥,当前值[%s] ", conf.PublicKey))
postUpScriptIn := readInput(fmt.Sprintf("请输入PostUp脚本当前值[%s] ", conf.PostUpScript))
postDownScriptIn := readInput(fmt.Sprintf("请输入PostDown脚本当前值[%s] ", conf.PostDownScript))
if ipScopeIn != "" {
conf.IpScope = strings.Split(ipScopeIn, ",")
}
if listenPortIn != "" {
conf.ListenPort = cast.ToInt(listenPortIn)
}
if privateKeyIn != "" {
conf.PrivateKey = privateKeyIn
}
if publicKeyIn != "" {
conf.PublicKey = publicKeyIn
}
if postUpScriptIn != "" {
conf.PostUpScript = postUpScriptIn
}
if postDownScriptIn != "" {
conf.PostDownScript = postDownScriptIn
}
data, _ := json.Marshal(conf)
if err := service.Setting().SetData(&model.Setting{
Code: "WG_SERVER",
Data: string(data),
}); err != nil {
fmt.Println("保存服务端配置失败: ", err)
return
}
fmt.Println("修改服务端配置成功")
return
}
// GlobalSetting
// @description: 全局设置
// @receiver s
func (s *SettingComponent) GlobalSetting() {
fmt.Println("\n服务端配置")
// 先读取一下服务端配置
globalConf, err := service.Setting().GetByCode("WG_SETTING")
if err != nil {
fmt.Println("获取服务端配置失败: ", err)
return
}
type gConf 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"`
}
// 解析出来好渲染
var conf gConf
if err = json.Unmarshal([]byte(globalConf.Data), &conf); err != nil {
fmt.Println("解析全局配置失败: ", err)
return
}
mtu := readInput(fmt.Sprintf("请输入mtu不填写默认当前值下同当前值[%d] ", conf.MTU))
configFilePath := readInput(fmt.Sprintf("请输入配置文件地址,当前值[%s] ", conf.ConfigFilePath))
dnsServer := readInput(fmt.Sprintf("请输入dns多个采用 ',[英文逗号]' 分割,当前值[%s] ", strings.Replace(strings.Join(conf.DnsServer, ","), " ", "", -1)))
endpointAddress := readInput(fmt.Sprintf("请输入公网IP默认系统自动获取当前值[%s] ", conf.EndpointAddress))
firewallMark := readInput(fmt.Sprintf("请输入FirewallMark当前值[%s] ", conf.FirewallMark))
persistentKeepalive := readInput(fmt.Sprintf("请输入PersistentKeepalive当前值[%d] ", conf.PersistentKeepalive))
tableRule := readInput(fmt.Sprintf("请输入Table当前值[%s] ", conf.Table))
if mtu != "" {
conf.MTU = cast.ToInt(mtu)
}
if configFilePath != "" {
conf.ConfigFilePath = configFilePath
}
if dnsServer != "" {
conf.DnsServer = strings.Split(dnsServer, ",")
}
if endpointAddress != "" {
conf.EndpointAddress = endpointAddress
} else {
conf.EndpointAddress = utils.Network().GetHostPublicIP()
}
if firewallMark != "" {
conf.FirewallMark = firewallMark
}
if persistentKeepalive != "" {
conf.PersistentKeepalive = cast.ToInt(persistentKeepalive)
}
if tableRule != "" {
conf.Table = tableRule
}
data, _ := json.Marshal(conf)
if err := service.Setting().SetData(&model.Setting{
Code: "WG_SETTING",
Data: string(data),
}); err != nil {
fmt.Println("保存全局配置失败: ", err)
return
}
fmt.Println("修改全局配置成功")
return
}
// OtherSettingComponent
// @description: 其他配置杂项
type OtherSettingComponent struct {
Setting *SettingComponent
Menu []string
}
func NewOtherSettingComponent() *OtherSettingComponent {
return &OtherSettingComponent{
Menu: []string{"[1] 列表", "[2] 添加", "[3] 编辑", "[4] 删除", "[q] 返回上一级菜单"},
}
}
func (s *OtherSettingComponent) Menus(setting *SettingComponent) {
if s.Setting == nil {
s.Setting = setting
}
fmt.Println("")
for _, r := range s.Menu {
fmt.Println(" -> " + r)
}
chooseMenu := readInput("\n请选择: ")
switch chooseMenu {
case "1":
s.List(true)
case "2":
s.Add()
case "3":
s.Edit()
case "4":
s.Delete()
case "q":
s.Setting.Menus()
}
}
// List
// @description: 其他配置
// @receiver s
// @param showMenu
func (s *OtherSettingComponent) List(showMenu bool) {
fmt.Println("\n其他配置列表")
// 不查询的配置
var blackList = []string{"WG_SETTING", "WG_SERVER"}
data, err := service.Setting().GetAllSetting(blackList)
if err != nil {
fmt.Println("获取配置失败")
return
}
title := []table.Column{
{
Title: "序号",
Width: 10,
},
{
Title: "编码",
Width: 40,
},
{
Title: "描述",
Width: 50,
},
{
Title: "创建时间",
Width: 30,
},
{
Title: "更新时间",
Width: 30,
},
}
var result [][]string
for i, v := range data {
result = append(result, []string{
cast.ToString(i + 1),
v.Code,
v.Describe,
v.CreatedAt.Format("2006-01-02 15:04:05"),
v.UpdatedAt.Format("2006-01-02 15:04:05"),
})
}
Show(GenerateTable(title, result))
if showMenu {
s.Menus(nil)
}
}
// Add
// @description: 新增其他配置
// @receiver s
func (s *OtherSettingComponent) Add() {
fmt.Println("\n新增其他配置")
code := readInput("请输入配置编码,此编码是唯一编码不可重复:")
desc := readInput("请输入配置描述:")
// 监听键盘事件,只监听 + 和 - 和 enter
if err := keyboard.Open(); err != nil {
return
}
defer func() {
_ = keyboard.Close()
}()
// + <=> 43 | - <=> 45 | enter <=> 0
fmt.Println("请按下 + 或者 - 进行配置项的新增和删除")
fmt.Println("每一项配置如此: key=val ")
fmt.Println("确认输入完成后 enter[按一次代表当前配置项输入完成,两次代表新增完成]")
fmt.Println("首先进入时请输入 + 进行第一个配置项填写")
var breakCycle bool
var keyVal []string
for {
char, _, err := keyboard.GetKey()
if err != nil {
break
}
if breakCycle {
break
}
switch char {
case 0:
// 收到enter事件触发执行后面的
var dm = make(map[string]any)
for _, kv := range keyVal {
kvs := strings.Split(kv, "=")
key := kvs[0]
val := kvs[1]
dm[key] = val
}
dms, err := json.Marshal(dm)
if err != nil {
breakCycle = true
continue
}
if err = service.Setting().SetData(&model.Setting{
Code: code,
Data: string(dms),
Describe: desc,
}); err != nil {
breakCycle = true
fmt.Println("保存配置失败: ", err.Error())
continue
}
fmt.Println("保存配置成功")
s.List(true)
breakCycle = true
case 43:
keyVal = append(keyVal, readInput("请输入配置项:"))
case 45:
keyVal = keyVal[:len(keyVal)-1]
fmt.Println("已删除最后一个配置项,当前配置项为:", keyVal)
}
}
}
// Edit
// @description: 编辑
// @receiver s
func (s *OtherSettingComponent) Edit() {
fmt.Println("\n编辑其他配置")
s.List(false)
code := readInput("请输入需要编辑的配置编码:")
// 通过编码查询配置
setting, err := service.Setting().GetByCode(code)
if err != nil {
fmt.Println("查找["+code+"]配置失败:", err.Error())
return
}
desc := readInput("请输入需要编辑的配置描述:")
if desc != "" {
setting.Describe = desc
}
var kvm = make(map[string]any)
if err = json.Unmarshal([]byte(setting.Data), &kvm); err != nil {
fmt.Println("配置解析失败: ", err.Error())
return
}
for k, v := range kvm {
valIn := readInput(fmt.Sprintf("请输入配置项值,仅能修改值,当前键值对:%s=%v ", k, v))
if valIn != "" {
kvm[k] = valIn
}
}
// 处理以下数据
kvmStr, err := json.Marshal(kvm)
if err != nil {
fmt.Println("序列化数据失败: ", err.Error())
return
}
setting.Data = string(kvmStr)
if err = service.Setting().SetData(setting); err != nil {
fmt.Println("修改配置失败: ", err.Error())
return
}
fmt.Println("修改配置成功")
}
// Delete
// @description: 删除
// @receiver s
func (s *OtherSettingComponent) Delete() {
fmt.Println("\n 删除指定配置")
s.List(false)
code := readInput("请输入要删除的配置项编码:")
// 查询配置是否存在
if err := service.Setting().Model(&model.Setting{}).
Where("code NOT IN (?)", []string{"WG_SETTING", "WG_SERVER"}).
Where("code = ?", code).Delete(&model.Setting{}).Error; err != nil {
fmt.Println("删除[" + code + "]配置失败")
return
}
fmt.Println("删除成功")
s.List(true)
}