-
Notifications
You must be signed in to change notification settings - Fork 401
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #630 from slackapi/feat-socket-mode
Adding SocketModeReceiver to Bolt-js
- Loading branch information
Showing
9 changed files
with
599 additions
and
7 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
--- | ||
title: Using Socket Mode | ||
lang: en | ||
slug: socket-mode | ||
order: 16 | ||
--- | ||
|
||
<div class="section-content"> | ||
[Socket Mode](https://api.slack.com/socket-mode) allows your app to connect and receive data from Slack via a WebSocket connection. To handle the connection, Bolt for JavaScript includes a `SocketModeReceiver` (in `@slack/bolt@3.0.0` and higher). Before using Socket Mode, be sure to enable it within your app configuration. | ||
|
||
To use the `SocketModeReceiver`, just pass in `socketMode:true` and `appToken:YOUR_APP_TOKEN` when initializing `App`. You can get your App Level Token in your app configuration under the **Basic Information** section. | ||
</div> | ||
|
||
```javascript | ||
const { App } = require('@slack/bolt'); | ||
|
||
const app = new App({ | ||
token: process.env.BOT_TOKEN | ||
socketMode: true, | ||
appToken: process.env.APP_TOKEN, | ||
}); | ||
|
||
(async () => { | ||
await app.start(); | ||
console.log('⚡️ Bolt app started'); | ||
})(); | ||
``` | ||
|
||
<details class="secondary-wrapper"> | ||
<summary class="section-head" markdown="0"> | ||
<h4 class="section-head">Custom SocketMode Receiver</h4> | ||
</summary> | ||
|
||
<div class="secondary-content" markdown="0"> | ||
You can define a custom `SocketModeReceiver` by importing it from `@slack/bolt`. | ||
|
||
</div> | ||
|
||
```javascript | ||
const { App, SocketModeReceiver } = require('@slack/bolt'); | ||
|
||
const socketModeReceiver = new SocketModeReceiver({ | ||
appToken: process.env.APP_TOKEN, | ||
|
||
// enable the following if you want to use OAuth | ||
// clientId: process.env.CLIENT_ID, | ||
// clientSecret: process.env.CLIENT_SECRET, | ||
// stateSecret: 'my-state-secret', | ||
// scopes: ['channels:read', 'chat:write', 'app_mentions:read', 'channels:manage', 'commands'], | ||
}); | ||
|
||
const app = new App({ | ||
receiver: socketModeReceiver, | ||
// disable token line below if using OAuth | ||
token: process.env.BOT_TOKEN | ||
}); | ||
|
||
(async () => { | ||
await app.start(); | ||
console.log('⚡️ Bolt app started'); | ||
})(); | ||
``` | ||
|
||
</details> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Bolt for JavaScript Socket Mode Test App | ||
|
||
This is a quick example app to test [Socket Mode](https://api.slack.com/socket-mode) with Bolt for JavaScript. | ||
|
||
If using OAuth, Slack requires a public URL where it can send requests. In this guide, we'll be using [`ngrok`](https://ngrok.com/download). Checkout [this guide](https://api.slack.com/tutorials/tunneling-with-ngrok) for setting it up. OAuth installation is only needed for public distribution. For internal apps, we recommend installing via your app configuration. | ||
|
||
Before we get started, make sure you have a development workspace where you have permissions to install apps. If you don’t have one setup, go ahead and [create one](https://slack.com/create). You also need to [create a new app](https://api.slack.com/apps?new_app=1) if you haven’t already. You will need to enable Socket Mode and generate an App Level Token. | ||
|
||
## Install Dependencies | ||
|
||
``` | ||
npm install | ||
``` | ||
|
||
## Install app to workspace | ||
|
||
In your [app configuration](https://api.slack.com/apps), go to **OAuth & Permissions** and add the `channels:read`, `app_mentions:read`, `commands`, and `chat:write` permissions. Click **Install App** to install the app to your workspace and generate a bot token. | ||
|
||
Next, navigate to the **Socket Mode** section and toggle the **Enable Socket Mode** button to start receiving events over a WebSocket connection. | ||
|
||
Next, click on **Basic Information** and generate a `App Level Token` with the `connections:write` scope. | ||
|
||
Then navigate to **App Home**. Under **Show tabs**, toggle the **Home tab** option. | ||
|
||
Lastly, in **Events Subscription**, click **Subscribe to bot events** and add `app_home_opened`, `app_mentioned`, and `message.channels`. | ||
|
||
## Setup Environment Variables | ||
|
||
This app requires you setup a few environment variables. You can find these values in your [app configuration](https://api.slack.com/apps). | ||
|
||
``` | ||
// can get this from OAuth & Permission page in app configuration | ||
export BOT_TOKEN=YOUR_SLACK_BOT_TOKEN | ||
// can generate the app level token from basic information page in app configuration | ||
export APP_TOKEN=YOUR_SLACK_APP_TOKEN | ||
// if using OAuth, also export the following | ||
export CLIENT_ID=YOUR_SLACK_CLIENT_ID | ||
export CLIENT_SECRET=YOUR_SLACK_CLIENT_SECRET | ||
``` | ||
|
||
## Run the App | ||
|
||
Start the app with the following command: | ||
|
||
``` | ||
npm start | ||
``` | ||
|
||
### Running with OAuth | ||
|
||
Only implement OAuth if you plan to distribute your application across multiple workspaces. Uncomment out the OAuth specific comments in the code. If you are on dev instance, you will have to uncomment out those options as well. | ||
|
||
Start `ngrok` so we can access the app on an external network and create a redirect URL for OAuth. | ||
|
||
``` | ||
ngrok http 3000 | ||
``` | ||
|
||
This output should include a forwarding address for `http` and `https` (we'll use the `https` one). It should look something like the following: | ||
|
||
``` | ||
Forwarding https://3cb89939.ngrok.io -> http://localhost:3000 | ||
``` | ||
|
||
Then navigate to **OAuth & Permissions** in your app configuration and click **Add a Redirect URL**. The redirect URL should be set to your `ngrok` forwarding address with the `slack/oauth_redirect` path appended. ex: | ||
|
||
``` | ||
https://3cb89939.ngrok.io/slack/oauth_redirect | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
const { App, LogLevel, SocketModeReceiver } = require('@slack/bolt'); | ||
|
||
const clientOptions = { | ||
// enable this for dev instance | ||
// slackApiUrl: 'https://dev.slack.com/api/' | ||
}; | ||
|
||
// const socketModeReceiver = new SocketModeReceiver({ | ||
// appToken: process.env.APP_TOKEN, | ||
// installerOptions: { | ||
// clientOptions, | ||
// // use the following when running against a dev instance and using OAuth | ||
// // authorizationUrl: 'https://dev.slack.com/oauth/v2/authorize', | ||
// }, | ||
|
||
// // enable the following if you want to use OAuth | ||
// // clientId: process.env.CLIENT_ID, | ||
// // clientSecret: process.env.CLIENT_SECRET, | ||
// // stateSecret: 'my-state-secret', | ||
// // scopes: ['channels:read', 'chat:write', 'app_mentions:read', 'channels:manage', 'commands'], | ||
|
||
// logLevel: LogLevel.DEBUG, | ||
// }); | ||
|
||
const app = new App({ | ||
// receiver: socketModeReceiver, | ||
token: process.env.BOT_TOKEN, //disable this if enabling OAuth in socketModeReceiver | ||
// logLevel: LogLevel.DEBUG, | ||
clientOptions, | ||
appToken: process.env.APP_TOKEN, | ||
socketMode: true, | ||
}); | ||
|
||
(async () => { | ||
await app.start(); | ||
console.log('⚡️ Bolt app started'); | ||
})(); | ||
|
||
// Publish a App Home | ||
app.event('app_home_opened', async ({ event, client }) => { | ||
await client.views.publish({ | ||
user_id: event.user, | ||
view: { | ||
"type":"home", | ||
"blocks":[ | ||
{ | ||
"type": "section", | ||
"block_id": "section678", | ||
"text": { | ||
"type": "mrkdwn", | ||
"text": "App Home Published" | ||
}, | ||
} | ||
] | ||
}, | ||
}); | ||
}); | ||
|
||
// Message Shortcut example | ||
app.shortcut('launch_msg_shortcut', async ({ shortcut, body, ack, context, client }) => { | ||
await ack(); | ||
console.log(shortcut); | ||
}); | ||
|
||
// Global Shortcut example | ||
// setup global shortcut in App config with `launch_shortcut` as callback id | ||
// add `commands` scope | ||
app.shortcut('launch_shortcut', async ({ shortcut, body, ack, context, client }) => { | ||
try { | ||
// Acknowledge shortcut request | ||
await ack(); | ||
|
||
// Call the views.open method using one of the built-in WebClients | ||
const result = await client.views.open({ | ||
trigger_id: shortcut.trigger_id, | ||
view: { | ||
type: "modal", | ||
title: { | ||
type: "plain_text", | ||
text: "My App" | ||
}, | ||
close: { | ||
type: "plain_text", | ||
text: "Close" | ||
}, | ||
blocks: [ | ||
{ | ||
type: "section", | ||
text: { | ||
type: "mrkdwn", | ||
text: "About the simplest modal you could conceive of :smile:\n\nMaybe <https://api.slack.com/reference/block-kit/interactive-components|*make the modal interactive*> or <https://api.slack.com/surfaces/modals/using#modifying|*learn more advanced modal use cases*>." | ||
} | ||
}, | ||
{ | ||
type: "context", | ||
elements: [ | ||
{ | ||
type: "mrkdwn", | ||
text: "Psssst this modal was designed using <https://api.slack.com/tools/block-kit-builder|*Block Kit Builder*>" | ||
} | ||
] | ||
} | ||
] | ||
} | ||
}); | ||
} | ||
catch (error) { | ||
console.error(error); | ||
} | ||
}); | ||
|
||
|
||
// subscribe to 'app_mention' event in your App config | ||
// need app_mentions:read and chat:write scopes | ||
app.event('app_mention', async ({ event, context, client, say }) => { | ||
try { | ||
await say({"blocks": [ | ||
{ | ||
"type": "section", | ||
"text": { | ||
"type": "mrkdwn", | ||
"text": `Thanks for the mention <@${event.user}>! Click my fancy button` | ||
}, | ||
"accessory": { | ||
"type": "button", | ||
"text": { | ||
"type": "plain_text", | ||
"text": "Button", | ||
"emoji": true | ||
}, | ||
"value": "click_me_123", | ||
"action_id": "first_button" | ||
} | ||
} | ||
]}); | ||
} | ||
catch (error) { | ||
console.error(error); | ||
} | ||
}); | ||
|
||
// subscribe to `message.channels` event in your App Config | ||
// need channels:read scope | ||
app.message('hello', async ({ message, say }) => { | ||
// say() sends a message to the channel where the event was triggered | ||
// no need to directly use 'chat.postMessage', no need to include token | ||
await say({"blocks": [ | ||
{ | ||
"type": "section", | ||
"text": { | ||
"type": "mrkdwn", | ||
"text": `Thanks for the mention <@${message.user}>! Click my fancy button` | ||
}, | ||
"accessory": { | ||
"type": "button", | ||
"text": { | ||
"type": "plain_text", | ||
"text": "Button", | ||
"emoji": true | ||
}, | ||
"value": "click_me_123", | ||
"action_id": "first_button" | ||
} | ||
} | ||
]}); | ||
}); | ||
|
||
// Listen and respond to button click | ||
app.action('first_button', async({action, ack, say, context}) => { | ||
console.log('button clicked'); | ||
console.log(action); | ||
// acknowledge the request right away | ||
await ack(); | ||
await say('Thanks for clicking the fancy button'); | ||
}); | ||
|
||
// Listen to slash command | ||
// need to add commands permission | ||
// create slash command in App Config | ||
app.command('/socketslash', async ({ command, ack, say }) => { | ||
// Acknowledge command request | ||
await ack(); | ||
|
||
await say(`${command.text}`); | ||
}); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "bolt-socket-mode-example", | ||
"version": "1.0.0", | ||
"description": "Example app using socket mode", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "node app.js", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"author": "Slack Technologies, Inc.", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@slack/bolt": "feat-socket-mode" | ||
} | ||
} |
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
Oops, something went wrong.