implement Caller.AddTmp for temporary handlers
This commit is contained in:
parent
14091fe17f
commit
cdac81184a
63
handler.go
63
handler.go
@ -177,6 +177,8 @@ func (c *Caller) exec(command string, client *Client, event *Event) {
|
|||||||
stack = append(stack, execStack{c.internal[command][cuid], cuid})
|
stack = append(stack, execStack{c.internal[command][cuid], cuid})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
c.debug.Printf("not executing internal callbacks for event %s, due to event not having a source", command)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aaand then external handlers.
|
// Aaand then external handlers.
|
||||||
@ -244,7 +246,7 @@ func (c *Caller) Clear(cmd string) {
|
|||||||
}
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
c.debug.Printf("cleared external handlers for %q", cmd)
|
c.debug.Printf("cleared external handlers for %s", cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the handler with cuid from the handler stack. success
|
// Remove removes the handler with cuid from the handler stack. success
|
||||||
@ -277,8 +279,7 @@ func (c *Caller) remove(cuid string) (success bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete(c.external[cmd], uid)
|
delete(c.external[cmd], uid)
|
||||||
|
c.debug.Printf("removed handler %s", cuid)
|
||||||
c.debug.Printf("removed handler %q", cuid)
|
|
||||||
|
|
||||||
// Assume success.
|
// Assume success.
|
||||||
return true
|
return true
|
||||||
@ -345,7 +346,7 @@ func (c *Caller) AddBg(cmd string, handler func(client *Client, event Event)) (c
|
|||||||
go func() {
|
go func() {
|
||||||
// If they want to catch any panics, add to defer stack.
|
// If they want to catch any panics, add to defer stack.
|
||||||
if client.Config.RecoverFunc != nil {
|
if client.Config.RecoverFunc != nil {
|
||||||
defer recoverHandlerPanic(client, &event, "unknown-goroutine", 3)
|
defer recoverHandlerPanic(client, &event, "goroutine", 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler(client, event)
|
handler(client, event)
|
||||||
@ -353,6 +354,58 @@ func (c *Caller) AddBg(cmd string, handler func(client *Client, event Event)) (c
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddTmp adds a "temporary" handler, which is good for one-time or few-time
|
||||||
|
// uses. This supports a deadline and/or manual removal, as this differs
|
||||||
|
// much from how normal handlers work. An example of a good use for this
|
||||||
|
// would be to capture the entire output of a multi-response query to the
|
||||||
|
// server. (e.g. LIST, WHOIS, etc)
|
||||||
|
//
|
||||||
|
// The supplied handler is able to return a boolean, which if true, will
|
||||||
|
// remove the handler from the handler stack.
|
||||||
|
//
|
||||||
|
// Additionally, AddTmp has a useful option, deadline. When set to greater
|
||||||
|
// than 0, deadline will be the amount of time that passes before the handler
|
||||||
|
// is removed from the stack, regardless if the handler returns true or not.
|
||||||
|
// This is useful in that it ensures that the handler is cleaned up if the
|
||||||
|
// server does not respond appropriately, or takes too long to respond.
|
||||||
|
//
|
||||||
|
// Note that handlers supplied with AddTmp are executed in a goroutine to
|
||||||
|
// ensure that they are not blocking other handlers. Additionally, use cuid
|
||||||
|
// with Caller.Remove() to prematurely remove the handler from the stack,
|
||||||
|
// bypassing the timeout or waiting for the handler to return that it wants
|
||||||
|
// to be removed from the stack.
|
||||||
|
func (c *Caller) AddTmp(cmd string, deadline time.Duration, handler func(client *Client, event Event) bool) (cuid string) {
|
||||||
|
var uid string
|
||||||
|
cuid, uid = c.cuid(cmd, 20)
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
c.external[cmd][uid] = HandlerFunc(func(client *Client, event Event) {
|
||||||
|
// Setting up background-based handlers this way allows us to get
|
||||||
|
// clean call stacks for use with panic recovery.
|
||||||
|
go func() {
|
||||||
|
// If they want to catch any panics, add to defer stack.
|
||||||
|
if client.Config.RecoverFunc != nil {
|
||||||
|
defer recoverHandlerPanic(client, &event, "tmp-goroutine", 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
remove := handler(client, event)
|
||||||
|
if remove {
|
||||||
|
c.Remove(cuid)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
if deadline > 0 {
|
||||||
|
go func() {
|
||||||
|
<-time.After(deadline)
|
||||||
|
c.Remove(cuid)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
return cuid
|
||||||
|
}
|
||||||
|
|
||||||
// recoverHandlerPanic is used to catch all handler panics, and re-route
|
// recoverHandlerPanic is used to catch all handler panics, and re-route
|
||||||
// them if necessary.
|
// them if necessary.
|
||||||
func recoverHandlerPanic(client *Client, event *Event, id string, skip int) {
|
func recoverHandlerPanic(client *Client, event *Event, id string, skip int) {
|
||||||
@ -399,7 +452,7 @@ type HandlerError struct {
|
|||||||
// line, and basic error string.
|
// line, and basic error string.
|
||||||
func (e *HandlerError) Error() string {
|
func (e *HandlerError) Error() string {
|
||||||
if e.callOk {
|
if e.callOk {
|
||||||
return fmt.Sprintf("panic during handler [%s] execution in %s (line %d): %s", e.ID, e.File, e.Line, e.Panic)
|
return fmt.Sprintf("panic during handler [%s] execution in %s:%d: %s", e.ID, e.File, e.Line, e.Panic)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("panic during handler [%s] execution in unknown: %s", e.ID, e.Panic)
|
return fmt.Sprintf("panic during handler [%s] execution in unknown: %s", e.ID, e.Panic)
|
||||||
|
Loading…
Reference in New Issue
Block a user