The easiest way to get started in Slack socket mode (Go)

slack-go/slack now supports socket mode: tada:

The widely used Go SDK github.com/slack-go/slack ) Now supports socket mode: tada: @ mumoshu and @ kanata2's great work: clap:

https://github.com/slack-go/slack

Procedure to start the socket mode application

In this article, I'll show you how to use this Go SDK to run the same sample app that you used in Easy Getting Started with Slack Socket Mode.

Create a project

The sample presented here works with v0.8.0 and above.

go mod init socket-mode-app
go get github.com/slack-go/[email protected]

Prepare main.go

For the time being, please copy and paste the following source code as it is.

package main

import (
	"fmt"
	"github.com/slack-go/slack/socketmode"
	"log"
	"os"
	"strings"

	"github.com/slack-go/slack"
	"github.com/slack-go/slack/slackevents"
)

func main() {
	webApi := slack.New(
		os.Getenv("SLACK_BOT_TOKEN"),
		slack.OptionAppLevelToken(os.Getenv("SLACK_APP_TOKEN")),
		slack.OptionDebug(true),
		slack.OptionLog(log.New(os.Stdout, "api: ", log.Lshortfile|log.LstdFlags)),
	)
	socketMode := socketmode.New(
		webApi,
		socketmode.OptionDebug(true),
		socketmode.OptionLog(log.New(os.Stdout, "sm: ", log.Lshortfile|log.LstdFlags)),
	)
	authTest, authTestErr := webApi.AuthTest()
	if authTestErr != nil {
		fmt.Fprintf(os.Stderr, "SLACK_BOT_TOKEN is invalid: %v\n", authTestErr)
		os.Exit(1)
	}
	selfUserId := authTest.UserID

	go func() {
		for envelope := range socketMode.Events {
			switch envelope.Type {
			case socketmode.EventTypeEventsAPI:
				//Event API handling

				//Ack for the time being within 3 seconds
				socketMode.Ack(*envelope.Request)

				eventPayload, _ := envelope.Data.(slackevents.EventsAPIEvent)
				switch eventPayload.Type {
				case slackevents.CallbackEvent:
					switch event := eventPayload.InnerEvent.Data.(type) {
					case *slackevents.MessageEvent:
						if event.User != selfUserId && strings.Contains(event.Text, "Hello") {
							_, _, err := webApi.PostMessage(
								event.Channel,
								slack.MsgOptionText(
									fmt.Sprintf(":wave:Hello<@%v>San!", event.User),
									false,
								),
							)
							if err != nil {
								log.Printf("Failed to reply: %v", err)
							}
						}
					default:
						socketMode.Debugf("Skipped: %v", event)
					}
				default:
					socketMode.Debugf("unsupported Events API eventPayload received")
				}
			case socketmode.EventTypeInteractive:
				//Shortcut handling and modal activation
				payload, _ := envelope.Data.(slack.InteractionCallback)
				switch payload.Type {
				case slack.InteractionTypeShortcut:
					if payload.CallbackID == "socket-mode-shortcut" {
						socketMode.Ack(*envelope.Request)
						modalView := slack.ModalViewRequest{
							Type:       "modal",
							CallbackID: "modal-id",
							Title: slack.NewTextBlockObject(
								"plain_text",
								"Task registration",
								false,
								false,
							),
							Submit: slack.NewTextBlockObject(
								"plain_text",
								"Send",
								false,
								false,
							),
							Close: slack.NewTextBlockObject(
								"plain_text",
								"Cancel",
								false,
								false,
							),
							Blocks: slack.Blocks{
								BlockSet: []slack.Block{
									slack.NewInputBlock(
										"input-task",
										slack.NewTextBlockObject(
											"plain_text",
											"task",
											false,
											false,
										),
										// multiline is not yet supported
										slack.NewPlainTextInputBlockElement(
											slack.NewTextBlockObject(
												"plain_text",
												"Please write the details and deadline of the task",
												false,
												false,
											),
											"input",
										),
									),
								},
							},
						}
						resp, err := webApi.OpenView(payload.TriggerID, modalView)
						if err != nil {
							log.Printf("Failed to opemn a modal: %v", err)
						}
						socketMode.Debugf("views.open response: %v", resp)
					}
				case slack.InteractionTypeViewSubmission:
					//Handling transmissions from modals
					if payload.CallbackID == "modal-id" {
						socketMode.Debugf("Submitted Data: %v", payload.View.State.Values)
						socketMode.Ack(*envelope.Request)
					}
				default:
					socketMode.Debugf("Skipped: %v", payload)
				}

			default:
				socketMode.Debugf("Skipped: %v", envelope.Type)
			}
		}
	}()

	socketMode.Run()
}

to start

As in the previous article, let's set the environment variables and start it.

