mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 13:10:26 +08:00 
			
		
		
		
	
		
			
	
	
		
			235 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			235 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								package apps
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"github.com/iwind/TeaGo/Tea"
							 | 
						||
| 
								 | 
							
									"github.com/iwind/TeaGo/logs"
							 | 
						||
| 
								 | 
							
									"os"
							 | 
						||
| 
								 | 
							
									"os/exec"
							 | 
						||
| 
								 | 
							
									"runtime"
							 | 
						||
| 
								 | 
							
									"strconv"
							 | 
						||
| 
								 | 
							
									"time"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// App命令帮助
							 | 
						||
| 
								 | 
							
								type AppCmd struct {
							 | 
						||
| 
								 | 
							
									product       string
							 | 
						||
| 
								 | 
							
									version       string
							 | 
						||
| 
								 | 
							
									usage         string
							 | 
						||
| 
								 | 
							
									options       []*CommandHelpOption
							 | 
						||
| 
								 | 
							
									appendStrings []string
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									directives []*Directive
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func NewAppCmd() *AppCmd {
							 | 
						||
| 
								 | 
							
									return &AppCmd{}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type CommandHelpOption struct {
							 | 
						||
| 
								 | 
							
									Code        string
							 | 
						||
| 
								 | 
							
									Description string
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 产品
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) Product(product string) *AppCmd {
							 | 
						||
| 
								 | 
							
									this.product = product
							 | 
						||
| 
								 | 
							
									return this
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 版本
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) Version(version string) *AppCmd {
							 | 
						||
| 
								 | 
							
									this.version = version
							 | 
						||
| 
								 | 
							
									return this
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 使用方法
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) Usage(usage string) *AppCmd {
							 | 
						||
| 
								 | 
							
									this.usage = usage
							 | 
						||
| 
								 | 
							
									return this
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 选项
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) Option(code string, description string) *AppCmd {
							 | 
						||
| 
								 | 
							
									this.options = append(this.options, &CommandHelpOption{
							 | 
						||
| 
								 | 
							
										Code:        code,
							 | 
						||
| 
								 | 
							
										Description: description,
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
									return this
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 附加内容
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) Append(appendString string) *AppCmd {
							 | 
						||
| 
								 | 
							
									this.appendStrings = append(this.appendStrings, appendString)
							 | 
						||
| 
								 | 
							
									return this
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 打印
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) Print() {
							 | 
						||
| 
								 | 
							
									fmt.Println(this.product + " v" + this.version)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									usage := this.usage
							 | 
						||
| 
								 | 
							
									fmt.Println("Usage:", "\n   "+usage)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if len(this.options) > 0 {
							 | 
						||
| 
								 | 
							
										fmt.Println("")
							 | 
						||
| 
								 | 
							
										fmt.Println("Options:")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										spaces := 20
							 | 
						||
| 
								 | 
							
										max := 40
							 | 
						||
| 
								 | 
							
										for _, option := range this.options {
							 | 
						||
| 
								 | 
							
											l := len(option.Code)
							 | 
						||
| 
								 | 
							
											if l < max && l > spaces {
							 | 
						||
| 
								 | 
							
												spaces = l + 4
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for _, option := range this.options {
							 | 
						||
| 
								 | 
							
											if len(option.Code) > max {
							 | 
						||
| 
								 | 
							
												fmt.Println("")
							 | 
						||
| 
								 | 
							
												fmt.Println("  " + option.Code)
							 | 
						||
| 
								 | 
							
												option.Code = ""
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											fmt.Printf("  %-"+strconv.Itoa(spaces)+"s%s\n", option.Code, ": "+option.Description)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if len(this.appendStrings) > 0 {
							 | 
						||
| 
								 | 
							
										fmt.Println("")
							 | 
						||
| 
								 | 
							
										for _, s := range this.appendStrings {
							 | 
						||
| 
								 | 
							
											fmt.Println(s)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 添加指令
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) On(arg string, callback func()) {
							 | 
						||
| 
								 | 
							
									this.directives = append(this.directives, &Directive{
							 | 
						||
| 
								 | 
							
										Arg:      arg,
							 | 
						||
| 
								 | 
							
										Callback: callback,
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 运行
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) Run(main func()) {
							 | 
						||
| 
								 | 
							
									// 获取参数
							 | 
						||
| 
								 | 
							
									args := os.Args[1:]
							 | 
						||
| 
								 | 
							
									if len(args) > 0 {
							 | 
						||
| 
								 | 
							
										switch args[0] {
							 | 
						||
| 
								 | 
							
										case "-v", "version", "-version", "--version":
							 | 
						||
| 
								 | 
							
											this.runVersion()
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										case "?", "help", "-help", "h", "-h":
							 | 
						||
| 
								 | 
							
											this.runHelp()
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										case "start":
							 | 
						||
| 
								 | 
							
											this.runStart()
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										case "stop":
							 | 
						||
| 
								 | 
							
											this.runStop()
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										case "restart":
							 | 
						||
| 
								 | 
							
											this.runRestart()
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										case "status":
							 | 
						||
| 
								 | 
							
											this.runStatus()
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// 查找指令
							 | 
						||
| 
								 | 
							
										for _, directive := range this.directives {
							 | 
						||
| 
								 | 
							
											if directive.Arg == args[0] {
							 | 
						||
| 
								 | 
							
												directive.Callback()
							 | 
						||
| 
								 | 
							
												return
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										fmt.Println("unknown command '" + args[0] + "'")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// 记录PID
							 | 
						||
| 
								 | 
							
									_ = this.writePid()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// 日志
							 | 
						||
| 
								 | 
							
									writer := new(LogWriter)
							 | 
						||
| 
								 | 
							
									writer.Init()
							 | 
						||
| 
								 | 
							
									logs.SetWriter(writer)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// 运行主函数
							 | 
						||
| 
								 | 
							
									main()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 版本号
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) runVersion() {
							 | 
						||
| 
								 | 
							
									fmt.Println(this.product+" v"+this.version, "(build: "+runtime.Version(), runtime.GOOS, runtime.GOARCH+")")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 帮助
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) runHelp() {
							 | 
						||
| 
								 | 
							
									this.Print()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 启动
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) runStart() {
							 | 
						||
| 
								 | 
							
									proc := this.checkPid()
							 | 
						||
| 
								 | 
							
									if proc != nil {
							 | 
						||
| 
								 | 
							
										fmt.Println(this.product+" already started, pid:", proc.Pid)
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									cmd := exec.Command(os.Args[0])
							 | 
						||
| 
								 | 
							
									err := cmd.Start()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										fmt.Println(this.product+"  start failed:", err.Error())
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									fmt.Println(this.product+" started ok, pid:", cmd.Process.Pid)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 停止
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) runStop() {
							 | 
						||
| 
								 | 
							
									proc := this.checkPid()
							 | 
						||
| 
								 | 
							
									if proc == nil {
							 | 
						||
| 
								 | 
							
										fmt.Println(this.product + " not started yet")
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// 停止进程
							 | 
						||
| 
								 | 
							
									_ = proc.Kill()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// 在Windows上经常不能及时释放资源
							 | 
						||
| 
								 | 
							
									_ = DeletePid(Tea.Root + "/bin/pid")
							 | 
						||
| 
								 | 
							
									fmt.Println(this.product+" stopped ok, pid:", proc.Pid)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 重启
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) runRestart() {
							 | 
						||
| 
								 | 
							
									this.runStop()
							 | 
						||
| 
								 | 
							
									time.Sleep(1 * time.Second)
							 | 
						||
| 
								 | 
							
									this.runStart()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 状态
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) runStatus() {
							 | 
						||
| 
								 | 
							
									proc := this.checkPid()
							 | 
						||
| 
								 | 
							
									if proc == nil {
							 | 
						||
| 
								 | 
							
										fmt.Println(this.product + " not started yet")
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										fmt.Println(this.product + " is running, pid: " + fmt.Sprintf("%d", proc.Pid))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 检查PID
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) checkPid() *os.Process {
							 | 
						||
| 
								 | 
							
									return CheckPid(Tea.Root + "/bin/pid")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 写入PID
							 | 
						||
| 
								 | 
							
								func (this *AppCmd) writePid() error {
							 | 
						||
| 
								 | 
							
									return WritePid(Tea.Root + "/bin/pid")
							 | 
						||
| 
								 | 
							
								}
							 |