|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/franela/goreq"
|
|
|
|
"github.com/goji/httpauth"
|
|
|
|
"github.com/urfave/cli"
|
|
|
|
)
|
|
|
|
|
|
|
|
func postForm(pathname string, data url.Values) (r JSONResponse, err error) {
|
|
|
|
resp, err := http.PostForm(cfg.Client.ServerURL+pathname, data)
|
|
|
|
if err != nil {
|
|
|
|
return r, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return r, err
|
|
|
|
}
|
|
|
|
err = json.Unmarshal(body, &r)
|
|
|
|
if err != nil {
|
|
|
|
return r, fmt.Errorf("POST %v %v", strconv.Quote(pathname), string(body))
|
|
|
|
}
|
|
|
|
return r, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionStartServer(c *cli.Context) error {
|
|
|
|
suv, hdlr, err := newSupervisorHandler()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
auth := cfg.Server.HttpAuth
|
|
|
|
if auth.Enabled {
|
|
|
|
hdlr = httpauth.SimpleBasicAuth(auth.User, auth.Password)(hdlr)
|
|
|
|
}
|
|
|
|
http.Handle("/", hdlr)
|
|
|
|
|
|
|
|
addr := cfg.Server.Addr
|
|
|
|
if c.Bool("foreground") {
|
|
|
|
suv.AutoStartPrograms()
|
|
|
|
log.Printf("server listen on %v", addr)
|
|
|
|
log.Fatal(http.ListenAndServe(addr, nil))
|
|
|
|
} else {
|
|
|
|
if checkServerStatus() == nil {
|
|
|
|
fmt.Println("server is already running")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
logPath := filepath.Join(defaultConfigDir, "gosuv.log")
|
|
|
|
logFd, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("create file %s failed: %v", logPath, err)
|
|
|
|
}
|
|
|
|
cmd := exec.Command(os.Args[0], "start-server", "-f")
|
|
|
|
cmd.Stdout = logFd
|
|
|
|
cmd.Stderr = logFd
|
|
|
|
err = cmd.Start()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case err = <-GoFunc(cmd.Wait):
|
|
|
|
log.Fatalf("server started failed, %v", err)
|
|
|
|
case <-time.After(200 * time.Millisecond):
|
|
|
|
showAddr := addr
|
|
|
|
if strings.HasPrefix(addr, ":") {
|
|
|
|
showAddr = "0.0.0.0" + addr
|
|
|
|
}
|
|
|
|
fmt.Printf("server started, listening on %s\n", showAddr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionStatus(c *cli.Context) error {
|
|
|
|
res, err := goreq.Request{
|
|
|
|
Uri: cfg.Client.ServerURL + "/api/programs",
|
|
|
|
}.Do()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
var programs = make([]struct {
|
|
|
|
Program Program `json:"program"`
|
|
|
|
Status string `json:"status"`
|
|
|
|
}, 0)
|
|
|
|
if err := res.Body.FromJsonTo(&programs); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
format := "%-23s\t%-8s\n"
|
|
|
|
fmt.Printf(format, "PROGRAM NAME", "STATUS")
|
|
|
|
for _, p := range programs {
|
|
|
|
fmt.Printf(format, p.Program.Name, p.Status)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// cmd: <start|stop>
|
|
|
|
func programOperate(cmd, name string) (err error, success bool) {
|
|
|
|
res, err := goreq.Request{
|
|
|
|
Method: "POST",
|
|
|
|
Uri: cfg.Client.ServerURL + "/api/programs/" + name + "/" + cmd,
|
|
|
|
}.Do()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var v = struct {
|
|
|
|
Status int `json:"status"`
|
|
|
|
}{}
|
|
|
|
if err = res.Body.FromJsonTo(&v); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
success = v.Status == 0
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionStart(c *cli.Context) (err error) {
|
|
|
|
name := c.Args().First()
|
|
|
|
err, success := programOperate("start", name)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if success {
|
|
|
|
fmt.Println("Started")
|
|
|
|
} else {
|
|
|
|
fmt.Println("Start failed")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionStop(c *cli.Context) (err error) {
|
|
|
|
name := c.Args().First()
|
|
|
|
err, success := programOperate("stop", name)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !success {
|
|
|
|
fmt.Println("Stop failed")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionShutdown(c *cli.Context) error {
|
|
|
|
restart := c.Bool("restart")
|
|
|
|
if restart {
|
|
|
|
log.Fatal("Restart not implemented.")
|
|
|
|
}
|
|
|
|
ret, err := postForm("/api/shutdown", nil)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
fmt.Println(ret.Value)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionUpdateSelf(c *cli.Context) error {
|
|
|
|
return equinoxUpdate(c.String("channel"), c.Bool("yes"))
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionEdit(c *cli.Context) error {
|
|
|
|
cmd := exec.Command("vim", filepath.Join(os.Getenv("HOME"), ".gosuv/programs.yml"))
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
cmd.Stdin = os.Stdin
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
return cmd.Run()
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionVersion(c *cli.Context) error {
|
|
|
|
fmt.Printf("gosuv version %s\n", version)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionReload(c *cli.Context) error {
|
|
|
|
ret, err := postForm("/api/reload", nil)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
fmt.Println(ret.Value)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionConfigTest(c *cli.Context) error {
|
|
|
|
if _, _, err := newSupervisorHandler(); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
log.Println("test is successful")
|
|
|
|
return nil
|
|
|
|
}
|