package service import ( "backend/logging" "encoding/json" "errors" "fmt" "github.com/gin-gonic/gin" "io/ioutil" "net/http" "os" "os/exec" "path" "path/filepath" "runtime" "strconv" "sync" ) type Command struct { Cmd string `json:"command"` } type ServerConf struct { ServerRoot string `json:"server_root"` TestUrl string `json:"test_url"` } func (s *ServerConf) binary() string { if runtime.GOOS == "windows" { return path.Join(s.ServerRoot, "library", "tophttpserver.exe") } else if runtime.GOOS == "linux" { return path.Join(s.ServerRoot, "bin", "tophttpserver") } return "" } type Server struct { mtx sync.Mutex file string db *DBManage cfg *ServerConf cmd map[string]func(*Server) error } func (s *Server) ServerRoot() string { return s.cfg.ServerRoot } func getPid(name string) int { var pid int files, err := ioutil.ReadDir("/proc") for _, f := range files { if !f.IsDir() { continue } pid, err = strconv.Atoi(f.Name()) // not process if err != nil { continue } data, err := ioutil.ReadFile(path.Join("/proc", f.Name(), "cmdline")) if err != nil { continue } if len(data) < 2 { continue } str := string(data[0: len(data)-1]) // cmdline has trialling '\0' (its NULL terminated c string) if str == name { return pid } } return -1 } func restart(s *Server) error { if runtime.GOOS == "windows" { return exec.Command("taskkill", "/f", "/im", "tophttpserver.exe").Run() } else if runtime.GOOS == "linux" { pid := getPid(s.cfg.binary()) if pid < 0 { return errors.New("can't find pid") } return exec.Command("kill", "-15", strconv.Itoa(pid)).Run() } return errors.New("platform not support") } func monitor(*Server) error { return nil } func NewServer(db *DBManage) *Server { exe, err := os.Executable() if err != nil { logging.Fatal("can't get current directory: %s", err) } file := filepath.Join(filepath.Dir(exe), "server.json") f, err := os.Open(file) if err != nil { f, err = os.OpenFile(file, os.O_CREATE | os.O_TRUNC, 00644) } if err == nil { f.Close() } return &Server{ mtx: sync.Mutex{}, file: file, db: db, cfg: new(ServerConf), cmd: map[string]func(*Server) error{ "restart": restart, "monitor": monitor, }, } } func (s *Server) Serve(c *gin.Context) { s.mtx.Lock() defer s.mtx.Unlock() var cmd Command err := c.BindJSON(&cmd) if err != nil { newError(c, -1, err.Error()) return } println("command", cmd.Cmd) fp, ok := s.cmd[cmd.Cmd] if !ok { newError(c, -1, fmt.Sprintf("bad request, no such command: %s", cmd.Cmd)) return } err = fp(s) if err != nil { newError(c, -1, err.Error()) return } newError(c, 0, "ok") } func (s *Server) Retrieve(c *gin.Context) { s.mtx.Lock() defer s.mtx.Unlock() data, err := ioutil.ReadFile(s.file) if err != nil { newError(c, -1, err.Error()) return } data = skipBom(data) if len(data) == 0 { data = []byte("{}") } err = json.Unmarshal(data, s.cfg) if err != nil { newError(c, -1, err.Error()) return } s.db.UpdateServerRoot(s.ServerRoot()) c.JSON(http.StatusOK, gin.H{ "code": 0, "data": s.cfg, "msg": "ok", }) } func (s *Server) update(c *gin.Context) error { data, err := ioutil.ReadAll(c.Request.Body) if err != nil { return err } err = json.Unmarshal(data, s.cfg) if err == nil { tmp, err := json.MarshalIndent(s.cfg, "", " ") if err == nil { data = tmp } } f, err := os.OpenFile(s.file, os.O_WRONLY | os.O_TRUNC, 00644) if err != nil { return err } defer f.Close() s.db.UpdateServerRoot(s.ServerRoot()) _, err = f.Write(data) return err } func (s *Server) Update(c *gin.Context) { s.mtx.Lock() defer s.mtx.Unlock() err := s.update(c) if err != nil { newError(c, -1, err.Error()) } else { newError(c, 0, "ok") } }