441 lines
11 KiB
Go
441 lines
11 KiB
Go
|
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)
|
|||
|
|
|||
|
}
|