slack

package
v4.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2022 License: MIT Imports: 14 Imported by: 2

Documentation

Overview

Package slack provides a sarah.Adapter implementation for Slack.

Index

Constants

View Source
const (
	// SLACK is a designated sara.BotType for Slack integration.
	SLACK sarah.BotType = "slack"
)

Variables

View Source
var ErrNonSupportedEvent = errors.New("event not supported")

ErrNonSupportedEvent is returned when the given Slack event is not supported by this adapter.

Functions

func DefaultEventsPayloadHandler

func DefaultEventsPayloadHandler(_ context.Context, config *Config, payload *eventsapi.EventWrapper, enqueueInput func(input sarah.Input) error)

DefaultEventsPayloadHandler receives incoming events, converts them to sarah.Input, and then passes them to enqueueInput. To replace this default behavior, define a function with the same signature and replace this.

myHandler := func(_ context.Context, _ config *Config, _ *eventsapi.EventWrapper, _ func(sarah.Input) error) {}
slackAdapter, _ := slack.NewAdapter(slackConfig, slack.WithEventsPayloadHandler(myHandler))

func DefaultRTMPayloadHandler

func DefaultRTMPayloadHandler(_ context.Context, config *Config, payload rtmapi.DecodedPayload, enqueueInput func(sarah.Input) error)

DefaultRTMPayloadHandler receives incoming events, converts them to sarah.Input, and then passes them to enqueueInput. To replace this default behavior, define a function with the same signature and replace this.

myHandler := func(_ context.Context, config *Config, _ rtmapi.DecodedPayload, _ func(sarah.Input) error) {}
slackAdapter, _ := slack.NewAdapter(slackConfig, slack.WithRTMPayloadHandler(myHandler))

func EventToInput

func EventToInput(e interface{}) (sarah.Input, error)

EventToInput converts the given event payload to *Input.

func IsThreadMessage

func IsThreadMessage(input *Input) bool

IsThreadMessage tells if the given message is sent in a thread. If the message is sent in a thread, this is encouraged to reply in a thread. NewResponse, therefore, defaults to send a response as a thread reply when the input is sent in a thread. Use RespAsThreadReply to modify the behavior.

func NewResponse

func NewResponse(input sarah.Input, msg string, options ...RespOption) (*sarah.CommandResponse, error)

NewResponse creates *sarah.CommandResponse with the given arguments. Simply pass a received sarah.Input instance and a text string to send a text message as a reply. To send a more customized reply message, pass as many options created by ResponseWith* functions as required.

When an input is sent in a thread, this function defaults to send a response as a thread reply. To explicitly change such behavior, use RespAsThreadReply or RespReplyBroadcast.

Types

type Adapter

type Adapter struct {
	// contains filtered or unexported fields
}

Adapter is a sarah.Adapter implementation that internally calls Slack Rest API and Real Time Messaging API to offer Bot developers an easy way to communicate with Slack.

slackConfig := slack.NewConfig()
slackConfig.Token = "XXXXXXXXXXXX" // Set token manually or feed slackConfig to json.Unmarshal or yaml.Unmarshal
slackAdapter, _ := slack.NewAdapter(slackConfig)
slackBot, _ := sarah.NewBot(slackAdapter)
sarah.RegisterBot(slackBot)

sarah.Run(context.TODO(), sarah.NewConfig())

func NewAdapter

func NewAdapter(config *Config, options ...AdapterOption) (*Adapter, error)

NewAdapter creates a new Adapter with the given *Config and zero or more AdapterOption values.

func (*Adapter) BotType

func (adapter *Adapter) BotType() sarah.BotType

BotType returns a designated BotType for Slack integration.

func (*Adapter) Run

func (adapter *Adapter) Run(ctx context.Context, enqueueInput func(sarah.Input) error, notifyErr func(error))

Run establishes a connection with Slack, supervises it, and tries to reconnect when the current connection is gone.

When a message is sent from the Slack server, the payload is passed to Sarah via the function given as the 2nd argument -- enqueueInput. This function simply wraps a channel to prevent blocking situation. When workers are too busy and channel blocks, this function returns BlockedInputError.