export SLACK_APP_TOKEN=xapp-<Value of my token>
export SLACK_BOT_TOKEN=xoxb-<Value of my token>
go run main.go

If you see a message like the one below, you are connected!

$ go run main.go
api: 2021/01/19 15:41:48 slack.go:125: Challenging auth...
sm: 2021/01/19 15:41:48 socket_mode_managed_conn.go:241: Starting SocketMode
sm: 2021/01/19 15:41:48 main.go:133: Skipped: connecting
api: 2021/01/19 15:41:48 socket_mode.go:30: Using URL: wss://wss-primary.slack.com/link/?ticket=xxx&app_id=yyy
sm: 2021/01/19 15:41:48 socket_mode_managed_conn.go:249: Dialing to websocket on url wss://wss-primary.slack.com/link/?ticket=xxx&app_id=yyy
sm: 2021/01/19 15:41:49 socket_mode_managed_conn.go:78: WebSocket connection succeeded on try 0
sm: 2021/01/19 15:41:49 socket_mode_managed_conn.go:422: Starting to receive message
sm: 2021/01/19 15:41:49 main.go:133: Skipped: connected
sm: 2021/01/19 15:41:49 socket_mode_managed_conn.go:464: Incoming WebSocket message: {
  "type": "hello",
  "num_connections": 1,
  "debug_info": {
    "host": "applink-xxx-yyy",
    "build_number": 10,
    "approximate_connection_time": 18060
  },
  "connection_info": {
    "app_id": "A111"
  }
}

sm: 2021/01/19 15:41:49 socket_mode_managed_conn.go:476: Finished to receive message
sm: 2021/01/19 15:41:49 socket_mode_managed_conn.go:422: Starting to receive message
sm: 2021/01/19 15:41:49 socket_mode_managed_conn.go:319: Received WebSocket message: {"type":"hello","num_connections":1,"debug_info":{"host":"applink-xxx-yyy","build_number":10,"approximate_connection_time":18060},"connection_info":{"app_id":"A111"}}
sm: 2021/01/19 15:41:49 main.go:133: Skipped: hello
sm: 2021/01/19 15:41:51 socket_mode_managed_conn.go:544: WebSocket ping message received: Ping from applink-xxx-yyy

Next step

The official sample code can be found at the following location, so please check it out.

https://github.com/slack-go/slack/tree/master/examples/socketmode

Recommended Posts

The easiest way to get started in Slack socket mode (Go)
The easiest way to get started with Django
The easiest way to set up Last-Modified in Flask
Post to slack in Go language
The easiest way to make Flask
The easiest way to try PyQtGraph
Create a function to get the contents of the database in Go
The easiest way to get Chainer v1.5 + CUDA + cuDNN on Windows
The easiest way to synthesize speech with python
The easiest way to use OpenCV with python
How to get the files in the [Python] folder
Use pygogo to get the log in json.
How to get the variable name itself in python
The easiest line bot in the world to lose weight
One liner to get the nth commit hash in Git
[Go language] How to get terminal input in real time
Minimum knowledge to get started with the Python logging module
Probably the easiest way to create a pdf with Python3
I wrote it in Go to understand the SOLID principle
To write a test in Go, first design the interface
[Shell] How to get the remote default branch in Git
Post to Slack in Python
An easy way to hit the Amazon Product API in Python
How to get all the possible values in a regular expression
A game to go on an adventure in python interactive mode
Hit the New Relic API in Python to get the server status
I tried to get started with Bitcoin Systre on the weekend
How to get the vertex coordinates of a feature in ArcPy
Steps to get Caffe into Mac OS X 10.10 in CPU Mode
The fastest way to get camera images regularly with python opencv
Get the IPv4 address assigned to the network interface in code (Linux)
How to display bytes in the same way in Java and Python
What is Jenkins? ] Installation-how to use-automatic test / automatic deployment will be explained in the world's easiest way
Programming to fight in the world ~ 5-5,5-6
Programming to fight in the world 5-3
Link to get started with python
Get the desktop path in Python
Programming to fight in the world-Chapter 4
Get the script path in Python
In the python command python points to python3.8
How to get the Python version
How to get started with Scrapy
How to get started with Python
How to get started with Django
Get the desktop path in Python
Cython to try in the shortest
Get the host name in Python
The fastest way to try EfficientNet
Get started with Python in Blender
Programming to fight in the world ~ 5-2
Get custom emoji registered in slack
Get the query string (query string) in Django
How to get the date and time difference in seconds with python
Click the Selenium links in order to get the elements of individual pages
[Linux] Command to get a list of commands executed in the past
Sample code to get the Twitter API oauth_token and oauth_token_secret in Python 2.7
I will teach you the Twitter tweet bot in the easiest way in Japan.
What is the fastest way to create a reverse dictionary in python?