Slack Bot Framework

Overview

slacker Build Status Go Report Card GoDoc License: MIT Mentioned in Awesome Go

Built on top of the Slack API github.com/slack-go/slack with the idea to simplify the Real-Time Messaging feature to easily create Slack Bots, assign commands to them and extract parameters.

Features

  • Easy definitions of commands and their input
  • Available bot initialization, errors and default handlers
  • Simple parsing of String, Integer, Float and Boolean parameters
  • Contains support for context.Context
  • Built-in help command
  • Replies can be new messages or in threads
  • Supports authorization
  • Bot responds to mentions and direct messages
  • Handlers run concurrently via goroutines
  • Produces events for executed commands
  • Full access to the Slack API github.com/slack-go/slack

Dependencies

Install

go get github.com/shomali11/slacker

Examples

Example 1

Defining a command using slacker

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("pong")
		},
	}

	bot.Command("ping", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 2

Defining a command with an optional description and example. The handler replies to a thread.

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Ping!",
		Example:     "ping",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("pong", slacker.WithThreadReply(true))
		},
	}

	bot.Command("ping", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 3

Defining a command with a parameter

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Echo a word!",
		Example:     "echo hello",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")
			response.Reply(word)
		},
	}

	bot.Command("echo <word>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 4

Defining a command with two parameters. Parsing one as a string and the other as an integer. (The second parameter is the default value in case no parameter was passed or could not parse the value)

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Repeat a word a number of times!",
		Example:     "repeat hello 10",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.StringParam("word", "Hello!")
			number := request.IntegerParam("number", 1)
			for i := 0; i < number; i++ {
				response.Reply(word)
			}
		},
	}

	bot.Command("repeat <word> <number>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 5

Defines two commands that display sending errors to the Slack channel. One that replies as a new message. The other replies to the thread.

package main

import (
	"context"
	"errors"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	messageReplyDefinition := &slacker.CommandDefinition{
		Description: "Tests errors in new messages",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.ReportError(errors.New("Oops!"))
		},
	}

	threadReplyDefinition := &slacker.CommandDefinition{
		Description: "Tests errors in threads",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.ReportError(errors.New("Oops!"), slacker.WithThreadError(true))
		},
	}

	bot.Command("message", messageReplyDefinition)
	bot.Command("thread", threadReplyDefinition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 6

Send a "Typing" indicator

package main

import (
	"context"
	"log"
	"time"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Server time!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Typing()

			time.Sleep(time.Second)

			response.Reply(time.Now().Format(time.RFC1123))
		},
	}

	bot.Command("time", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 7

Showcasing the ability to access the github.com/slack-go/slack API and the Real-Time Messaging Protocol. In this example, we are sending a message using RTM and uploading a file using the Slack API.

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
	"github.com/slack-go/slack"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Upload a word!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")

			channel := botCtx.Event().Channel
			rtm := botCtx.RTM()
			client := botCtx.Client()

			rtm.SendMessage(rtm.NewOutgoingMessage("Uploading file ...", channel))
			client.UploadFile(slack.FileUploadParameters{Content: word, Channels: []string{channel}})
		},
	}

	bot.Command("upload <word>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 8

Showcasing the ability to leverage context.Context to add a timeout

package main

import (
	"context"
	"errors"
	"log"
	"time"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Process!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			timedContext, cancel := context.WithTimeout(botCtx.Context(), time.Second)
			defer cancel()

			select {
			case <-timedContext.Done():
				response.ReportError(errors.New("timed out"))
			case <-time.After(time.Minute):
				response.Reply("Processing done!")
			}
		},
	}

	bot.Command("process", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 9

Showcasing the ability to add attachments to a Reply

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
	"github.com/slack-go/slack"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Echo a word!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")

			attachments := []slack.Attachment{}
			attachments = append(attachments, slack.Attachment{
				Color:      "red",
				AuthorName: "Raed Shomali",
				Title:      "Attachment Title",
				Text:       "Attachment Text",
			})

			response.Reply(word, slacker.WithAttachments(attachments))
		},
	}

	bot.Command("echo <word>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 10

Showcasing the ability to add blocks to a Reply

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
	"github.com/slack-go/slack"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Echo a word!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")

			attachments := []slack.Block{}
			attachments = append(attachments, slack.NewContextBlock("1",
				slack.NewTextBlockObject("mrkdwn", "Hi!", false, false)),
			)

			response.Reply(word, slacker.WithBlocks(attachments))
		},
	}

	bot.Command("echo <word>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 11

Showcasing the ability to create custom responses via CustomResponse

package main

import (
	"log"

	"context"
	"errors"
	"fmt"

	"github.com/shomali11/slacker"
)

const (
	errorFormat = "> Custom Error: _%s_"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	bot.CustomResponse(NewCustomResponseWriter)

	definition := &slacker.CommandDefinition{
		Description: "Custom!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("custom")
			response.ReportError(errors.New("oops"))
		},
	}

	bot.Command("custom", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

// NewCustomResponseWriter creates a new ResponseWriter structure
func NewCustomResponseWriter(botCtx slacker.BotContext) slacker.ResponseWriter {
	return &MyCustomResponseWriter{botCtx: botCtx}
}

// MyCustomResponseWriter a custom response writer
type MyCustomResponseWriter struct {
	botCtx slacker.BotContext
}

// ReportError sends back a formatted error message to the channel where we received the event from
func (r *MyCustomResponseWriter) ReportError(err error, options ...slacker.ReportErrorOption) {
	rtm := r.botCtx.RTM()
	event := r.botCtx.Event()
	rtm.SendMessage(rtm.NewOutgoingMessage(fmt.Sprintf(errorFormat, err.Error()), event.Channel))
}

// Typing send a typing indicator
func (r *MyCustomResponseWriter) Typing() {
	rtm := r.botCtx.RTM()
	event := r.botCtx.Event()
	rtm.SendMessage(rtm.NewTypingMessage(event.Channel))
}

// Reply send a attachments to the current channel with a message
func (r *MyCustomResponseWriter) Reply(message string, options ...slacker.ReplyOption) {
	rtm := r.botCtx.RTM()
	event := r.botCtx.Event()
	rtm.SendMessage(rtm.NewOutgoingMessage(message, event.Channel))
}

Example 12

Showcasing the ability to toggle the slack Debug option via WithDebug

package main

import (
	"context"
	"github.com/shomali11/slacker"
	"log"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>", slacker.WithDebug(true))

	definition := &slacker.CommandDefinition{
		Description: "Ping!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("pong")
		},
	}

	bot.Command("ping", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 13

Defining a command that can only be executed by authorized users

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	authorizedUsers := []string{"<USER ID>"}

	authorizedDefinition := &slacker.CommandDefinition{
		Description: "Very secret stuff",
		AuthorizationFunc: func(botCtx slacker.BotContext, request slacker.Request) bool {
			return contains(authorizedUsers, botCtx.Event().User)
		},
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("You are authorized!")
		},
	}

	bot.Command("secret", authorizedDefinition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

func contains(list []string, element string) bool {
	for _, value := range list {
		if value == element {
			return true
		}
	}
	return false
}

Example 14

Adding handlers to when the bot is connected, encounters an error and a default for when none of the commands match

package main

import (
	"log"

	"context"
	"fmt"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	bot.Init(func() {
		log.Println("Connected!")
	})

	bot.Err(func(err string) {
		log.Println(err)
	})

	bot.DefaultCommand(func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
		response.Reply("Say what?")
	})

	bot.DefaultEvent(func(event interface{}) {
		fmt.Println(event)
	})

	definition := &slacker.CommandDefinition{
		Description: "help!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("Your own help function...")
		},
	}

	bot.Help(definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 15

Listening to the Commands Events being produced

package main

import (
	"fmt"
	"log"

	"context"

	"github.com/shomali11/slacker"
)

func printCommandEvents(analyticsChannel <-chan *slacker.CommandEvent) {
	for event := range analyticsChannel {
		fmt.Println("Command Events")
		fmt.Println(event.Timestamp)
		fmt.Println(event.Command)
		fmt.Println(event.Parameters)
		fmt.Println(event.Message)
		fmt.Println()
	}
}

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	go printCommandEvents(bot.CommandEvents())

	bot.Command("ping", &slacker.CommandDefinition{
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("pong")
		},
	})

	bot.Command("echo <word>", &slacker.CommandDefinition{
		Description: "Echo a word!",
		Example:     "echo hello",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")
			response.Reply(word)
		},
	})

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}
Issues
  • Allow event handler to be configured

    Allow event handler to be configured

    Example of usage:

    
    handler := func(ctx context.Context, s *slacker.Slacker, msg slack.RTMEvent) error {
    	switch event := msg.Data.(type) {
    		case *slack.MessageEvent:
    			// do any special process, like filter messages by channel and process them.
    	}
    	return slacker.DefaultEventHandler(ctx,  s, msg)
    }
    bot := slacker..NewClient(token, slacker.WithEventHandler(handler))
    
    opened by smoya 20
  • my app only responds to the 1st message i post

    my app only responds to the 1st message i post

    i copy the example go file, and wrote @app run, it only responds to the 1st mention. while if i register new command it respond again to the very 1st one. Any reason for this? thanks

    opened by huaweiunity 18
  • Expose the slack client in AuthorizedFunc

    Expose the slack client in AuthorizedFunc

    We'd like to be able to authenticate a Slack user with a backend database that has no concept of Slack User IDs, but to get the requesting users profile details we need access to the Slack client. Simple example:

    var myCommand = &slacker.CommandDefinition {
        ...
        AuthorizationFunc: func(request slacker.Request, client slack.Client) bool {
            ...
            userInfo, _ := client.GetUserInfo(request.Event().User)
            return AuthorizeFromDatabase("some-command", user.Profile.Email)
        },
        ...
    }
    
    opened by arusso 12
  • This only works with

    This only works with "classic" slack apps

    I think the README should be updated to indicate it uses the RTM API which does not function with new slack apps that have granular oauth permissions.

    Took me 40 minutes to figure out what was going on by finally dropping the debug option in the config and seeing:

    slack-go/slack2020/07/18 13:56:31 websocket_managed_conn.go:177: Connecting to RTM
    slack-go/slack2020/07/18 13:56:32 rtm.go:71: Using URL:
    slack-go/slack2020/07/18 13:56:32 websocket_managed_conn.go:181: Failed to start or connect to RTM: not_allowed_token_type
    slack-go/slack2020/07/18 13:56:32 websocket_managed_conn.go:147: reconnection 1 failed: not_allowed_token_type reconnecting in 100ms
    ...
    

    It is possible to still create apps that use the old permissions scopes but they are pushing everything to the events API.

    More info in this thread https://github.com/slackapi/node-slack-sdk/issues/921#issuecomment-644317329

    opened by leetrout 11
  • Use SocketMode for connections

    Use SocketMode for connections

    Updates Slacker to use the Events API over the SocketMode communication protocol, replacing calls to the deprecated RTM API.

    A few key functions have changed, notably the NewClient function now requires both an App and Bot token to be specified. In addition, the typing indicator is not supported in SocketMode and has been removed altogether.

    Fixes #63

    opened by arusso 11
  • Fix help response showing up unexpectedly

    Fix help response showing up unexpectedly

    Hi, the pattern matching for help is too broad IMO, I believe my suggestion is more suitable.

    opened by bergundy 9
  • Auth not working

    Auth not working

    Starting from your example, I'm testing a quick bot, but I'm getting an auth error. It's not clear from the code:

    bot := slacker.NewClient(os.Getenv("SLACK_BOT_TOKEN"), os.Getenv("SLACK_APP_TOKEN"))

    Whether this requires either a BOT token or an APP token, or if it needs both and what the difference is? For our Slack setup, I got an "API token" that should be a BOT token. When I set that and run it, I get:

    Connecting to Slack with Socket Mode. 2021/05/26 14:52:01 not_authed exit status 1

    Just to check, I used the token as SLACK_APP_TOKEN and then it just repeats:

    Connecting to Slack with Socket Mode. Connection failed. Retrying later...

    Over and over.

    It's not clear what the "not_authed" error means -- was the token refused, or did it fail to connect for authentication, or something else? Any hints on debugging this? Thank you!

    opened by mason-jones-ck 9
  • Enabling reply in thread

    Enabling reply in thread

    As the timestamp is needed to reply in thread, made some changes to be able to have this optional methods in ResponseWriter

    • Changed ResponseWriter interface to have replies methods with InThread version
    • Changed contructor to receive the events instead of only the channel
    • Adapted the whole code to comply to the new interface and constructor
    opened by batagliao 8
  • Adding flags

    Adding flags

    Hey, i think this could be a cool improvement for slacker if we got something like https://github.com/spf13/cobra

    with flags

    Interesting you think?

    opened by piclemx 6
  • Add some features

    Add some features

    • Request is now a interface
    • Add method to interface of the response to have access to client and rtm struct.
    • Should close #18
    opened by piclemx 6
  • Debugging why a response isn't being shown in Slack

    Debugging why a response isn't being shown in Slack

    I have a situation where I can see that my command is reaching the slackbot, and it is responding, but the response is not showing up in Slack. It's hard for me to tell if this is something wrong with the bot/slacker, or if it's something else, and I'm wonder if there are good strategies for debugging this? I'm happy to try things out and then add some documentation here via PR with any helpful info I come up with.

    Here's what I have so far:

    I have put the "ping" command for testing, with a log line to show that the handler is getting executed -- it is:

    definition := &slacker.CommandDefinition{
         Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
              fmt.Println("I've been asked to ping-pong!")
              response.Reply("pong")
         },
    }
    
    bot.Command("ping", definition)
    

    I've added debug(true) to the client: bot := slacker.NewClient(os.Getenv("SLACK_BOT_TOKEN"), os.Getenv("SLACK_APP_TOKEN"), slacker.WithDebug(true))

    When I start the bot, I see what I'd expect, although there is a message about unsupported Events API event received:

    Connecting to Slack with Socket Mode.
    slack-go/slack/socketmode2021/06/17 14:25:32 socket_mode_managed_conn.go:258: Starting SocketMode
    slack-go/slack2021/06/17 14:25:32 socket_mode.go:30: Using URL: wss://wss-primary.slack.com/link/?ticket=<etc>
    slack-go/slack/socketmode2021/06/17 14:25:32 socket_mode_managed_conn.go:266: Dialing to websocket on url wss://wss-primary.slack.com/link/?ticket=<etc>
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:91: WebSocket connection succeeded on try 0
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:439: Starting to receive message
    Connected to Slack with Socket Mode.
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:481: Incoming WebSocket message: {
      "type": "hello",
      "num_connections": 2,
      "debug_info": {
        "host": "applink-d85c5c684-wkb2x",
        "build_number": 18,
        "approximate_connection_time": 18060
      },
      "connection_info": {
        "app_id": "<id here>"
      }
    }
    
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:493: Finished to receive message
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:439: Starting to receive message
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:336: Received WebSocket message: {"type":"hello","num_connections":2,"debug_info":{"host":"applink-d85c5c684-wkb2x","build_number":18,"approximate_connection_time":18060},"connection_info":{"app_id":"<id here>"}}
    slack-go/slack/socketmode2021/06/17 14:25:33 slacker.go:185: unsupported Events API event received
    slack-go/slack/socketmode2021/06/17 14:25:38 socket_mode_managed_conn.go:561: WebSocket ping message received: Ping from applink-d85c5c684-wkb2x
    

    When I chat with the bot in Slack and say "ping", I get no response, but I see this logged:

    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:493: Finished to receive message
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:439: Starting to receive message
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:336: Received WebSocket message: {"envelope_id":"9159361e-b381-4801-85a5-eedad48bc59a","payload":{"token":"<token>","team_id":"<id>","api_app_id":"<id>","event":{"client_msg_id":"e7d533c4-9442-4fac-8b86-cef8181f93b7","type":"message","text":"ping","user":"<user>","ts":"1623965305.000200","team":"<team>","blocks":[{"type":"rich_text","block_id":"ckcY","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"ping"}]}]}],"channel":"<channel>","event_ts":"1623965305.000200","channel_type":"im"},"type":"event_callback","event_id":"Ev025MBNNNLC","event_time":1623965305,"authorizations":[{"enterprise_id":null,"team_id":"<team>","user_id":"<user>","is_bot":true,"is_enterprise_install":false}],"is_ext_shared_channel":false,"event_context":"2-message-T065FDZTQ-A02305WBY31-D024FNJ3953"},"type":"events_api","accepts_response_payload":false,"retry_attempt":0,"retry_reason":""}
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:430: Scheduling Socket Mode response for envelope ID 9159361e-b381-4801-85a5-eedad48bc59a: {"envelope_id":"9159361e-b381-4801-85a5-eedad48bc59a"}
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:312: Sending Socket Mode response with envelope ID "9159361e-b381-4801-85a5-eedad48bc59a": &{9159361e-b381-4801-85a5-eedad48bc59a <nil>}
    I've been asked to ping-pong!
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:321: Finished sending Socket Mode response with envelope ID "9159361e-b381-4801-85a5-eedad48bc59a"
    slack-go/slack2021/06/17 14:28:25 chat.go:233: Sending request: attachments=%5B%5D&blocks=%5B%5D&channel=<channel>&text=pong&token=<token>
    

    (I have obviously taken out anything potentially sensitive/security-related)

    Since I can see the response being sent, I'm not sure where to check next to see what the problem might be -- all of the connection, auth, etc seems fine. Any suggestions would be very much appreciated -- thanks for your help!

    opened by mason-jones-ck 3
  • Support for Slash Commands

    Support for Slash Commands

    Slack's Slash Commands offer another method of invoking some kind of action from within Slack, much like bot commands can do, but have the benefit of providing an arguably nicer user experience by pulling up a context pop up on how to invoke it, without requiring the user to memorize commands or to send a help message to a bot user.

    Given the similarities between slacker's bot commands and slash commands, seems like a logical step to support both, and with Socket Mode support, we now have that option.

    opened by arusso 0
  • HandleMessage with prefixed messages, not just mention or direct message

    HandleMessage with prefixed messages, not just mention or direct message

    I was just trying to trigger the bot with !<COMMAND_NAME> like !catch etc. commands. However, messages handled for only mention or direct message for slack.MessageEvent case. How can we add any condition like isCommandPrefixMatch or sth like this ?

    opened by icy95 1
  • Any sentence containing the word `help` anywhere will call the Help Command

    Any sentence containing the word `help` anywhere will call the Help Command

    Hi, I'm having some issues with the Help Command specification.

    Currently using in my code Slacker Git revision: 37d2f0fd93e4c63a1afaba092dc5bb548620fcb3

    Specifically I set a command to be something like:

    	// function tied to sentences sent to the Bot and starting with "open emergency" followed by some text
    	emergencyCmdDefinition := &slacker.CommandDefinition{
    		Description: "Open an EMERGENCY incident to Customer Support",
    		Handler: func(request slacker.Request, response slacker.ResponseWriter) {
    			if err := Emergency(request, response, config); err != nil {
    				Err(err.Error())
    				return
    			}
    		},
    	}
    	bot.Command("open emergency <msg>", emergencyCmdDefinition)
    

    and then added the Help function as:

    	// set the "help" message handling function
    	helpCmdDefinition := &slacker.CommandDefinition{
    		Description: "Help function",
    		Handler: func(request slacker.Request, response slacker.ResponseWriter) {
    			help(response, config)
    		},
    	}
    	bot.Help(helpCmdDefinition)
    

    But any sentence that contains the help word will trigger the Help Command (I guess because that's parsed earlier from what I read in your code).

    Say that you write open emergency my printer is on fire... I need some help! that would still just print the help instead of triggering the open emergency command as it normally would.

    I'd just want the help command to be triggered when the ONLY word is "help"... otherwise IMO the rest of the parsing should happen (go through normal commands parsing and then hit the DefaultCommand).

    You can see the full code here: https://github.com/gravitational/slackbot/blob/master/slackbot.go#L74

    opened by eldios 7
Owner
Raed Shomali
A Software Engineer by Profession, a Photographer by Talent and a Joker by Nature.
Raed Shomali
IRC, Slack, Telegram and RocketChat bot written in go

go-bot IRC, Slack & Telegram bot written in Go using go-ircevent for IRC connectivity, nlopes/slack for Slack and Syfaro/telegram-bot-api for Telegram

null 686 Jul 17, 2021
Telegram Bot Framework for Go

Margelet Telegram Bot Framework for Go is based on telegram-bot-api It uses Redis to store it's states, configs and so on. Any low-level interactions

Gleb Sinyavskiy 62 Jul 15, 2021
easy-peasy wg tg bot

wireguard-telegram-bot Simple-Dimple Telegram Bot for Wireguard VPN config generation Functionality /menu — list available commands /newkeys — create

Sergey Skaredov 12 Jun 7, 2021
Flexible message router add-on for go-telegram-bot-api library.

telemux Flexible message router add-on for go-telegram-bot-api library. Table of contents Motivation Features Minimal example Documentation Changelog

Andrew Dunai 12 Jul 20, 2021
Chatto is a minimal chatbot framework in Go.

chatto Simple chatbot framework written in Go, with configurations in YAML. The aim of this project is to create very simple text-based chatbots using

Jaime Tenorio 88 Jul 12, 2021
Golang bindings for the Telegram Bot API

Golang bindings for the Telegram Bot API All methods are fairly self explanatory, and reading the godoc page should explain everything. If something i

null 3k Jul 23, 2021
Simple yet customizable bot framework written in Go.

Introduction Sarah is a general-purpose bot framework named after the author's firstborn daughter. This comes with a unique feature called "stateful c

Go Hagiwara 196 Jul 7, 2021
A golang implementation of a console-based trading bot for cryptocurrency exchanges

Golang Crypto Trading Bot A golang implementation of a console-based trading bot for cryptocurrency exchanges. Usage Download a release or directly bu

Alessandro Sanino 574 Jul 22, 2021
Kelp is a free and open-source trading bot for the Stellar DEX and 100+ centralized exchanges

Kelp Kelp is a free and open-source trading bot for the Stellar universal marketplace and for centralized exchanges such as Binance, Kraken, CoinbaseP

Stellar 714 Jul 25, 2021
Bot that polls activity API for Github organisation and pushes updates to Telegram.

git-telegram-bot Telegram bot for notifying org events Requirements (for building) Go version 1.16.x Setup If you don't have a telegram bot token yet,

Skycoin 3 May 13, 2021
A general-purpose bot library inspired by Hubot but written in Go. :robot:

Joe Bot ?? A general-purpose bot library inspired by Hubot but written in Go. Joe is a library used to write chat bots in the Go programming language.

Joe Bot 425 Jul 16, 2021
Golang Framework for writing Slack bots

hanu - Go for Slack Bots! The Go framework hanu is your best friend to create Slack bots! hanu uses allot for easy command and request parsing (e.g. w

Sebastian Müller 135 Jul 23, 2021
Telebot is a Telegram bot framework in Go.

Telebot "I never knew creating Telegram bots could be so sexy!" go get -u gopkg.in/tucnak/telebot.v2 Overview Getting Started Poller Commands Files Se

Ian P Badtrousers 2k Jul 22, 2021
Slack bot core/framework written in Go with support for reactions to message updates/deletes

Overview Requirements Features Demo The Name Concepts Create Your Own Slackscot Assembling the Parts and Bringing Your slackscot to Life Configuration

Alexandre Normand 45 Jun 27, 2021