Upon a critical situation such as consecutive reconnection trial failures, such a state is notified to Sarah via the 3rd argument function -- notifyErr. Sarah cancels this Bot/Adapter and cleans up related resources when BotNonContinuableError is given to this function.

func (*Adapter) SendMessage

func (adapter *Adapter) SendMessage(ctx context.Context, output sarah.Output)

SendMessage lets sarah.Bot send a message to Slack.

type AdapterOption

type AdapterOption func(adapter *Adapter)

AdapterOption defines a function's signature that Adapter's functional options must satisfy.

func WithEventsPayloadHandler

func WithEventsPayloadHandler(fnc func(context.Context, *Config, *eventsapi.EventWrapper, func(sarah.Input) error)) AdapterOption

WithEventsPayloadHandler creates an AdapterOption with the given function to handle incoming Events API payloads. The simplest example to receive a message payload is to use a default payload handler as below:

slackAdapter, _ := slack.NewAdapter(slackConfig, slack.WithEventsPayloadHandler(slack.DefaultEventsPayloadHandler))

See WithRTMPayloadHandler for the detailed usage. WithEventsPayloadHandler is just another form of payload handler to work with Events API.

func WithRTMPayloadHandler

func WithRTMPayloadHandler(fnc func(context.Context, *Config, rtmapi.DecodedPayload, func(sarah.Input) error)) AdapterOption

WithRTMPayloadHandler creates an AdapterOption with the given function to handle incoming RTM payloads. The simplest example to receive message payloads is to use a default payload handler as below:

slackAdapter, _ := slack.NewAdapter(slackConfig, slack.WithRTMPayloadHandler(DefaultRTMPayloadHandler))

However, Slack's RTM API defines a relatively large amount of payload types. To have a better user experience, developers may provide a customized callback function to handle different types of received payloads. In that case, one may implement a new payload handler and replace DefaultRTMPayloadHandler. Inside the customized payload handler, a developer may wish to have direct access to SlackClient to post some sort of message to Slack via Web API. To support such a scenario, wrap this function like below so the SlackClient can be accessed within its scope.

 // Setup golack instance, which implements SlackClient interface.
 golackConfig := golack.NewConfig()
 golackConfig.Token = "XXXXXXX"
 slackClient := golack.New(golackConfig)

 rtmPayloadHandler := func(connCtx context.Context, config *Config, payload rtmapi.DecodedPayload, enqueueInput func(sarah.Input) error) {
		switch p := payload.(type) {
 	case *event.PinAdded:
			// Do something with pre-defined SlackClient
   		// slackClient.PostMessage(connCtx, ...)

   	default:
   		input, err := EventToInput(p)
   		if err == ErrNonSupportedEvent {
    			log.Debugf("Event given, but no corresponding action is defined. %#v", payload)
    			return
   		}

   		if err != nil {
    			log.Errorf("Failed to convert %T event: %s", p, err.Error())
    			return
   		}

   		trimmed := strings.TrimSpace(input.Message())
   		if config.HelpCommand != "" && trimmed == config.HelpCommand {
    			// Help command
    			help := sarah.NewHelpInput(input)
    			_ = enqueueInput(help)
   		} else if config.AbortCommand != "" && trimmed == config.AbortCommand {
    			// Abort command
    			abort := sarah.NewAbortInput(input)
    			_ = enqueueInput(abort)
   		} else {
    			// Regular input
    			_ = enqueueInput(input)
   		}
   	}
 }

 slackConfig := slack.NewConfig()
 slackAdapter, _ := slack.NewAdapter(slackConfig, slack.WithSlackClient(slackClient), slack.WithRTMPayloadHandler(rtmPayloadHandler))
 slackBot, _ := sarah.NewBot(slackAdapter)

func WithSlackClient

func WithSlackClient(client SlackClient) AdapterOption

WithSlackClient creates an AdapterOption with the given SlackClient implementation. If this option is not given, NewAdapter tries to create golack instance with the given Config.

type Config

