bot_mob 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/server.rb +4 -1
- data/lib/bot_mob.rb +2 -2
- data/lib/bot_mob/bot.rb +18 -19
- data/lib/bot_mob/inbound_message.rb +86 -8
- data/lib/bot_mob/logger.rb +22 -0
- data/lib/bot_mob/networks/roaming.rb +2 -1
- data/lib/bot_mob/networks/roaming/inbound_message.rb +15 -0
- data/lib/bot_mob/networks/slack.rb +4 -1
- data/lib/bot_mob/networks/slack/inbound_message.rb +36 -0
- data/lib/bot_mob/roster.rb +25 -2
- data/lib/bot_mob/server.rb +19 -17
- data/lib/bot_mob/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b85965cd3ed7759eb4a7d79ca601dc94536cf04
|
4
|
+
data.tar.gz: 22edb2f9215b9e1414dab19908b5d33001897e65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82652bacc7af4349f248d6674c480fc96ee0ab6c682a70c7147099808a40c01a0c2b24d31c725cf8725b20a6b2e8e651aee65c124978597f773b9eb503331164
|
7
|
+
data.tar.gz: 7dbfbfd3c16abb88e1230e7227138b1741d47256753d3ebff5cc31fe7632c72739e3bfe2740fc992cb189d7b054c18b5612d6ba32c9dee31312b54e9e342ddd2
|
data/examples/server.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
require 'dotenv'
|
1
2
|
require_relative 'fizz_buzz_bot'
|
2
3
|
require_relative 'hello_bot'
|
3
4
|
|
5
|
+
Dotenv.load
|
6
|
+
|
4
7
|
BotMob.start! do |app|
|
5
8
|
app.register FizzBuzzBot
|
6
|
-
app.register HelloBot.new(
|
9
|
+
app.register HelloBot.new(slack: { token: ENV['SLACK_TOKEN'] })
|
7
10
|
end
|
data/lib/bot_mob.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'logger'
|
2
|
-
require 'slack-ruby-client'
|
3
2
|
require 'bot_mob/core_ext/hash'
|
4
3
|
require 'bot_mob/core_ext/string'
|
5
4
|
require 'bot_mob/version'
|
@@ -19,6 +18,7 @@ module BotMob
|
|
19
18
|
autoload :Command, 'bot_mob/command'
|
20
19
|
autoload :Connection, 'bot_mob/connection'
|
21
20
|
autoload :InboundMessage, 'bot_mob/inbound_message'
|
21
|
+
autoload :Logger, 'bot_mob/logger'
|
22
22
|
autoload :OutboundMessage, 'bot_mob/outbound_message'
|
23
23
|
autoload :Roster, 'bot_mob/roster'
|
24
24
|
autoload :Server, 'bot_mob/server'
|
@@ -61,7 +61,7 @@ module BotMob
|
|
61
61
|
# Provide a logger for the BotMob gem, silences test env output by default
|
62
62
|
def self.logger
|
63
63
|
@logger ||= begin
|
64
|
-
buffer = Logger.new(ENV['MOB_ENV'] == 'test' ? '/dev/null' : STDOUT)
|
64
|
+
buffer = BotMob::Logger.new(ENV['MOB_ENV'] == 'test' ? '/dev/null' : STDOUT)
|
65
65
|
if buffer
|
66
66
|
buffer.level = ($PROGRAM_NAME == 'irb' ? Logger::DEBUG : Logger::INFO)
|
67
67
|
buffer.formatter = proc { |_s, _d, _p, msg| "#{msg}\n" }
|
data/lib/bot_mob/bot.rb
CHANGED
@@ -56,13 +56,10 @@ module BotMob
|
|
56
56
|
def receive(message, options = {})
|
57
57
|
inbound_message = BotMob::InboundMessage.prepare(message, options)
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
unless
|
62
|
-
|
63
|
-
BotMob.logger.info(' > Does not warrant response')
|
64
|
-
end
|
65
|
-
|
59
|
+
BotMob.logger.log_request(self, :message, inbound_message.params)
|
60
|
+
BotMob.logger.info('-> Received message was from a bot') unless inbound_message.human?
|
61
|
+
unless respond?(inbound_message)
|
62
|
+
BotMob.logger.info('-> Does not warrant response')
|
66
63
|
return
|
67
64
|
end
|
68
65
|
|
@@ -77,11 +74,18 @@ module BotMob
|
|
77
74
|
# bot.receive('foo')
|
78
75
|
#
|
79
76
|
# Specify *message* as the received data
|
80
|
-
def receive_command(command)
|
81
|
-
BotMob.logger.
|
82
|
-
|
77
|
+
def receive_command(command, params = {})
|
78
|
+
BotMob.logger.log_request(self, :command, command: command)
|
79
|
+
|
80
|
+
return unless valid_command?(command)
|
83
81
|
|
84
|
-
|
82
|
+
begin
|
83
|
+
send(command, params)
|
84
|
+
rescue ArgumentError => e
|
85
|
+
BotMob.logger.warn("#{name}##{command} is not accepting parameters")
|
86
|
+
BotMob.logger.warn("ArgumentError - #{e.message}")
|
87
|
+
send(command)
|
88
|
+
end
|
85
89
|
end
|
86
90
|
|
87
91
|
# ## `valid_command?`
|
@@ -106,9 +110,9 @@ module BotMob
|
|
106
110
|
# contents of the inbound message. Commonly used for checking language
|
107
111
|
# used or regex matching of the inbound messages' contents.
|
108
112
|
#
|
109
|
-
# Defaults to true
|
110
|
-
def respond?(
|
111
|
-
|
113
|
+
# Defaults to true for human messages
|
114
|
+
def respond?(inbound_message)
|
115
|
+
inbound_message.human?
|
112
116
|
end
|
113
117
|
|
114
118
|
# ## `respond`
|
@@ -161,10 +165,5 @@ module BotMob
|
|
161
165
|
def log_responseless_activity?
|
162
166
|
BotMob.env.development?
|
163
167
|
end
|
164
|
-
|
165
|
-
def log_message(message)
|
166
|
-
BotMob.logger.info("#{name} received message at #{Time.now}")
|
167
|
-
BotMob.logger.info(" Parameters: #{message.params}")
|
168
|
-
end
|
169
168
|
end
|
170
169
|
end
|
@@ -3,24 +3,102 @@ module BotMob
|
|
3
3
|
#
|
4
4
|
# Structured data provided to a bot
|
5
5
|
class InboundMessage
|
6
|
-
attr_reader :body, :network
|
6
|
+
attr_reader :user_name, :body, :network
|
7
7
|
|
8
8
|
def initialize(**options)
|
9
|
-
@
|
10
|
-
@
|
9
|
+
@body ||= options[:body]
|
10
|
+
@network ||= options[:network]
|
11
|
+
|
12
|
+
provided_message_attributes(options).each do |attr|
|
13
|
+
instance_variable_set("@#{attr}".to_sym, options[attr.to_sym])
|
14
|
+
end
|
11
15
|
end
|
12
16
|
|
17
|
+
# ## `prepare`
|
18
|
+
#
|
19
|
+
# Prepare accepts three different data types and attempts to coerce
|
20
|
+
# it into a contextual inbound message. In the case of an inbound
|
21
|
+
# message, it simply assumes the provided message is already correct.
|
22
|
+
# In the case of a hash, it passes the hash along as the `initialize`
|
23
|
+
# attrs. In the case of a string, it overrides the `body` key of the
|
24
|
+
# provided options, then passes the options provided to `prepare` as
|
25
|
+
# the `initialize` params
|
13
26
|
def self.prepare(message, options = {})
|
14
27
|
return message if message.is_a?(BotMob::InboundMessage)
|
28
|
+
options.symbolize_keys!
|
29
|
+
|
30
|
+
approach = "prepare_#{message.class.to_s.downcase}_attrs".to_sym
|
31
|
+
attrs = send(approach, message, options)
|
32
|
+
message_delegate(attrs[:network]).new(attrs)
|
33
|
+
end
|
15
34
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
35
|
+
# ## `human?`
|
36
|
+
#
|
37
|
+
# This should be overrode in the inheriting bot class. Use this
|
38
|
+
# to determine if the inbound message was written by a human
|
39
|
+
def human?
|
40
|
+
ENV['MOB_NAME'] != user_name
|
20
41
|
end
|
21
42
|
|
43
|
+
# ## `params`
|
44
|
+
#
|
45
|
+
# A representation of the relevant data attached to a bot
|
22
46
|
def params
|
23
|
-
@params
|
47
|
+
@params ||= {
|
48
|
+
body: body,
|
49
|
+
network: network,
|
50
|
+
user_name: user_name
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
class << self
|
55
|
+
def message_attrs(*attrs)
|
56
|
+
@message_attrs = attrs
|
57
|
+
attr_reader(*@message_attrs)
|
58
|
+
end
|
59
|
+
|
60
|
+
def message_attributes
|
61
|
+
@message_attrs || []
|
62
|
+
end
|
63
|
+
|
64
|
+
def default_user_name
|
65
|
+
ENV['MOB_NAME'] || 'nomad'
|
66
|
+
end
|
67
|
+
|
68
|
+
def default_network
|
69
|
+
:roaming
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def prepare_hash_attrs(message, options)
|
75
|
+
attrs = message.symbolize_keys.merge(options)
|
76
|
+
attrs.merge(
|
77
|
+
network: attrs[:network] || default_network,
|
78
|
+
user_name: attrs[:user_name] || default_user_name
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def prepare_string_attrs(message, options)
|
83
|
+
options.merge(
|
84
|
+
network: options[:network] || default_network,
|
85
|
+
user_name: options[:user_name] || default_user_name,
|
86
|
+
body: message
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
def message_delegate(network)
|
91
|
+
delegate = BotMob::Networks.const_get(network.to_s.camelize)
|
92
|
+
delegate.const_get('InboundMessage')
|
93
|
+
rescue NameError
|
94
|
+
raise BotMob::InvalidNetworkError
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def provided_message_attributes(options)
|
101
|
+
self.class.message_attributes.select { |attr| options[attr.to_sym] }
|
24
102
|
end
|
25
103
|
end
|
26
104
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module BotMob
|
2
|
+
# # BotMob::Logger
|
3
|
+
#
|
4
|
+
# Wrapper for the logger implemented by BotMob
|
5
|
+
class Logger < ::Logger
|
6
|
+
OMITTED_PARAMS = %w(splat captures).freeze
|
7
|
+
|
8
|
+
def log_request(source, action = :request, params = {})
|
9
|
+
source_network = params[:network] || 'roaming'
|
10
|
+
ts = Time.now.strftime('%Y-%m-%d %H:%M:%S%Z')
|
11
|
+
|
12
|
+
info "\n#{source.name} received #{action} from :#{source_network} at #{ts}"
|
13
|
+
info "Parameters: #{logged_params(params).inspect}"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def logged_params(params)
|
19
|
+
params.reject { |k, _| OMITTED_PARAMS.include?(k) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -5,7 +5,8 @@ module BotMob
|
|
5
5
|
# The default network for a bot that has not yet connected to
|
6
6
|
# an external network
|
7
7
|
module Roaming
|
8
|
-
autoload :Connection,
|
8
|
+
autoload :Connection, 'bot_mob/networks/roaming/connection'
|
9
|
+
autoload :InboundMessage, 'bot_mob/networks/roaming/inbound_message'
|
9
10
|
autoload :OutboundMessage, 'bot_mob/networks/roaming/outbound_message'
|
10
11
|
end
|
11
12
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module BotMob
|
2
|
+
module Networks
|
3
|
+
module Roaming
|
4
|
+
# # BotMob::InboundMessage
|
5
|
+
#
|
6
|
+
# Structured data provided to a bot without a connected network
|
7
|
+
class InboundMessage < BotMob::InboundMessage
|
8
|
+
def initialize(**options)
|
9
|
+
@network = :roaming
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,10 +1,13 @@
|
|
1
|
+
require 'slack-ruby-client'
|
2
|
+
|
1
3
|
module BotMob
|
2
4
|
module Networks
|
3
5
|
# ## BotMob::Networks::Slack
|
4
6
|
#
|
5
7
|
# Network connection adapters to work with Slack
|
6
8
|
module Slack
|
7
|
-
autoload :Connection,
|
9
|
+
autoload :Connection, 'bot_mob/networks/slack/connection'
|
10
|
+
autoload :InboundMessage, 'bot_mob/networks/slack/inbound_message'
|
8
11
|
autoload :OutboundMessage, 'bot_mob/networks/slack/outbound_message'
|
9
12
|
end
|
10
13
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module BotMob
|
2
|
+
module Networks
|
3
|
+
module Slack
|
4
|
+
# # BotMob::InboundMessage
|
5
|
+
#
|
6
|
+
# Structured data provided to a bot by Slack via sinatra params
|
7
|
+
# {
|
8
|
+
# "token": "NiI3K5i7SORx0MAf8U9QRfCX",
|
9
|
+
# "team_id": "T09K1L491",
|
10
|
+
# "team_domain": "foobar",
|
11
|
+
# "service_id": "16319829032",
|
12
|
+
# "channel_id": "C29R5RZLN",
|
13
|
+
# "channel_name": "general",
|
14
|
+
# "timestamp": "1482729119.000014",
|
15
|
+
# "user_id": "U07R1RUJA",
|
16
|
+
# "user_name": "matthew",
|
17
|
+
# "text": "Hi Everyone!",
|
18
|
+
# "splat": [],
|
19
|
+
# "captures": [
|
20
|
+
# "slack"
|
21
|
+
# ],
|
22
|
+
# "network": "slack"
|
23
|
+
# }
|
24
|
+
class InboundMessage < BotMob::InboundMessage
|
25
|
+
message_attrs :domain, :channel_name, :user_name, :timestamp,
|
26
|
+
:token, :team_id, :service_id, :channel_id, :user_id
|
27
|
+
|
28
|
+
def initialize(**options)
|
29
|
+
@network = :slack
|
30
|
+
@body = options[:text]
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/bot_mob/roster.rb
CHANGED
@@ -10,8 +10,31 @@ module BotMob
|
|
10
10
|
@bots = []
|
11
11
|
end
|
12
12
|
|
13
|
-
def register(bot, **
|
14
|
-
@bots << (bot.is_a?(Class) ? bot.new : bot)
|
13
|
+
def register(bot, **options)
|
14
|
+
@bots << (bot.is_a?(Class) ? bot.new(options) : bot)
|
15
|
+
end
|
16
|
+
|
17
|
+
# ## `disseminate`
|
18
|
+
#
|
19
|
+
# This method will distribute a message or command to all bots
|
20
|
+
# on the roster. It collects and returns a compacted array
|
21
|
+
# of the bots' responses
|
22
|
+
def disseminate(action, params = {})
|
23
|
+
bots.map do |bot|
|
24
|
+
approach = "handle_#{action}".to_sym
|
25
|
+
respond_to?(approach, true) ? send(approach, bot, params) : nil
|
26
|
+
end.compact
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def handle_message(bot, params)
|
32
|
+
bot.receive(params)
|
33
|
+
end
|
34
|
+
|
35
|
+
def handle_command(bot, params)
|
36
|
+
method_name = params[:method].to_sym
|
37
|
+
bot.receive_command(method_name, params)
|
15
38
|
end
|
16
39
|
end
|
17
40
|
end
|
data/lib/bot_mob/server.rb
CHANGED
@@ -11,6 +11,10 @@ module BotMob
|
|
11
11
|
super
|
12
12
|
end
|
13
13
|
|
14
|
+
def name
|
15
|
+
'Server'
|
16
|
+
end
|
17
|
+
|
14
18
|
get '/' do
|
15
19
|
erb :index
|
16
20
|
end
|
@@ -19,29 +23,27 @@ module BotMob
|
|
19
23
|
erb :console
|
20
24
|
end
|
21
25
|
|
22
|
-
get '/
|
23
|
-
|
24
|
-
end
|
26
|
+
get '/:network/callback' do
|
27
|
+
BotMob.logger.log_request(self, :callback, params)
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
case params[:network].to_sym
|
30
|
+
when :facebook
|
31
|
+
params['hub.challenge']
|
32
|
+
else
|
33
|
+
erb :authorize
|
31
34
|
end
|
35
|
+
end
|
36
|
+
|
37
|
+
post '/:network/message' do
|
38
|
+
BotMob.logger.log_request(self, :message, params)
|
32
39
|
|
33
|
-
|
40
|
+
settings.roster.disseminate(:message, params).join(', ')
|
34
41
|
end
|
35
42
|
|
36
|
-
|
37
|
-
|
38
|
-
settings.roster.bots.map do |bot|
|
39
|
-
method_name = params[:method].to_sym
|
40
|
-
result = bot.receive_command(method_name)
|
41
|
-
results << result unless result.nil?
|
42
|
-
end
|
43
|
+
post '/:network/command/:method' do
|
44
|
+
BotMob.logger.log_request(self, :command, params)
|
43
45
|
|
44
|
-
|
46
|
+
settings.roster.disseminate(:command, params).join(', ')
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
data/lib/bot_mob/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bot_mob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Werner
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -168,11 +168,14 @@ files:
|
|
168
168
|
- lib/bot_mob/core_ext/string.rb
|
169
169
|
- lib/bot_mob/environment.rb
|
170
170
|
- lib/bot_mob/inbound_message.rb
|
171
|
+
- lib/bot_mob/logger.rb
|
171
172
|
- lib/bot_mob/networks/roaming.rb
|
172
173
|
- lib/bot_mob/networks/roaming/connection.rb
|
174
|
+
- lib/bot_mob/networks/roaming/inbound_message.rb
|
173
175
|
- lib/bot_mob/networks/roaming/outbound_message.rb
|
174
176
|
- lib/bot_mob/networks/slack.rb
|
175
177
|
- lib/bot_mob/networks/slack/connection.rb
|
178
|
+
- lib/bot_mob/networks/slack/inbound_message.rb
|
176
179
|
- lib/bot_mob/networks/slack/outbound_message.rb
|
177
180
|
- lib/bot_mob/outbound_message.rb
|
178
181
|
- lib/bot_mob/public/console.js
|