mirror of
https://github.com/42wim/matterbridge.git
synced 2025-02-07 18:14:15 +01:00
261 lines
7.1 KiB
Go
261 lines
7.1 KiB
Go
package socketmode
|
|
|
|
import (
|
|
"context"
|
|
"github.com/slack-go/slack"
|
|
"github.com/slack-go/slack/slackevents"
|
|
)
|
|
|
|
type SocketmodeHandler struct {
|
|
Client *Client
|
|
|
|
//lvl 1 - the most generic type of event
|
|
EventMap map[EventType][]SocketmodeHandlerFunc
|
|
//lvl 2 - Manage event by inner type
|
|
InteractionEventMap map[slack.InteractionType][]SocketmodeHandlerFunc
|
|
EventApiMap map[slackevents.EventsAPIType][]SocketmodeHandlerFunc
|
|
//lvl 3 - the most userfriendly way of managing event
|
|
InteractionBlockActionEventMap map[string]SocketmodeHandlerFunc
|
|
SlashCommandMap map[string]SocketmodeHandlerFunc
|
|
|
|
Default SocketmodeHandlerFunc
|
|
}
|
|
|
|
// Handler have access to the event and socketmode client
|
|
type SocketmodeHandlerFunc func(*Event, *Client)
|
|
|
|
// Middleware accept SocketmodeHandlerFunc, and return SocketmodeHandlerFunc
|
|
type SocketmodeMiddlewareFunc func(SocketmodeHandlerFunc) SocketmodeHandlerFunc
|
|
|
|
// Initialization constructor for SocketmodeHandler
|
|
func NewSocketmodeHandler(client *Client) *SocketmodeHandler {
|
|
eventMap := make(map[EventType][]SocketmodeHandlerFunc)
|
|
interactionEventMap := make(map[slack.InteractionType][]SocketmodeHandlerFunc)
|
|
eventApiMap := make(map[slackevents.EventsAPIType][]SocketmodeHandlerFunc)
|
|
|
|
interactionBlockActionEventMap := make(map[string]SocketmodeHandlerFunc)
|
|
slackCommandMap := make(map[string]SocketmodeHandlerFunc)
|
|
|
|
return &SocketmodeHandler{
|
|
Client: client,
|
|
EventMap: eventMap,
|
|
EventApiMap: eventApiMap,
|
|
InteractionEventMap: interactionEventMap,
|
|
InteractionBlockActionEventMap: interactionBlockActionEventMap,
|
|
SlashCommandMap: slackCommandMap,
|
|
Default: func(e *Event, c *Client) {
|
|
c.log.Printf("Unexpected event type received: %v\n", e.Type)
|
|
},
|
|
}
|
|
}
|
|
|
|
// Register a middleware or handler for an Event from socketmode
|
|
// This most general entrypoint
|
|
func (r *SocketmodeHandler) Handle(et EventType, f SocketmodeHandlerFunc) {
|
|
r.EventMap[et] = append(r.EventMap[et], f)
|
|
}
|
|
|
|
// Register a middleware or handler for an Interaction
|
|
// There is several types of interactions, decated functions lets you better handle them
|
|
// See
|
|
// * HandleInteractionBlockAction
|
|
// * (Not Implemented) HandleShortcut
|
|
// * (Not Implemented) HandleView
|
|
func (r *SocketmodeHandler) HandleInteraction(et slack.InteractionType, f SocketmodeHandlerFunc) {
|
|
r.InteractionEventMap[et] = append(r.InteractionEventMap[et], f)
|
|
}
|
|
|
|
// Register a middleware or handler for a Block Action referenced by its ActionID
|
|
func (r *SocketmodeHandler) HandleInteractionBlockAction(actionID string, f SocketmodeHandlerFunc) {
|
|
if actionID == "" {
|
|
panic("invalid command cannot be empty")
|
|
}
|
|
if f == nil {
|
|
panic("invalid handler cannot be nil")
|
|
}
|
|
if _, exist := r.InteractionBlockActionEventMap[actionID]; exist {
|
|
panic("multiple registrations for actionID" + actionID)
|
|
}
|
|
r.InteractionBlockActionEventMap[actionID] = f
|
|
}
|
|
|
|
// Register a middleware or handler for an Event (from slackevents)
|
|
func (r *SocketmodeHandler) HandleEvents(et slackevents.EventsAPIType, f SocketmodeHandlerFunc) {
|
|
r.EventApiMap[et] = append(r.EventApiMap[et], f)
|
|
}
|
|
|
|
// Register a middleware or handler for a Slash Command
|
|
func (r *SocketmodeHandler) HandleSlashCommand(command string, f SocketmodeHandlerFunc) {
|
|
if command == "" {
|
|
panic("invalid command cannot be empty")
|
|
}
|
|
if f == nil {
|
|
panic("invalid handler cannot be nil")
|
|
}
|
|
if _, exist := r.SlashCommandMap[command]; exist {
|
|
panic("multiple registrations for command" + command)
|
|
}
|
|
r.SlashCommandMap[command] = f
|
|
}
|
|
|
|
// Register a middleware or handler to use as a last resort
|
|
func (r *SocketmodeHandler) HandleDefault(f SocketmodeHandlerFunc) {
|
|
r.Default = f
|
|
}
|
|
|
|
// RunSlackEventLoop receives the event via the socket
|
|
func (r *SocketmodeHandler) RunEventLoop() error {
|
|
|
|
go r.runEventLoop(context.Background())
|
|
|
|
return r.Client.Run()
|
|
}
|
|
|
|
func (r *SocketmodeHandler) RunEventLoopContext(ctx context.Context) error {
|
|
go r.runEventLoop(ctx)
|
|
|
|
return r.Client.RunContext(ctx)
|
|
}
|
|
|
|
// Call the dispatcher for each incomming event
|
|
func (r *SocketmodeHandler) runEventLoop(ctx context.Context) {
|
|
for {
|
|
select {
|
|
case evt, ok := <-r.Client.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
r.dispatcher(evt)
|
|
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dispatch events to the specialized dispatcher
|
|
func (r *SocketmodeHandler) dispatcher(evt Event) {
|
|
var ishandled bool
|
|
|
|
// Some eventType can be further decomposed
|
|
switch evt.Type {
|
|
case EventTypeInteractive:
|
|
ishandled = r.interactionDispatcher(&evt)
|
|
case EventTypeEventsAPI:
|
|
ishandled = r.eventAPIDispatcher(&evt)
|
|
case EventTypeSlashCommand:
|
|
ishandled = r.slashCommandDispatcher(&evt)
|
|
default:
|
|
ishandled = r.socketmodeDispatcher(&evt)
|
|
}
|
|
|
|
if !ishandled {
|
|
go r.Default(&evt, r.Client)
|
|
}
|
|
}
|
|
|
|
// Dispatch socketmode events to the registered middleware
|
|
func (r *SocketmodeHandler) socketmodeDispatcher(evt *Event) bool {
|
|
if handlers, ok := r.EventMap[evt.Type]; ok {
|
|
// If we registered an event
|
|
for _, f := range handlers {
|
|
go f(evt, r.Client)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Dispatch interactions to the registered middleware
|
|
func (r *SocketmodeHandler) interactionDispatcher(evt *Event) bool {
|
|
var ishandled bool = false
|
|
|
|
interaction, ok := evt.Data.(slack.InteractionCallback)
|
|
if !ok {
|
|
r.Client.log.Printf("Ignored %+v\n", evt)
|
|
return false
|
|
}
|
|
|
|
// Level 1 - socketmode EventType
|
|
ishandled = r.socketmodeDispatcher(evt)
|
|
|
|
// Level 2 - interaction EventType
|
|
if handlers, ok := r.InteractionEventMap[interaction.Type]; ok {
|
|
// If we registered an event
|
|
for _, f := range handlers {
|
|
go f(evt, r.Client)
|
|
}
|
|
|
|
ishandled = true
|
|
}
|
|
|
|
// Level 3 - interaction with actionID
|
|
blockActions := interaction.ActionCallback.BlockActions
|
|
// outmoded approach won`t be implemented
|
|
// attachments_actions := interaction.ActionCallback.AttachmentActions
|
|
|
|
for _, action := range blockActions {
|
|
if handler, ok := r.InteractionBlockActionEventMap[action.ActionID]; ok {
|
|
|
|
go handler(evt, r.Client)
|
|
|
|
ishandled = true
|
|
}
|
|
}
|
|
return ishandled
|
|
}
|
|
|
|
// Dispatch eventAPI events to the registered middleware
|
|
func (r *SocketmodeHandler) eventAPIDispatcher(evt *Event) bool {
|
|
var ishandled bool = false
|
|
eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent)
|
|
if !ok {
|
|
r.Client.log.Printf("Ignored %+v\n", evt)
|
|
return false
|
|
}
|
|
|
|
innerEventType := slackevents.EventsAPIType(eventsAPIEvent.InnerEvent.Type)
|
|
|
|
// Level 1 - socketmode EventType
|
|
ishandled = r.socketmodeDispatcher(evt)
|
|
|
|
// Level 2 - EventAPI EventType
|
|
if handlers, ok := r.EventApiMap[innerEventType]; ok {
|
|
// If we registered an event
|
|
for _, f := range handlers {
|
|
go f(evt, r.Client)
|
|
}
|
|
|
|
ishandled = true
|
|
}
|
|
|
|
return ishandled
|
|
}
|
|
|
|
// Dispatch SlashCommands events to the registered middleware
|
|
func (r *SocketmodeHandler) slashCommandDispatcher(evt *Event) bool {
|
|
var ishandled bool = false
|
|
slashCommandEvent, ok := evt.Data.(slack.SlashCommand)
|
|
if !ok {
|
|
r.Client.log.Printf("Ignored %+v\n", evt)
|
|
return false
|
|
}
|
|
|
|
// Level 1 - socketmode EventType
|
|
ishandled = r.socketmodeDispatcher(evt)
|
|
|
|
// Level 2 - SlackCommand by name
|
|
if handler, ok := r.SlashCommandMap[slashCommandEvent.Command]; ok {
|
|
|
|
go handler(evt, r.Client)
|
|
|
|
ishandled = true
|
|
}
|
|
|
|
return ishandled
|
|
|
|
}
|