type Config struct {
	// Token declares the API token to integrate with Gitter.
	Token string `json:"token" yaml:"token"`

	// AppSecret declares the application secret issued by Slack.
	AppSecret string `json:"app_secret" yaml:"app_secret"`

	// ListenPort declares the port number that receives requests from Slack.
	ListenPort int `json:"listen_port" yaml:"listen_port"`

	// HelpCommand declares the command string that is converted to sarah.HelpInput.
	HelpCommand string `json:"help_command" yaml:"help_command"`

	// AbortCommand declares the command string to abort the current user context.
	AbortCommand string `json:"abort_command" yaml:"abort_command"`

	// SendingQueueSize declares the capacity of the outgoing message queue.
	SendingQueueSize uint `json:"sending_queue_size" yaml:"sending_queue_size"`

	// RequestTimeout declares the timeout interval for the Slack API calls.
	RequestTimeout time.Duration `json:"request_timeout" yaml:"request_timeout"`

	// PingInterval declares the ping interval for RTM API interaction.
	PingInterval time.Duration `json:"ping_interval" yaml:"ping_interval"`

	// RetryPolicy declares how a retrial for an API call should behave.
	RetryPolicy *retry.Policy `json:"retry_policy" yaml:"retry_policy"`
}

Config contains some configuration variables for Slack Adapter.

func NewConfig

func NewConfig() *Config

NewConfig creates and returns a new Config instance with default settings. Token and AppSecret are empty at this point as there can not be default values. Use json.Unmarshal, yaml.Unmarshal, or manual manipulation to populate the blank value or override those default values.

type Input

type Input struct {
	Event interface{}
	// contains filtered or unexported fields
}

Input is a sarah.Input implementation that represents a received message. Pass an incoming payload to EventToInput for a conversion.

func (*Input) Message

func (i *Input) Message() string

Message returns the received text.

func (*Input) ReplyTo

func (i *Input) ReplyTo() sarah.OutputDestination

ReplyTo returns the Slack channel where the message was sent.

func (*Input) SenderKey

func (i *Input) SenderKey() string

SenderKey returns the message sender's id.

func (*Input) SentAt

func (i *Input) SentAt() time.Time

SentAt returns when the message is sent.

type RespOption

type RespOption func(*respOptions)

RespOption defines a function's signature that NewResponse's functional option must satisfy.

func RespAsThreadReply

func RespAsThreadReply(asReply bool) RespOption

RespAsThreadReply specifies if the response should be sent as a thread reply.

func RespReplyBroadcast

func RespReplyBroadcast(broadcast bool) RespOption

RespReplyBroadcast decides if the thread reply should be broadcast. To activate this option, RespAsThreadReply must be set to true.

func RespWithAttachments

func RespWithAttachments(attachments []*webapi.MessageAttachment) RespOption

RespWithAttachments adds given attachments to the response.

func RespWithLinkNames

func RespWithLinkNames(linkNames int) RespOption

RespWithLinkNames sets the given linkNames value to the response. Set 1 to linkify channel names and usernames in the response. The default value is 1.

func RespWithNext

func RespWithNext(fnc sarah.ContextualFunc) RespOption

RespWithNext sets a given fnc as part of the response's *sarah.UserContext. The next input from the same user will be passed to this fnc. sarah.UserContextStorage must be configured or otherwise, the function will be ignored.

func RespWithNextSerializable

func RespWithNextSerializable(arg *sarah.SerializableArgument) RespOption

RespWithNextSerializable sets the given arg as part of the response's *sarah.UserContext. The next input from the same user will be passed to the function defined in the arg. sarah.UserContextStorage must be configured or otherwise, the function will be ignored.

func RespWithParse

func RespWithParse(mode webapi.ParseMode) RespOption

RespWithParse sets the given mode value to the response. The default value is webapi.ParseModeFull.

func RespWithUnfurlLinks(unfurl bool) RespOption

RespWithUnfurlLinks sets the given unfurl value to the response. The default value is true.

func RespWithUnfurlMedia

func RespWithUnfurlMedia(unfurl bool) RespOption

RespWithUnfurlMedia sets the given unfurl value to the response. The default value is true.

type SlackClient

type SlackClient interface {
	ConnectRTM(ctx context.Context) (rtmapi.Connection, error)
	PostMessage(ctx context.Context, message *webapi.PostMessage) (*webapi.APIResponse, error)
	RunServer(ctx context.Context, receiver eventsapi.EventReceiver) <-chan error
}

SlackClient is an interface that covers golack's public methods.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL