diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index ded9dfb..439282e 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -116,39 +116,27 @@ func (d *Daemon) handleIpcConn(conn net.Conn) { rsp := ipc.Response{} switch req.Op { case ipc.OpPs: - rsp.Data = d.ptable.Ps() + rsp.Ps = d.ptable.Ps() case ipc.OpStop: - names, ok := req.Data.([]any) - if !ok { - rsp.Err = "not a []any" + if len(req.Names) == 0 { + d.ptable.StopAll() } else { - if len(names) == 0 { - d.ptable.StopAll() - } else { - for _, v := range names { - name, _ := v.(string) - if err := d.ptable.Stop(name); err != nil { - rsp.Err = err.Error() - } + for _, name := range req.Names { + if err := d.ptable.Stop(name); err != nil { + rsp.Err = err.Error() } } } case ipc.OpStart: - names, ok := req.Data.([]any) - if !ok { - rsp.Err = "not a []any" + if len(req.Names) == 0 { + if err := d.ptable.StartAll(); err != nil { + rsp.Err = err.Error() + } } else { - if len(names) == 0 { - if err := d.ptable.StartAll(); err != nil { + for _, name := range req.Names { + if err := d.ptable.Start(name); err != nil { rsp.Err = err.Error() } - } else { - for _, v := range names { - name, _ := v.(string) - if err := d.ptable.Start(name); err != nil { - rsp.Err = err.Error() - } - } } } default: diff --git a/internal/ipc/ipc.go b/internal/ipc/ipc.go index 0c44d27..7ea3f95 100644 --- a/internal/ipc/ipc.go +++ b/internal/ipc/ipc.go @@ -32,17 +32,22 @@ func (op Op) String() string { } type Request struct { - Op Op - Data any `json:",omitempty"` + Op Op + + // for start/stop + Names []string `json:",omitempty"` } type Response struct { - Err string - Data any `json:",omitempty"` + Err string + + // for ps + Ps []PsResult `json:",omitempty"` } type PsResult struct { Name string + Pid int Status string } @@ -54,25 +59,11 @@ func Ps() ([]PsResult, error) { if rsp.Err != "" { return nil, errors.New(rsp.Err) } - data, ok := rsp.Data.([]any) - if !ok { - return nil, errors.New("response data is not a slice") - } - res := make([]PsResult, 0, len(data)) - for _, v := range data { - vv, _ := v.(map[string]any) - name, _ := vv["Name"].(string) - status, _ := vv["Status"].(string) - res = append(res, PsResult{ - Name: name, - Status: status, - }) - } - return res, nil + return rsp.Ps, nil } func Stop(names ...string) error { - rsp, err := execRequest(Request{Op: OpStop, Data: names}) + rsp, err := execRequest(Request{Op: OpStop, Names: names}) if err != nil { return err } @@ -83,7 +74,7 @@ func Stop(names ...string) error { } func Start(names ...string) error { - rsp, err := execRequest(Request{Op: OpStart, Data: names}) + rsp, err := execRequest(Request{Op: OpStart, Names: names}) if err != nil { return err } diff --git a/internal/ipc/ipc_test.go b/internal/ipc/ipc_test.go index 4e18908..4052266 100644 --- a/internal/ipc/ipc_test.go +++ b/internal/ipc/ipc_test.go @@ -77,20 +77,6 @@ func TestPs(t *testing.T) { } }) - t.Run("RspWithWrongDataType", func(t *testing.T) { - started := make(chan struct{}) - done := make(chan struct{}) - - go fakeDaemon(started, done, Response{Data: "dummy"}) - - <-started - defer func() { <-done }() - - if _, err := Ps(); err == nil { - t.Fatal("expected error") - } - }) - t.Run("Ok", func(t *testing.T) { started := make(chan struct{}) done := make(chan struct{}) @@ -100,7 +86,7 @@ func TestPs(t *testing.T) { {Name: "b", Status: "y"}, } - go fakeDaemon(started, done, Response{Data: expected}) + go fakeDaemon(started, done, Response{Ps: expected}) <-started defer func() { <-done }() @@ -115,8 +101,8 @@ func TestPs(t *testing.T) { return fmt.Errorf("different len: %d %d", len(result), len(expected)) } for i := range result { - if result[i] != expected[i] { - return fmt.Errorf("different element at index %d: %s %s", i, result[i], expected[i]) + if err := psResultEqual(result[i], expected[i]); err != nil { + return fmt.Errorf("different element at index %d: %w", i, err) } } return nil @@ -128,6 +114,19 @@ func TestPs(t *testing.T) { }) } +func psResultEqual(l, r PsResult) error { + if l.Name != r.Name { + return fmt.Errorf("different name: %s %s", l.Name, r.Name) + } + if l.Status != r.Status { + return fmt.Errorf("different status: %s %s", l.Status, r.Status) + } + if l.Pid != r.Pid { + return fmt.Errorf("different pid: %d %d", l.Pid, r.Pid) + } + return nil +} + func TestStop(t *testing.T) { started := make(chan struct{}) done := make(chan struct{}) diff --git a/internal/process/process.go b/internal/process/process.go index 0a0a68e..12d8da0 100644 --- a/internal/process/process.go +++ b/internal/process/process.go @@ -48,6 +48,7 @@ type Process struct { } func (p *Process) UpdateState() { + p.State = Failed if p.Cmd == nil { return } @@ -55,7 +56,7 @@ func (p *Process) UpdateState() { return } ps := p.Cmd.ProcessState - p.State = Failed + p.Cmd = nil if ps.Success() { p.State = Finished return @@ -63,7 +64,7 @@ func (p *Process) UpdateState() { ws, _ := ps.Sys().(syscall.WaitStatus) if ws.Signaled() { sig := ws.Signal() - if sig == syscall.SIGTERM || sig == syscall.SIGINT { + if sig == syscall.SIGTERM || sig == syscall.SIGINT || sig == syscall.SIGKILL { p.State = Stopped } } @@ -76,9 +77,10 @@ func (p *Process) Stop() { if p.State != Running { return } - if err := p.Cmd.Process.Kill(); err != nil { + if err := p.Cmd.Process.Signal(syscall.SIGTERM); err != nil { fmt.Printf("[daemon] failed to kill [%s]: %v\n", p.Name, err) } + // TODO: this may not actually kill it => wait to see if it stopped then send SIGKILL } type Table struct { @@ -213,9 +215,14 @@ func (t *Table) Ps() []ipc.PsResult { defer t.mu.Unlock() var result []ipc.PsResult for _, p := range t.procs { + pid := -1 + if p.Cmd != nil && p.Cmd.Process != nil { + pid = p.Cmd.Process.Pid + } result = append(result, ipc.PsResult{ Name: p.Name, Status: p.State.String(), + Pid: pid, }) } return result diff --git a/main.go b/main.go index 838ed21..cafcfbe 100644 --- a/main.go +++ b/main.go @@ -144,11 +144,11 @@ Options: w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0) defer w.Flush() - fmt.Fprintf(w, "Name\tStatus\n") - fmt.Fprintf(w, "----\t-------\n") + fmt.Fprintf(w, "Name\tPID\tStatus\n") + fmt.Fprintf(w, "----\t---\t-------\n") for _, s := range services { - fmt.Fprintf(w, "%s\t%s\n", s.Name, s.Status) + fmt.Fprintf(w, "%s\t%d\t%s\n", s.Name, s.Pid, s.Status) } return nil