Created
July 15, 2019 12:10
-
-
Save k2wanko/4df5501da581b7370d148e6a7429ccdd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
Receiver, | |
ReceiverEvent, | |
ReceiverAckTimeoutError, | |
ExpressReceiverOptions, | |
} from '@slack/bolt' | |
import { ConsoleLogger } from '@slack/logger' | |
import { verifySignatureAndParseBody } from '@slack/bolt/dist/ExpressReceiver' | |
import express, { Application, RequestHandler, Request, Response, NextFunction } from 'express' | |
import axios from 'axios' | |
export class HTTPFunctionsReceiver implements Receiver { | |
public app: Application | |
private listenerMap = new Map<string | symbol, Array<Function> | undefined>() | |
constructor({ | |
signingSecret = '', | |
logger = new ConsoleLogger(), | |
endpoints = { events: '/slack/events' } | |
}: ExpressReceiverOptions) { | |
this.app = express() | |
this.app.use((err: any, req: Request, res: Response, next: NextFunction) => { | |
this.errorHandler(err, req, res, next) | |
.catch(err => this.emit('error', err)) | |
}) | |
const expressMiddleware: RequestHandler[] = [ | |
verifySignatureAndParseBody(logger, signingSecret), | |
respondToSslCheck, | |
respondToUrlVerification, | |
(req: Request, res: Response, next: NextFunction) => { | |
this.requestHandler(req, res) | |
.then(() => { | |
next() }) | |
.catch(next) | |
} | |
] | |
const endpointList: string[] = typeof endpoints === 'string' ? [endpoints] : Object.values(endpoints); | |
for (const endpoint of endpointList) { | |
this.app.post(endpoint, ...expressMiddleware); | |
} | |
} | |
private async requestHandler(req: Request, res: Response) { | |
const event: ReceiverEvent = { | |
body: req.body as { [key: string]: any }, | |
ack: (response: any): void => { | |
if (!response) res.send('') | |
if (typeof response === 'string') { | |
res.send(response) | |
} else { | |
res.json(response) | |
} | |
}, | |
respond: undefined, | |
} | |
if (req.body && req.body.response_url) { | |
event.respond = (response): void => { | |
axios.post(req.body.response_url, response) | |
.catch((e) => { | |
return this.emit('error', e) | |
}) | |
} | |
} | |
await this.emit('message', event) | |
} | |
on(event: "message", listener: (event: ReceiverEvent) => void): unknown; on(event: "error", listener: (error: Error | ReceiverAckTimeoutError) => void): unknown | |
on(event: any, listener: any) { | |
const v = this.listenerMap.get(event) | |
if (!v) { | |
this.listenerMap.set(event, [listener]) | |
return | |
} | |
v.push(listener) | |
} | |
start(...args: any[]): Promise<unknown> { | |
throw new Error("Method not implemented.") | |
} | |
stop(...args: any[]): Promise<unknown> { | |
throw new Error("Method not implemented.") | |
} | |
private async errorHandler(err: any, _req: Request, _res: Response, next: NextFunction) { | |
await this.emit('error', err) | |
next(err) | |
} | |
listeners(event: string | symbol): Array<Function> { | |
const v = this.listenerMap.get(event) | |
if (!v) { | |
return [] | |
} | |
return v | |
} | |
emit(event: string | symbol, ...args: any[]): Promise<any[]> { | |
return Promise.all( | |
this.listeners(event) | |
.map(listener => listener(...args)) | |
) | |
} | |
} | |
const respondToSslCheck: RequestHandler = (req, res, next) => { | |
if (req.body && req.body.ssl_check) { | |
res.send() | |
return | |
} | |
next() | |
} | |
const respondToUrlVerification: RequestHandler = (req, res, next) => { | |
if (req.body && req.body.type && req.body.type === 'url_verification') { | |
res.json({ challenge: req.body.challenge }) | |
return | |
} | |
next() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment