Class: SlackBotServer::Bot

Inherits:
Object
  • Object
show all
Extended by:
Logging
Includes:
Logging
Defined in:
lib/slack_bot_server/bot.rb

Overview

A superclass for integration bot implementations.

A simple example:

class MyBot < SlackBotServer::Bot
  # Set the friendly username displayed in Slack
  username 'My Bot'
  # Set the image to use as an avatar icon in Slack
  icon_url 'http://my.server.example.com/assets/icon.png'

  # Respond to mentions in the connected chat room (defaults to #general).
  # As well as the normal data provided by Slack's API, we add the `message`,
  # which is the `text` parameter with the username stripped out. For example,
  # When a user sends 'simple_bot: how are you?', the `message` data contains
  # only 'how are you'.
  on_mention do |data|
    if data['message'] == 'who are you'
      reply text: "I am #{bot_user_name} (user id: #{bot_user_id}, connected to team #{team_name} with team id #{team_id}"
    else
      reply text: "You said '#{data['message']}', and I'm frankly fascinated."
    end
  end

  # Respond to messages sent via IM communication directly with the bot.
  on_im do
    reply text: "Hmm, OK, let me get back to you about that."
  end
end

Direct Known Subclasses

SimpleBot

Defined Under Namespace

Classes: ConnectionError

Constant Summary collapse

SLACKBOT_USER_ID =

The user ID of the special slack user SlackBot

'USLACKBOT'

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

debug, log, log_error, log_string

Constructor Details

#initialize(token:, key: nil) ⇒ Bot

Create a new bot. This is normally called from within the block passed to Server#on_add, which should return a new bot instance.

Parameters:

  • token (String)

    the Slack bot token to use for authentication

  • key (String) (defaults to: nil)

    a key used to target messages to this bot from your application when using RemoteControl. If not provided, this defaults to the token.



54
55
56
57
58
59
# File 'lib/slack_bot_server/bot.rb', line 54

def initialize(token:, key: nil)
  @token = token
  @key = key || @token
  @connected = false
  @running = false
end

Class Attribute Details

.mention_keywordsObject (readonly)

Returns the value of attribute mention_keywords.



205
206
207
# File 'lib/slack_bot_server/bot.rb', line 205

def mention_keywords
  @mention_keywords
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.



41
42
43
# File 'lib/slack_bot_server/bot.rb', line 41

def key
  @key
end

#tokenObject (readonly)

Returns the value of attribute token.



41
42
43
# File 'lib/slack_bot_server/bot.rb', line 41

def token
  @token
end

Class Method Details

.callbacksObject

All callbacks defined on this class



261
262
263
# File 'lib/slack_bot_server/bot.rb', line 261

def callbacks
  @callbacks ||= {}
end

.callbacks_for(type) ⇒ Object

Returns all callbacks (including those in superclasses) for a given event type



267
268
269
270
271
272
273
274
275
# File 'lib/slack_bot_server/bot.rb', line 267

def callbacks_for(type)
  if superclass.respond_to?(:callbacks_for)
    matching_callbacks = superclass.callbacks_for(type)
  else
    matching_callbacks = []
  end
  matching_callbacks += callbacks[type.to_sym] if callbacks[type.to_sym]
  matching_callbacks
end

.default_message_optionsObject

Holds default options to send with each message to Slack



256
257
258
# File 'lib/slack_bot_server/bot.rb', line 256

def default_message_options
  @default_message_options ||= {type: 'message'}
end

.icon_url(url) ⇒ Object

Sets the image to use as an avatar for this bot

class MyBot < SlackBotServer::Bot
  icon_url 'http://example.com/bot.png'

  # etc
end


228
229
230
# File 'lib/slack_bot_server/bot.rb', line 228

def icon_url(url)
  default_message_options[:icon_url] = url
end

.low_level_callbacksObject



337
338
339
# File 'lib/slack_bot_server/bot.rb', line 337

def low_level_callbacks
  @low_level_callbacks ||= []
end

.mention_as(*keywords) ⇒ Object

Sets the keywords in messages that will trigger the on_mention callback

class MyBot < SlackBotServer::Bot
  mention_as 'hey', 'bot'

  # etc
end

will mean the on_mention callback fires for messages like “hey you!” and “bot, what are you thinking”.

