service: Return the error rather than printing it

This enables callers to make the difference between a successful
service call and a failed one.
This commit is contained in:
delthas 2023-01-20 15:46:42 +01:00 committed by Simon Ser
parent f05bd84787
commit b920facdff
3 changed files with 37 additions and 36 deletions

View File

@ -2428,7 +2428,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
}) })
} }
if msg.Command == "PRIVMSG" { if msg.Command == "PRIVMSG" {
handleServicePRIVMSG(&serviceContext{ if err := handleServicePRIVMSG(&serviceContext{
Context: ctx, Context: ctx,
nick: dc.nick, nick: dc.nick,
network: dc.network, network: dc.network,
@ -2438,7 +2438,9 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
print: func(text string) { print: func(text string) {
sendServicePRIVMSG(dc, text) sendServicePRIVMSG(dc, text)
}, },
}, text) }, text); err != nil {
sendServicePRIVMSG(dc, fmt.Sprintf("error: %v", err))
}
} }
continue continue
} }

View File

@ -125,28 +125,24 @@ func splitWords(s string) ([]string, error) {
return words, nil return words, nil
} }
func handleServicePRIVMSG(ctx *serviceContext, text string) { func handleServicePRIVMSG(ctx *serviceContext, text string) error {
words, err := splitWords(text) words, err := splitWords(text)
if err != nil { if err != nil {
ctx.print(fmt.Sprintf(`error: failed to parse command: %v`, err)) return fmt.Errorf(`failed to parse command: %v`, err)
return
} }
handleServiceCommand(ctx, words) return handleServiceCommand(ctx, words)
} }
func handleServiceCommand(ctx *serviceContext, words []string) { func handleServiceCommand(ctx *serviceContext, words []string) error {
cmd, params, err := serviceCommands.Get(words) cmd, params, err := serviceCommands.Get(words)
if err != nil { if err != nil {
ctx.print(fmt.Sprintf(`error: %v (type "help" for a list of commands)`, err)) return fmt.Errorf(`%v (type "help" for a list of commands)`, err)
return
} }
if cmd.admin && !ctx.admin { if cmd.admin && !ctx.admin {
ctx.print("error: you must be an admin to use this command") return fmt.Errorf("you must be an admin to use this command")
return
} }
if !cmd.global && ctx.user == nil { if !cmd.global && ctx.user == nil {
ctx.print("error: this command must be run as a user (try running with user run)") return fmt.Errorf("this command must be run as a user (try running with user run)")
return
} }
if cmd.handle == nil { if cmd.handle == nil {
@ -154,7 +150,8 @@ func handleServiceCommand(ctx *serviceContext, words []string) {
var l []string var l []string
appendServiceCommandSetHelp(cmd.children, words, ctx.admin, ctx.user == nil, &l) appendServiceCommandSetHelp(cmd.children, words, ctx.admin, ctx.user == nil, &l)
ctx.print("available commands: " + strings.Join(l, ", ")) ctx.print("available commands: " + strings.Join(l, ", "))
} else { return nil
}
// Pretend the command does not exist if it has neither children nor handler. // Pretend the command does not exist if it has neither children nor handler.
// This is obviously a bug but it is better to not die anyway. // This is obviously a bug but it is better to not die anyway.
var logger Logger var logger Logger
@ -164,14 +161,10 @@ func handleServiceCommand(ctx *serviceContext, words []string) {
logger = ctx.srv.Logger logger = ctx.srv.Logger
} }
logger.Printf("command without handler and subcommands invoked:", words[0]) logger.Printf("command without handler and subcommands invoked:", words[0])
ctx.print(fmt.Sprintf("command %q not found", words[0])) return fmt.Errorf("command %q not found", words[0])
}
return
} }
if err := cmd.handle(ctx, params); err != nil { return cmd.handle(ctx, params)
ctx.print(fmt.Sprintf("error: %v", err))
}
} }
func (cmds serviceCommandSet) Get(params []string) (*serviceCommand, []string, error) { func (cmds serviceCommandSet) Get(params []string) (*serviceCommand, []string, error) {
@ -1169,8 +1162,7 @@ func handleUserRun(ctx *serviceContext, params []string) error {
username := params[0] username := params[0]
params = params[1:] params = params[1:]
if ctx.user != nil && username == ctx.user.Username { if ctx.user != nil && username == ctx.user.Username {
handleServiceCommand(ctx, params) return handleServiceCommand(ctx, params)
return nil
} }
u := ctx.srv.getUser(username) u := ctx.srv.getUser(username)
@ -1179,9 +1171,11 @@ func handleUserRun(ctx *serviceContext, params []string) error {
} }
printCh := make(chan string, 1) printCh := make(chan string, 1)
retCh := make(chan error, 1)
ev := eventUserRun{ ev := eventUserRun{
params: params, params: params,
print: printCh, print: printCh,
ret: retCh,
} }
select { select {
case <-ctx.Done(): case <-ctx.Done():
@ -1199,13 +1193,14 @@ func handleUserRun(ctx *serviceContext, params []string) error {
// in case the event is never processed. // in case the event is never processed.
// TODO: Properly fix this condition by flushing the u.events queue // TODO: Properly fix this condition by flushing the u.events queue
// and running close(ev.print) in a defer // and running close(ev.print) in a defer
return nil return fmt.Errorf("timeout executing command")
case text, ok := <-printCh: case text, ok := <-printCh:
if !ok { if ok {
return nil
}
ctx.print(text) ctx.print(text)
} }
case ret := <-retCh:
return ret
}
} }
} }

View File

@ -87,6 +87,7 @@ type eventTryRegainNick struct {
type eventUserRun struct { type eventUserRun struct {
params []string params []string
print chan string print chan string
ret chan error
} }
type deliveredClientMap map[string]string // client name -> msg ID type deliveredClientMap map[string]string // client name -> msg ID
@ -808,7 +809,7 @@ func (u *user) run() {
e.uc.tryRegainNick(e.nick) e.uc.tryRegainNick(e.nick)
case eventUserRun: case eventUserRun:
ctx := context.TODO() ctx := context.TODO()
handleServiceCommand(&serviceContext{ err := handleServiceCommand(&serviceContext{
Context: ctx, Context: ctx,
user: u, user: u,
srv: u.srv, srv: u.srv,
@ -823,7 +824,10 @@ func (u *user) run() {
} }
}, },
}, e.params) }, e.params)
close(e.print) select {
case <-ctx.Done():
case e.ret <- err:
}
case eventStop: case eventStop:
for _, dc := range u.downstreamConns { for _, dc := range u.downstreamConns {
dc.Close() dc.Close()