mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-10-08 18:20:47 +08:00

grpcSimple包的服务端和客户端现在都已完成,且兼容v2ray等内核。 grpcSimple包 简洁、高效,更加科学。暂不支持multiMode。 若 grpc_full 给出,则使用grpc包,否则默认使用 grpcSimple包。 若 noquic给出,则不使用 quic,否则 默认使用 quic。 修复 ws early 失效问题;
782 lines
17 KiB
Go
782 lines
17 KiB
Go
package main
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"log"
|
||
"os"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"github.com/asaskevich/govalidator"
|
||
"github.com/e1732a364fed/v2ray_simple/netLayer"
|
||
"github.com/e1732a364fed/v2ray_simple/proxy"
|
||
"github.com/e1732a364fed/v2ray_simple/proxy/trojan"
|
||
"github.com/e1732a364fed/v2ray_simple/proxy/vless"
|
||
"github.com/e1732a364fed/v2ray_simple/tlsLayer"
|
||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||
"github.com/manifoldco/promptui"
|
||
)
|
||
|
||
var cliCmdList = []CliCmd{
|
||
{
|
||
"生成随机ssl证书", func() {
|
||
const certFn = "cert.pem"
|
||
const keyFn = "cert.key"
|
||
if utils.FileExist(certFn) {
|
||
fmt.Printf(certFn)
|
||
fmt.Printf(" 已存在!\n")
|
||
return
|
||
}
|
||
|
||
if utils.FileExist(keyFn) {
|
||
fmt.Printf(keyFn)
|
||
fmt.Printf(" 已存在!\n")
|
||
return
|
||
}
|
||
|
||
err := tlsLayer.GenerateRandomCertKeyFiles(certFn, keyFn)
|
||
if err == nil {
|
||
fmt.Printf("生成成功!请查看目录中的 ")
|
||
fmt.Printf(certFn)
|
||
fmt.Printf(" 和 ")
|
||
fmt.Printf(keyFn)
|
||
fmt.Printf("\n")
|
||
|
||
} else {
|
||
|
||
fmt.Printf("生成失败,")
|
||
fmt.Printf(err.Error())
|
||
fmt.Printf("\n")
|
||
|
||
}
|
||
},
|
||
},
|
||
}
|
||
|
||
func init() {
|
||
|
||
//cli.go 中定义的 CliCmd都是需进一步交互的命令
|
||
|
||
cliCmdList = append(cliCmdList, CliCmd{
|
||
"交互生成配置,超级强大", func() {
|
||
generateConfigFileInteractively()
|
||
},
|
||
})
|
||
cliCmdList = append(cliCmdList, CliCmd{
|
||
"热删除配置", func() {
|
||
interactively_hotRemoveServerOrClient()
|
||
},
|
||
})
|
||
cliCmdList = append(cliCmdList, CliCmd{
|
||
"热加载新配置文件", func() {
|
||
interactively_hotLoadConfigFile()
|
||
},
|
||
})
|
||
cliCmdList = append(cliCmdList, CliCmd{
|
||
"调节日志等级", func() {
|
||
interactively_adjust_loglevel()
|
||
},
|
||
})
|
||
|
||
}
|
||
|
||
type CliCmd struct {
|
||
Name string
|
||
F func()
|
||
}
|
||
|
||
func (cc CliCmd) String() string {
|
||
return cc.Name
|
||
}
|
||
|
||
//交互式命令行用户界面
|
||
//
|
||
//阻塞,可按ctrl+C退出或回退到上一级
|
||
func runCli() {
|
||
defer func() {
|
||
fmt.Printf("Interactive Mode exited. \n")
|
||
if ce := utils.CanLogInfo("Interactive Mode exited"); ce != nil {
|
||
ce.Write()
|
||
}
|
||
}()
|
||
|
||
/*
|
||
langList := []string{"简体中文", "English"}
|
||
fmt.Printf("Welcome to Interactive Mode, please choose a Language \n")
|
||
Select := promptui.Select{
|
||
Label: "Select Language",
|
||
Items: langList,
|
||
}
|
||
|
||
_, result, err := Select.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("You choose %q\n", result)
|
||
|
||
if result != langList[0] {
|
||
fmt.Printf("Sorry, language not supported yet \n")
|
||
return
|
||
}
|
||
*/
|
||
|
||
for {
|
||
Select := promptui.Select{
|
||
Label: "请选择想执行的功能",
|
||
Items: cliCmdList,
|
||
}
|
||
|
||
i, result, err := Select.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你选择了 %s\n", result)
|
||
|
||
if f := cliCmdList[i].F; f != nil {
|
||
f()
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
func generateConfigFileInteractively() {
|
||
|
||
rootLevelList := []string{
|
||
"打印当前缓存的配置",
|
||
"开始交互生成配置",
|
||
"清除此次缓存的配置",
|
||
"将该缓存的配置写到文件(client.toml和 server.toml)",
|
||
"以该缓存的配置【生成客户端分享链接url】",
|
||
"将此次生成的配置投入运行(热加载)",
|
||
}
|
||
|
||
confClient := proxy.StandardConf{}
|
||
confServer := proxy.StandardConf{}
|
||
|
||
var clientStr, serverStr string
|
||
|
||
for {
|
||
Select := promptui.Select{
|
||
Label: "请选择想为你的配置文件做的事情",
|
||
Items: rootLevelList,
|
||
}
|
||
|
||
i, result, err := Select.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你选择了 %s\n", result)
|
||
|
||
generateConfStr := func() {
|
||
|
||
confClient.Route = []*netLayer.RuleConf{{
|
||
DialTag: "direct",
|
||
Domains: []string{"geosite:cn"},
|
||
}}
|
||
|
||
confClient.App = &proxy.AppConf{MyCountryISO_3166: "CN"}
|
||
|
||
clientStr, err = utils.GetPurgedTomlStr(confClient)
|
||
if err != nil {
|
||
log.Fatal(err)
|
||
}
|
||
|
||
serverStr, err = utils.GetPurgedTomlStr(confServer)
|
||
if err != nil {
|
||
log.Fatal(err)
|
||
}
|
||
}
|
||
|
||
switch i {
|
||
case 0: //print
|
||
|
||
generateConfStr()
|
||
|
||
fmt.Printf("#客户端配置\n")
|
||
fmt.Printf(clientStr)
|
||
fmt.Printf("\n")
|
||
|
||
fmt.Printf("#服务端配置\n")
|
||
fmt.Printf(serverStr)
|
||
fmt.Printf("\n")
|
||
|
||
case 2: //clear
|
||
confClient = proxy.StandardConf{}
|
||
confServer = proxy.StandardConf{}
|
||
clientStr = ""
|
||
serverStr = ""
|
||
case 3: //output
|
||
|
||
generateConfStr()
|
||
|
||
var clientFile *os.File
|
||
clientFile, err = os.OpenFile("client.toml", os.O_WRONLY|os.O_CREATE, 0666)
|
||
if err != nil {
|
||
fmt.Println("Can't create client.toml", err)
|
||
return
|
||
}
|
||
clientFile.WriteString(clientStr)
|
||
clientFile.Close()
|
||
|
||
var serverFile *os.File
|
||
serverFile, err = os.OpenFile("server.toml", os.O_WRONLY|os.O_CREATE, 0666)
|
||
if err != nil {
|
||
fmt.Println("Can't create server.toml", err)
|
||
return
|
||
}
|
||
serverFile.WriteString(serverStr)
|
||
serverFile.Close()
|
||
|
||
fmt.Println("生成成功!请查看文件")
|
||
case 4: //share url
|
||
if len(confClient.Dial) > 0 {
|
||
|
||
fmt.Println("生成的分享链接如下:")
|
||
|
||
for _, d := range confClient.Dial {
|
||
switch d.Protocol {
|
||
case vless.Name:
|
||
fmt.Println(vless.GenerateXrayShareURL(d))
|
||
|
||
case trojan.Name:
|
||
fmt.Println(trojan.GenerateOfficialDraftShareURL(d))
|
||
}
|
||
}
|
||
|
||
} else {
|
||
fmt.Println("请先进行配置")
|
||
|
||
}
|
||
case 5: //hot load
|
||
fmt.Println("因为本次同时生成了服务端和客户端配置, 请选择要热加载的是哪一个")
|
||
selectHot := promptui.Select{
|
||
Label: "加载客户端配置还是服务端配置?",
|
||
Items: []string{
|
||
"服务端",
|
||
"客户端",
|
||
},
|
||
}
|
||
ihot, result, err := selectHot.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你选择了 %s\n", result)
|
||
|
||
switch ihot {
|
||
case 0:
|
||
|
||
hotLoadDialConfForRuntime(confServer.Dial)
|
||
hotLoadListenConfForRuntime(confServer.Listen)
|
||
|
||
case 1:
|
||
hotLoadDialConfForRuntime(confClient.Dial)
|
||
hotLoadListenConfForRuntime(confClient.Listen)
|
||
}
|
||
|
||
fmt.Printf("加载成功!你可以回退(ctrl+c)到上级来使用 【查询当前状态】来查询新增的配置\n")
|
||
|
||
case 1: //interactively generate
|
||
|
||
select0 := promptui.Select{
|
||
Label: "【提醒】我们交互模式生成的配置都是直接带tls的,且客户端【默认使用utls】模拟chrome指纹",
|
||
Items: []string{"知道了"},
|
||
}
|
||
|
||
_, _, err := select0.Run()
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
select2 := promptui.Select{
|
||
Label: "请选择你客户端想监听的协议",
|
||
Items: []string{
|
||
"socks5",
|
||
"http",
|
||
},
|
||
}
|
||
i2, result, err := select2.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你选择了 %s\n", result)
|
||
|
||
if i2 < 2 {
|
||
confClient.Listen = append(confClient.Listen, &proxy.ListenConf{})
|
||
} else {
|
||
fmt.Printf("Prompt failed, werid input")
|
||
return
|
||
}
|
||
|
||
clientlisten := confClient.Listen[0]
|
||
clientlisten.Protocol = result
|
||
clientlisten.Tag = "my_" + result
|
||
|
||
var theInt int64
|
||
|
||
var canLowPort bool
|
||
validatePort := func(input string) error {
|
||
theInt, err = strconv.ParseInt(input, 10, 64)
|
||
if err != nil {
|
||
return errors.New("Invalid number")
|
||
}
|
||
if !canLowPort {
|
||
if theInt <= 1024 {
|
||
return errors.New("Invalid number")
|
||
}
|
||
}
|
||
if theInt > 65535 {
|
||
return errors.New("Invalid number")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
fmt.Printf("请输入你客户端想监听的端口\n")
|
||
|
||
promptPort := promptui.Prompt{
|
||
Label: "Port Number",
|
||
Validate: validatePort,
|
||
}
|
||
|
||
result, err = promptPort.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %d\n", theInt)
|
||
|
||
clientlisten.Port = int(theInt)
|
||
clientlisten.IP = "127.0.0.1"
|
||
|
||
select3 := promptui.Select{
|
||
Label: "请选择你客户端想拨号的协议(与服务端监听协议相同)",
|
||
Items: []string{
|
||
"vless",
|
||
"trojan",
|
||
},
|
||
}
|
||
i3, result, err := select3.Run()
|
||
|
||
if err != nil || i3 != 0 {
|
||
fmt.Println("Prompt failed ", err, i3)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你选择了 %s\n", result)
|
||
theProtocol := result
|
||
|
||
confClient.Dial = append(confClient.Dial, &proxy.DialConf{})
|
||
clientDial := confClient.Dial[0]
|
||
|
||
fmt.Printf("请输入你服务端想监听的端口\n")
|
||
canLowPort = true
|
||
|
||
result, err = promptPort.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %d\n", theInt)
|
||
|
||
clientDial.Port = int(theInt)
|
||
clientDial.Protocol = theProtocol
|
||
clientDial.TLS = true
|
||
clientDial.Tag = "my_proxy"
|
||
clientDial.Utls = true
|
||
|
||
select4 := promptui.Select{
|
||
Label: "请选择你客户端拨号想使用的高级层(与服务端监听的高级层相同)",
|
||
Items: []string{
|
||
"无",
|
||
"ws",
|
||
"grpc",
|
||
"quic",
|
||
},
|
||
}
|
||
i4, result, err := select4.Run()
|
||
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, i3)
|
||
return
|
||
}
|
||
|
||
switch i4 {
|
||
case 0:
|
||
default:
|
||
clientDial.AdvancedLayer = result
|
||
switch i4 {
|
||
case 1, 2:
|
||
clientlisten.Tag += "_" + result
|
||
promptPath := promptui.Prompt{
|
||
Label: "Path",
|
||
Validate: func(s string) error {
|
||
if result == "ws" && !strings.HasPrefix(s, "/") {
|
||
return errors.New("ws path must start with /")
|
||
}
|
||
return nil
|
||
},
|
||
}
|
||
|
||
result, err = promptPath.Run()
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, result)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %s\n", result)
|
||
|
||
clientDial.Path = result
|
||
|
||
}
|
||
}
|
||
|
||
fmt.Printf("请输入你服务端的ip\n")
|
||
|
||
promptIP := promptui.Prompt{
|
||
Label: "IP",
|
||
Validate: utils.WrapFuncForPromptUI(govalidator.IsIP),
|
||
}
|
||
|
||
result, err = promptIP.Run()
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, result)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %s\n", result)
|
||
|
||
clientDial.IP = result
|
||
|
||
fmt.Printf("请输入你服务端的域名\n")
|
||
|
||
promptDomain := promptui.Prompt{
|
||
Label: "域名",
|
||
Validate: func(s string) error { return nil }, //允许不设域名
|
||
}
|
||
|
||
result, err = promptDomain.Run()
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, result)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %s\n", result)
|
||
|
||
clientDial.Host = result
|
||
|
||
select5 := promptui.Select{
|
||
Label: "请选择uuid生成方式",
|
||
Items: []string{
|
||
"随机",
|
||
"手动输入(要保证你输入的是格式正确的uuid)",
|
||
},
|
||
}
|
||
i5, result, err := select5.Run()
|
||
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, i3)
|
||
return
|
||
}
|
||
if i5 == 0 {
|
||
uuid := utils.GenerateUUIDStr()
|
||
clientDial.Uuid = uuid
|
||
fmt.Println("随机生成的uuid为", uuid)
|
||
} else {
|
||
promptUUID := promptui.Prompt{
|
||
Label: "uuid",
|
||
Validate: utils.WrapFuncForPromptUI(govalidator.IsUUID),
|
||
}
|
||
|
||
result, err = promptUUID.Run()
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, result)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %s\n", result)
|
||
|
||
clientDial.Uuid = result
|
||
}
|
||
|
||
var serverListenStruct proxy.ListenConf
|
||
serverListenStruct.CommonConf = clientDial.CommonConf
|
||
serverListenStruct.IP = "0.0.0.0"
|
||
|
||
confServer.Listen = append(confServer.Listen, &serverListenStruct)
|
||
|
||
confServer.Dial = append(confServer.Dial, &proxy.DialConf{
|
||
CommonConf: proxy.CommonConf{
|
||
Protocol: "direct",
|
||
},
|
||
})
|
||
|
||
serverListen := confServer.Listen[0]
|
||
|
||
select6 := promptui.Select{
|
||
Label: "请配置服务端tls证书路径",
|
||
Items: []string{
|
||
"默认(cert.pem和cert.key),此时将自动开启 insecure",
|
||
"手动输入(要保证你输入的是正确的文件路径)",
|
||
},
|
||
}
|
||
i6, result, err := select6.Run()
|
||
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, i3)
|
||
return
|
||
}
|
||
if i6 == 0 {
|
||
serverListen.TLSCert = "cert.pem"
|
||
serverListen.TLSKey = "cert.key"
|
||
serverListen.Insecure = true
|
||
clientDial.Insecure = true
|
||
|
||
fmt.Printf("你选择了默认自签名证书, 这是不安全的, 我们不推荐. 所以自动生成证书这一步需要你一会再到交互模式里选择相应选项进行生成。 \n")
|
||
|
||
} else {
|
||
fmt.Printf("请输入 cert路径\n")
|
||
|
||
promptCPath := promptui.Prompt{
|
||
Label: "path",
|
||
Validate: utils.IsFilePath,
|
||
}
|
||
|
||
result, err = promptCPath.Run()
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, result)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %s\n", result)
|
||
|
||
serverListen.TLSCert = result
|
||
|
||
fmt.Printf("请输入 key 路径\n")
|
||
|
||
result, err = promptCPath.Run()
|
||
if err != nil {
|
||
fmt.Println("Prompt failed ", err, result)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %s\n", result)
|
||
|
||
serverListen.TLSKey = result
|
||
}
|
||
|
||
} // switch i case 1
|
||
} //for
|
||
}
|
||
|
||
//热删除配置
|
||
func interactively_hotRemoveServerOrClient() {
|
||
fmt.Printf("即将开始热删除配置步骤, 删除正在运行的配置可能有未知风险,谨慎操作\n")
|
||
fmt.Printf("【当前所有配置】为:\n")
|
||
fmt.Printf(delimiter)
|
||
printAllState(os.Stdout)
|
||
|
||
var items []string
|
||
if len(AllServers) > 0 {
|
||
items = append(items, "listen")
|
||
}
|
||
if len(AllClients) > 0 {
|
||
items = append(items, "dial")
|
||
}
|
||
|
||
Select := promptui.Select{
|
||
Label: "请选择你想删除的是dial还是listen",
|
||
Items: items,
|
||
}
|
||
|
||
i, result, err := Select.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
var will_delete_listen, will_delete_dial bool
|
||
|
||
var will_delete_index int
|
||
|
||
fmt.Printf("你选择了 %s\n", result)
|
||
switch i {
|
||
case 0:
|
||
will_delete_listen = true
|
||
case 1:
|
||
will_delete_dial = true
|
||
}
|
||
|
||
var theInt int64
|
||
|
||
if (will_delete_dial && len(AllClients) > 1) || (will_delete_listen && len(AllServers) > 1) {
|
||
|
||
validateFunc := func(input string) error {
|
||
theInt, err = strconv.ParseInt(input, 10, 64)
|
||
if err != nil || theInt < 0 {
|
||
return errors.New("Invalid number")
|
||
}
|
||
|
||
if will_delete_dial && int(theInt) >= len(AllClients) {
|
||
return errors.New("must with in len of dial array")
|
||
}
|
||
|
||
if will_delete_listen && int(theInt) >= len(AllServers) {
|
||
return errors.New("must with in len of listen array")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
fmt.Printf("请输入你想删除的序号\n")
|
||
|
||
promptIdx := promptui.Prompt{
|
||
Label: "序号",
|
||
Validate: validateFunc,
|
||
}
|
||
|
||
_, err = promptIdx.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %d\n", theInt)
|
||
|
||
}
|
||
|
||
will_delete_index = int(theInt)
|
||
|
||
if will_delete_dial {
|
||
AllClients[will_delete_index].Stop()
|
||
AllClients = utils.TrimSlice(AllClients, will_delete_index)
|
||
}
|
||
if will_delete_listen {
|
||
ListenerArray[will_delete_index].Close()
|
||
AllServers[will_delete_index].Stop()
|
||
|
||
AllServers = utils.TrimSlice(AllServers, will_delete_index)
|
||
ListenerArray = utils.TrimSlice(ListenerArray, will_delete_index)
|
||
|
||
}
|
||
|
||
fmt.Printf("删除成功!当前状态:\n")
|
||
fmt.Printf(delimiter)
|
||
printAllState(os.Stdout)
|
||
}
|
||
|
||
//热添加配置文件
|
||
func interactively_hotLoadConfigFile() {
|
||
fmt.Printf("即将开始热添加配置文件\n")
|
||
fmt.Printf("【注意】我们交互模式只支持热添加listen和dial, 对于dns/route/fallback的热增删, 请期待api server未来的实现.\n")
|
||
fmt.Printf("【当前所有配置】为:\n")
|
||
fmt.Printf(delimiter)
|
||
printAllState(os.Stdout)
|
||
|
||
fmt.Printf("请输入你想添加的文件名称\n")
|
||
|
||
promptFile := promptui.Prompt{
|
||
Label: "配置文件",
|
||
Validate: func(s string) error {
|
||
|
||
if err := utils.IsFilePath(s); err != nil {
|
||
return err
|
||
}
|
||
if !utils.FileExist(utils.GetFilePath(s)) {
|
||
return errors.New("文件不存在")
|
||
}
|
||
return nil
|
||
},
|
||
}
|
||
|
||
fpath, err := promptFile.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你输入了 %s\n", fpath)
|
||
|
||
standardConf, err = proxy.LoadTomlConfFile(fpath)
|
||
if err != nil {
|
||
|
||
log.Printf("can not load standard config file: %s\n", err)
|
||
return
|
||
}
|
||
|
||
//listen, dial, dns, route, fallbacks 这几项都可以选择性加载
|
||
|
||
//但是route和fallback的话,动态增删很麻烦,因为route/fallback可能配置相当多条;
|
||
|
||
//而dns的话,没法简单增删, 而是会覆盖。
|
||
|
||
//因此我们交互模式暂且只支持 listen和dial的热加载。 dns/route/fallback的热增删可以用apiServer实现.
|
||
|
||
//也就是说,理论上要写一个比较好的前端,才能妥善解决 复杂条目的热增删问题。
|
||
|
||
if len(standardConf.Dial) > 0 {
|
||
hotLoadDialConfForRuntime(standardConf.Dial)
|
||
|
||
}
|
||
|
||
if len(standardConf.Listen) > 0 {
|
||
hotLoadListenConfForRuntime(standardConf.Listen)
|
||
|
||
}
|
||
|
||
fmt.Printf("添加成功!当前状态:\n")
|
||
fmt.Printf(delimiter)
|
||
printAllState(os.Stdout)
|
||
}
|
||
|
||
func interactively_adjust_loglevel() {
|
||
fmt.Println("当前日志等级为:", utils.LogLevelStr(utils.LogLevel))
|
||
|
||
list := utils.LogLevelStrList()
|
||
Select := promptui.Select{
|
||
Label: "请选择你调节为点loglevel",
|
||
Items: list,
|
||
}
|
||
|
||
i, result, err := Select.Run()
|
||
|
||
if err != nil {
|
||
fmt.Printf("Prompt failed %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("你选择了 %s\n", result)
|
||
|
||
if i < len(list) && i >= 0 {
|
||
utils.LogLevel = i
|
||
utils.InitLog()
|
||
|
||
fmt.Printf("调节 日志等级完毕. 现在等级为\n")
|
||
fmt.Printf(list[i])
|
||
fmt.Printf("\n")
|
||
|
||
}
|
||
}
|