Mention keywords are only matched at the start of messages, so the text “I love you, bot” won’t trigger this callback. To implement general keyword spotting, use a custom on :message callback.

If this is not called, the default mention keyword is the bot username, e.g. simple_bot



251
252
253
# File 'lib/slack_bot_server/bot.rb', line 251

def mention_as(*keywords)
  @mention_keywords = keywords
end

.on(type, &block) ⇒ Object

Register a callback

class MyBot < SlackBotServer::Bot
  on :message do
    reply text: 'I heard a message, so now I am responding!'
  end
end

Possible callbacks are:

+:start+ :: fires when the bot establishes a connection to Slack
+:finish+ :: fires when the bot is disconnected from Slack
+:message+ :: fires when any message is sent in any channel the bot is
              connected to

Multiple blocks for each type can be registered; they will be run in the order they are defined.

If any block returns false, later blocks will not be fired.



295
296
297
298
# File 'lib/slack_bot_server/bot.rb', line 295

def on(type, &block)
  callbacks[type.to_sym] ||= []
  callbacks[type.to_sym] << block
end

.on_im(&block) ⇒ Object

Define a callback to run when any a user sends a direct message to this bot



327
328
329
330
331
332
333
334
335
# File 'lib/slack_bot_server/bot.rb', line 327

def on_im(&block)
  on(:message) do |data|
    debug on_im: data, bot_message: bot_message?(data), is_im_channel: is_im_channel?(data.channel)
    if !bot_message?(data) && is_im_channel?(data.channel)
      @last_received_user_message.merge!(message: data.text)
      instance_exec(@last_received_user_message, &block)
    end
  end
end

.on_mention(&block) ⇒ Object

Define a callback to run when any of the mention keywords are present in a message.

Typically this will be for messages in open channels, where as user directs a message to this bot, e.g. “@simple_bot hello”

By default, the mention keyword is simply the bot’s username e.g. simple_bot

As well as the raw Slack data about the message, the data Hash yielded to the given block will contain a ‘message’ key, which holds the text sent with the keyword removed.



312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/slack_bot_server/bot.rb', line 312

