bot_mob 0.3.0 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|