From efe0e6af2282286b28413c2607fd0832c5eece10 Mon Sep 17 00:00:00 2001 From: Noah Hsu Date: Fri, 11 Nov 2022 18:42:06 +0800 Subject: [PATCH] feat: silent start, stop and restart --- .gitignore | 1 + cmd/common.go | 30 +++++++++++++++++++++ cmd/restart.go | 32 +++++++++++++++++++++++ cmd/start.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ cmd/stop.go | 58 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 cmd/restart.go create mode 100644 cmd/start.go create mode 100644 cmd/stop.go diff --git a/.gitignore b/.gitignore index 71ec18a5..e1825952 100644 --- a/.gitignore +++ b/.gitignore @@ -25,5 +25,6 @@ bin/* data/ log/ lang/ +daemon/ public/dist/* !public/dist/README.md \ No newline at end of file diff --git a/cmd/common.go b/cmd/common.go index 62a80c77..c80123df 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -1,8 +1,14 @@ package cmd import ( + "os" + "path/filepath" + "strconv" + "github.com/alist-org/alist/v3/internal/bootstrap" "github.com/alist-org/alist/v3/internal/bootstrap/data" + "github.com/alist-org/alist/v3/pkg/utils" + log "github.com/sirupsen/logrus" ) func Init() { @@ -11,3 +17,27 @@ func Init() { bootstrap.InitDB() data.InitData() } + +var pid = -1 +var pidFile string + +func initDaemon() { + ex, err := os.Executable() + if err != nil { + log.Fatal(err) + } + exPath := filepath.Dir(ex) + _ = os.MkdirAll(filepath.Join(exPath, "daemon"), 0700) + pidFile = filepath.Join(exPath, "daemon/pid") + if utils.Exists(pidFile) { + bytes, err := os.ReadFile(pidFile) + if err != nil { + log.Fatal("failed to read pid file", err) + } + id, err := strconv.Atoi(string(bytes)) + if err != nil { + log.Fatal("failed to parse pid data", err) + } + pid = id + } +} diff --git a/cmd/restart.go b/cmd/restart.go new file mode 100644 index 00000000..e798d7d8 --- /dev/null +++ b/cmd/restart.go @@ -0,0 +1,32 @@ +/* +Copyright © 2022 NAME HERE +*/ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// restartCmd represents the restart command +var restartCmd = &cobra.Command{ + Use: "restart", + Short: "Restart alist server by daemon/pid file", + Run: func(cmd *cobra.Command, args []string) { + stop() + start() + }, +} + +func init() { + rootCmd.AddCommand(restartCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // restartCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // restartCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/start.go b/cmd/start.go new file mode 100644 index 00000000..27af97ba --- /dev/null +++ b/cmd/start.go @@ -0,0 +1,71 @@ +/* +Copyright © 2022 NAME HERE +*/ +package cmd + +import ( + "os" + "os/exec" + "path/filepath" + "strconv" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +// startCmd represents the start command +var startCmd = &cobra.Command{ + Use: "start", + Short: "Silent start alist server with `--force-bin-dir`", + Run: func(cmd *cobra.Command, args []string) { + start() + }, +} + +func start() { + initDaemon() + if pid != -1 { + _, err := os.FindProcess(pid) + if err == nil { + log.Info("alist already started, pid ", pid) + return + } + } + args := os.Args + args[1] = "server" + args = append(args, "--force-bin-dir") + cmd := &exec.Cmd{ + Path: args[0], + Args: args, + Env: os.Environ(), + } + stdout, err := os.OpenFile(filepath.Join(filepath.Dir(pidFile), "start.log"), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) + if err != nil { + log.Fatal(os.Getpid(), ": failed to open start log file:", err) + } + cmd.Stderr = stdout + cmd.Stdout = stdout + err = cmd.Start() + if err != nil { + log.Fatal("failed to start children process: ", err) + } + log.Infof("success start pid: %d", cmd.Process.Pid) + err = os.WriteFile(pidFile, []byte(strconv.Itoa(cmd.Process.Pid)), 0666) + if err != nil { + log.Warn("failed to record pid, you may not be able to stop the program with `./alist stop`") + } +} + +func init() { + rootCmd.AddCommand(startCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // startCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // startCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/stop.go b/cmd/stop.go new file mode 100644 index 00000000..5cae3a55 --- /dev/null +++ b/cmd/stop.go @@ -0,0 +1,58 @@ +/* +Copyright © 2022 NAME HERE +*/ +package cmd + +import ( + "os" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +// stopCmd represents the stop command +var stopCmd = &cobra.Command{ + Use: "stop", + Short: "Stop alist server by daemon/pid file", + Run: func(cmd *cobra.Command, args []string) { + stop() + }, +} + +func stop() { + initDaemon() + if pid == -1 { + log.Info("Seems not have been started. Try use `alist start` to start server.") + return + } + process, err := os.FindProcess(pid) + if err != nil { + log.Errorf("failed to find process by pid: %d, reason: %v", pid, process) + return + } + err = process.Kill() + if err != nil { + log.Errorf("failed to kill process %d: %v", pid, err) + } else { + log.Info("killed process: ", pid) + } + err = os.Remove(pidFile) + if err != nil { + log.Errorf("failed to remove pid file") + } + pid = -1 +} + +func init() { + rootCmd.AddCommand(stopCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // stopCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // stopCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +}