mirror of
https://github.com/42wim/matterbridge.git
synced 2025-02-12 11:31:32 +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
|
||
|
|
||
|
}
|