def on_mention(&block)
  on(:message) do |data|
    debug on_message: data, bot_message: bot_message?(data)
    if !bot_message?(data) &&
       (data.text =~ /\A(#{mention_keywords.join('|')})[\s\:](.*)/i ||
        data.text =~ /\A(<@#{bot_user_id}>)[\s\:](.*)/)
      message = $2.strip
      @last_received_user_message.merge!(message: message)
      instance_exec(@last_received_user_message, &block)
    end
  end
end

.on_slack_event(name, &block) ⇒ Object

Define a callback to use when a low-level slack event is fired



342
343
344
# File 'lib/slack_bot_server/bot.rb', line 342

def on_slack_event(name, &block)
  self.low_level_callbacks << [name, block]
end

.username(name) ⇒ Object

Sets the username this bot should use

class MyBot < SlackBotServer::Bot
  username 'My Bot'

  # etc
end

will result in the friendly name ‘My Bot’ appearing beside the messages in your Slack rooms



217
218
219
# File 'lib/slack_bot_server/bot.rb', line 217

def username(name)
  default_message_options[:username] = name
end

Instance Method Details

#bot_user_idObject

Returns the ID of the bot user we are connected as, e.g. ‘U123456’



68
69
70
# File 'lib/slack_bot_server/bot.rb', line 68

def bot_user_id
  client.self.id
end

#bot_user_nameObject

Returns the username (for @ replying) of the bot user we are connected as, e.g. ‘simple_bot’



63
64
65
# File 'lib/slack_bot_server/bot.rb', line 63

def bot_user_name
  client.self.name
end

#broadcast(options) ⇒ Object

Sends a message to every channel this bot is a member of

Parameters:

  • options (Hash)

    As #say, although the :channel option is redundant



106
107
108
109
110
# File 'lib/slack_bot_server/bot.rb', line 106

def broadcast(options)
  client.channels.each do |id, _|
    say(options.merge(channel: id))
  end
end

#call(method, args) ⇒ Object

Call a method directly on the Slack web API (via Slack::Web::Client). Useful for debugging only.



142
143
144
145
# File 'lib/slack_bot_server/bot.rb', line 142

def call(method, args)
  args.symbolize_keys!
  client.web_client.send(method, args)
end

#connected?Boolean

Returns true if this bot is currently connected to Slack

Returns:

  • (Boolean)


200
201
202
# File 'lib/slack_bot_server/bot.rb', line 200

def connected?
  @connected
end

#reply(options) ⇒ Object

Sends a reply to the same channel as the last message that was received by this bot.

Parameters:

  • options (Hash)

    As #say, although the :channel option is redundant



116
117
118
119
# File 'lib/slack_bot_server/bot.rb', line 116

def reply(options)
  channel = @last_received_user_message.channel
  say(options.merge(channel: channel))
end

#running?Boolean

Returns true if this bot is (or should be) running

Returns:

  • (Boolean)


195
196
197
# File 'lib/slack_bot_server/bot.rb', line 195

def running?
  @running
end

#say(options) ⇒ Object

Send a message to Slack

Parameters:

  • options (Hash)

    a hash containing any of the following:

    channel

    the name (‘#general’), or the ID of the channel to send to

    text

    the actual text of the message

    username

    the name the message should appear from; defaults to the value given to username in the Bot class definition

    icon_url

    the image url to use as the avatar for this message; defaults to the value given to icon_url in the Bot class definition



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/slack_bot_server/bot.rb', line 91

def say(options)
  message = symbolize_keys(default_message_options.merge(options))

  if rtm_incompatible_message?(message)
    debug "Sending via Web API", message
    client.web_client.chat_postMessage(message)
  else
    debug "Sending via RTM API", message
    client.message(message)
  end
end

#say_to(user_id, options) ⇒ Object

Sends a message via IM to a user

Parameters:

  • user_id (String)

    the Slack user ID of the person to receive this message

  • options (Hash)

    As #say, although the :channel option is redundant



125
126
127
128
129
# File 'lib/slack_bot_server/bot.rb', line 125

def say_to(user_id, options)
  result = client.web_client.im_open(user: user_id)
  channel = result.channel.id
  say(options.merge(channel: channel))
end

#startObject

Starts the bot running. You should not call this method; instead, the server will call it when it is ready for the bot to connect

See Also:



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/slack_bot_server/bot.rb', line 151

def start
  @client = ::Slack::RealTime::Client.new(token: @token)
  @running = true

  client.on :open do |event|
    @connected = true
    log "connected to '#{team_name}'"
    run_callbacks(:start)
  end

  client.on :message do |data|
    begin
      debug message: data
      @last_received_user_message = data if user_message?(data)
      handle_message(data)
    rescue => e
      log_error e
    end
  end

  client.on :close do |event|
    log "disconnected"
    @connected = false
    run_callbacks(:finish)
  end

  register_low_level_callbacks

  client.start_async
rescue Slack::Web::Api::Error => e
  raise ConnectionError.new(e.message, e.response)
end

#stopObject

Stops the bot from running. You should not call this method; instead send the server a remote_bot message

See Also:



187
188
189
190
191
192
# File 'lib/slack_bot_server/bot.rb', line 187

def stop
  log "closing connection"
  @running = false
  client.stop!
  log "closed"
end

#team_idObject

Returns the ID of the team we are connected to, e.g. ‘T234567’



78
79
80
# File 'lib/slack_bot_server/bot.rb', line 78

def team_id
  client.team.id
end

#team_nameObject

Returns the name of the team we are connected to, e.g. ‘My Team’



73
74
75
# File 'lib/slack_bot_server/bot.rb', line 73

def team_name
  client.team.name
end

#to_sObject

Returns a String representation of this SlackBotServer::Bot

Returns:

  • String



353
354
355
# File 'lib/slack_bot_server/bot.rb', line 353

def to_s
  "<#{self.class.name} key:#{key}>"
end

#typing(options = {}) ⇒ Object

Sends a typing notification

Parameters:

  • options (Hash) (defaults to: {})

    can contain :channel, which should be an ID; if no options are provided, the channel from the most recently recieved message is used



134
135
136
137
138
# File 'lib/slack_bot_server/bot.rb', line 134

def typing(options={})
  last_received_channel = @last_received_user_message ? @last_received_user_message.channel : nil
  default_options = {channel: last_received_channel}
  client.typing(default_options.merge(options))
end