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