in internal/command/command_monitor.go [169:239]
func (c *Server) start(ctx context.Context) error {
if c.srv != nil {
return errors.New("server already listening")
}
galog.Debugf("Starting command server at %q", c.pipe)
srv, err := listen(ctx, c.pipe, c.pipeMode, c.pipeGroup)
if err != nil {
return err
}
go func() {
defer srv.Close()
for {
if ctx.Err() != nil {
return
}
conn, err := srv.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
break
}
galog.Errorf("error on connection to pipe %s: %v", c.pipe, err)
continue
}
go func(conn net.Conn) {
defer conn.Close()
// Go has lots of helpers to read json from an io.Reader but none of
// them return the byte slice afterwards and we need it for the handler.
deadline := time.Now().Add(c.timeout)
if err := conn.SetDeadline(deadline); err != nil {
galog.Errorf("could not set deadline on command request: %v", err)
return
}
message, ok := readOrError(conn)
if !ok {
return
}
var req Request
for err := json.Unmarshal(message, &req); err != nil; err = json.Unmarshal(message, &req) {
b, ok := readOrError(conn)
if !ok {
return
}
message = append(message, b...)
}
c.monitor.handlersMu.RLock()
defer c.monitor.handlersMu.RUnlock()
handler, ok := c.monitor.handlers[req.Command]
if !ok {
if b, err := json.Marshal(CmdNotFoundError); err != nil {
conn.Write(internalError)
} else {
conn.Write(b)
}
return
}
resp, err := handler(ctx, message)
if err != nil {
re := Response{Status: HandlerError.Status, StatusMessage: err.Error()}
if b, err := json.Marshal(re); err != nil {
resp = internalError
} else {
resp = b
}
}
conn.Write(resp)
}(conn)
}
}()
c.srv = srv
return nil
}