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:
parent
f05bd84787
commit
b920facdff
@ -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
|
||||||
}
|
}
|
||||||
|
59
service.go
59
service.go
@ -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,24 +150,21 @@ 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.
|
|
||||||
// This is obviously a bug but it is better to not die anyway.
|
|
||||||
var logger Logger
|
|
||||||
if ctx.user != nil {
|
|
||||||
logger = ctx.user.logger
|
|
||||||
} else {
|
|
||||||
logger = ctx.srv.Logger
|
|
||||||
}
|
|
||||||
logger.Printf("command without handler and subcommands invoked:", words[0])
|
|
||||||
ctx.print(fmt.Sprintf("command %q not found", words[0]))
|
|
||||||
}
|
}
|
||||||
return
|
// 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.
|
||||||
|
var logger Logger
|
||||||
|
if ctx.user != nil {
|
||||||
|
logger = ctx.user.logger
|
||||||
|
} else {
|
||||||
|
logger = ctx.srv.Logger
|
||||||
|
}
|
||||||
|
logger.Printf("command without handler and subcommands invoked:", words[0])
|
||||||
|
return fmt.Errorf("command %q not found", words[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
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,12 +1193,13 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
user.go
8
user.go
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user