-
Notifications
You must be signed in to change notification settings - Fork 0
/
application.go
139 lines (124 loc) · 4.37 KB
/
application.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// This package contains the Slap framework for developing Slack Applications.
package slap
import (
"fmt"
"log/slog"
"net/http"
"os"
)
// A function taking a Slack teamID (workspace ID) that returns
// the workspace's bot token as a string.
// For a non-distributed app, simply return your bot token.
type BotTokenGetter func(teamID string) (string, error)
// Configuration options for the Slap Application
type Config struct {
// Required. Slap will overwrite the following POST routes:
// "POST /interactions", "POST /events",
// and "POST /commands".
Router *http.ServeMux
// Optional. Adds a path to the start of the Slack routes.
PathPrefix string
// Required. Method for fetching bot tokens
// for a workspace based on its team ID
BotToken BotTokenGetter
// Required. The Slack webhook signing secret for your app
SigningSecret string
// A logger for the Slap Application
Logger *slog.Logger
// A generic, ephemeral error message to send the user
// when a handler returns an error.
//
// Defaults to: "An error occurred".
ErrorMessage string
}
// A Slap Application.
type Application struct {
signingSecret string
botToken BotTokenGetter
errorMessage string
commands map[string]CommandHandler
blockActions map[string]BlockActionHandler
viewSubmissions map[string]ViewSubmissionHandler
events map[string]EventHandler
logger *slog.Logger
}
// Registers a slash command handler.
//
// Panics if the slash command has already been registered.
func (app *Application) RegisterCommand(command string, handler CommandHandler) {
_, ok := app.commands[command]
if ok {
panic(fmt.Sprintf("Command %v has already been registered", command))
}
app.commands[command] = handler
app.logger.Info("Registered Command", "command", command)
}
// Registers a block action handler.
//
// Panics if the actionID has already been registered.
func (app *Application) RegisterBlockAction(actionID string, handler BlockActionHandler) {
_, ok := app.blockActions[actionID]
if ok {
panic(fmt.Sprintf("Action ID %v has already been registered", actionID))
}
app.blockActions[actionID] = handler
app.logger.Info("Registered Block Action", "actionID", actionID)
}
// Registers a view submission handler.
//
// Panics if the callbackID has already been registered.
func (app *Application) RegisterViewSubmission(callbackID string, handler ViewSubmissionHandler) {
_, ok := app.viewSubmissions[callbackID]
if ok {
panic(fmt.Sprintf("View Callback ID %v has already been registered", callbackID))
}
app.viewSubmissions[callbackID] = handler
app.logger.Info("Registered View Callback", "callbackID", callbackID)
}
// Registers an EventAPI event handler for a subscribed event type.
//
// Panics if the eventType has already been registered.
func (app *Application) RegisterEventHandler(eventType string, handler EventHandler) {
_, ok := app.events[eventType]
if ok {
panic(fmt.Sprintf("Event Handler for type %v has already been registered", eventType))
}
app.events[eventType] = handler
app.logger.Info("Registered Event Handler", "eventType", eventType)
}
// Creates a new Applcation with an http.ServeMux.
func New(config Config) *Application {
if config.Router == nil {
panic("Missing http.ServeMux in slap.New")
}
if config.SigningSecret == "" {
panic("Missing Slack signing secret")
}
if config.BotToken == nil {
panic("Missing Slack bot token getter")
}
logger := config.Logger
if logger == nil {
logger = slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelError,
}))
}
errorMessage := config.ErrorMessage
if errorMessage == "" {
errorMessage = "An error occurred"
}
app := Application{
logger: logger,
botToken: config.BotToken,
signingSecret: config.SigningSecret,
errorMessage: errorMessage,
commands: make(map[string]CommandHandler),
blockActions: make(map[string]BlockActionHandler),
viewSubmissions: make(map[string]ViewSubmissionHandler),
events: make(map[string]EventHandler),
}
config.Router.HandleFunc(fmt.Sprintf("POST %v/commands", config.PathPrefix), app.validateSignature(app.handleCommand))
config.Router.HandleFunc(fmt.Sprintf("POST %v/interactions", config.PathPrefix), app.validateSignature(app.handleInteraction))
config.Router.HandleFunc(fmt.Sprintf("POST %v/events", config.PathPrefix), app.validateSignature(app.handleEvent))
return &app
}