slack

package
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Apr 28, 2019 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package slack provides sarah.Adapter implementation for Slack.

Index

Constants

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

Variables

This section is empty.

Functions

func NewPostMessageResponse

func NewPostMessageResponse(input sarah.Input, message string, attachments []*webapi.MessageAttachment) *sarah.CommandResponse

NewPostMessageResponse can be used by plugin command to send message with customizable attachments. Use NewStringResponse for simple text response.

func NewPostMessageResponseWithNext

func NewPostMessageResponseWithNext(input sarah.Input, message string, attachments []*webapi.MessageAttachment, next sarah.ContextualFunc) *sarah.CommandResponse

NewPostMessageResponseWithNext can be used by plugin command to send message with customizable attachments, and keep the user in the middle of conversation. Use NewStringResponse for simple text response.

With this method user context is directly stored as an anonymous function since Slack Bot works with single WebSocket connection and hence usually works with single process. To use external storage to store user context, use go-sarah-rediscontext or similar sarah.UserContextStorage implementation.

func NewStringResponse

func NewStringResponse(responseContent string) *sarah.CommandResponse

NewStringResponse creates new sarah.CommandResponse instance with given string.

func NewStringResponseWithNext

func NewStringResponseWithNext(responseContent string, next sarah.ContextualFunc) *sarah.CommandResponse

NewStringResponseWithNext creates new sarah.CommandResponse instance with given string and next function to continue

With this method user context is directly stored as an anonymous function since Slack Bot works with single WebSocket connection and hence usually works with single process. To use external storage to store user context, use go-sarah-rediscontext or similar sarah.UserContextStorage implementation.

Types

type Adapter

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

Adapter internally calls Slack Rest API and Real Time Messaging API to offer Bot developers easy way to communicate with Slack.

This implements sarah.Adapter interface, so this instance can be fed to sarah.Runner as below.

runnerOptions := sarah.NewRunnerOptions()

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)
runnerOptions.Append(sarah.WithBot(slackBot))

runner := sarah.NewRunner(sarah.NewConfig(), runnerOptions.Arg())
runner.Run(context.TODO())

func NewAdapter

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

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

func (*Adapter) BotType

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

BotType returns BotType of this particular instance.

func (*Adapter) Run

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

Run establishes connection with Slack, supervise it, and tries to reconnect when current connection is gone. Connection will be

When message is sent from slack server, the payload is passed to sarah.Runner via the function given as 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.

When critical situation such as reconnection trial fails for specified times, this critical situation is notified to sarah.Runner via 3rd argument function, notifyErr. sarah.Runner cancels this Bot/Adapter and related resources when BotNonContinuableError is given to this function.

func (*Adapter) SendMessage

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

SendMessage let Bot send message to Slack.

type AdapterOption

type AdapterOption func(adapter *Adapter) error

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

func WithPayloadHandler

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

WithPayloadHandler creates AdapterOption with given function that is called when payload is sent from Slack via WebSocket connection.

Slack's RTM API defines relatively large amount of payload types. To have better user experience, developers may provide customized callback function to handle received payload.

Developer may wish to have direct access to SlackClient to post some sort of message to Slack via Web API. In that case, 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)

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

  case *rtmapi.Message:
    // Convert RTM specific message to one that satisfies sarah.Input interface.
    input := &MessageInput{event: p}

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

  default:
    log.Debugf("payload given, but no corresponding action is defined. %#v", p)

  }
}

slackAdapter, _ := slack.NewAdapter(slackConfig, slack.WithSlackClient(slackClient), slack.WithPayloadHandler(payloadHandler))
slackBot, _ := sarah.NewBot(slackAdapter)

func WithSlackClient

func WithSlackClient(client SlackClient) AdapterOption

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

type Config

type Config struct {
	Token            string        `json:"token" yaml:"token"`
	HelpCommand      string        `json:"help_command" yaml:"help_command"`
	AbortCommand     string        `json:"abort_command" yaml:"abort_command"`
	SendingQueueSize uint          `json:"sending_queue_size" yaml:"sending_queue_size"`
	RequestTimeout   time.Duration `json:"request_timeout" yaml:"request_timeout"`
	PingInterval     time.Duration `json:"ping_interval" yaml:"ping_interval"`
	RetryPolicy      *retry.Policy `json:"retry_policy" yaml:"retry_policy"`
}

Config contains some configuration variables for slack Adapter.

func NewConfig

func NewConfig() *Config

NewConfig returns initialized Config struct with default settings. Token is empty at this point. Token can be set by feeding this instance to json.Unmarshal/yaml.Unmarshal, or direct assignment.

type MessageInput

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

MessageInput satisfies Input interface

func NewMessageInput

func NewMessageInput(message *rtmapi.Message) *MessageInput

NewMessageInput creates and returns MessageInput instance.

func (*MessageInput) Message

func (message *MessageInput) Message() string

Message returns sent message.

func (*MessageInput) ReplyTo

func (message *MessageInput) ReplyTo() sarah.OutputDestination

ReplyTo returns slack channel to send reply to.

func (*MessageInput) SenderKey

func (message *MessageInput) SenderKey() string

SenderKey returns string representing message sender.

func (*MessageInput) SentAt

func (message *MessageInput) SentAt() time.Time

SentAt returns message event's timestamp.

type SlackClient

type SlackClient interface {
	StartRTMSession(context.Context) (*webapi.RTMStart, error)
	ConnectRTM(context.Context, string) (rtmapi.Connection, error)
	PostMessage(context.Context, *webapi.PostMessage) (*webapi.APIResponse, 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