bot_mob 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env +1 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +16 -0
- data/.travis.yml +1 -1
- data/Gemfile +0 -2
- data/LICENSE.txt +21 -0
- data/README.md +5 -4
- data/bin/console +8 -4
- data/bin/mob +4 -0
- data/bot_mob.gemspec +8 -14
- data/examples/fizz_buzz_bot.rb +30 -0
- data/examples/hello_bot.rb +14 -0
- data/examples/server.rb +7 -0
- data/lib/bot_mob.rb +46 -32
- data/lib/bot_mob/bot.rb +146 -29
- data/lib/bot_mob/command.rb +38 -0
- data/lib/bot_mob/connection.rb +18 -50
- data/lib/bot_mob/core_ext/hash.rb +148 -0
- data/lib/bot_mob/core_ext/string.rb +8 -0
- data/lib/bot_mob/environment.rb +25 -0
- data/lib/bot_mob/inbound_message.rb +13 -32
- data/lib/bot_mob/networks/roaming.rb +12 -0
- data/lib/bot_mob/networks/roaming/connection.rb +34 -0
- data/lib/bot_mob/networks/roaming/outbound_message.rb +15 -0
- data/lib/bot_mob/networks/slack.rb +11 -0
- data/lib/bot_mob/networks/slack/connection.rb +37 -0
- data/lib/bot_mob/networks/slack/outbound_message.rb +18 -0
- data/lib/bot_mob/outbound_message.rb +23 -10
- data/lib/bot_mob/public/console.js +10 -0
- data/lib/bot_mob/roster.rb +8 -80
- data/lib/bot_mob/server.rb +47 -0
- data/lib/bot_mob/version.rb +1 -1
- data/lib/bot_mob/views/authorize.erb +1 -0
- data/lib/bot_mob/views/console.erb +6 -0
- data/lib/bot_mob/views/index.erb +1 -0
- data/lib/bot_mob/views/layout.erb +11 -0
- metadata +50 -110
- data/lib/bot_mob/ambassador.rb +0 -34
- data/lib/bot_mob/application.rb +0 -43
- data/lib/bot_mob/authority.rb +0 -41
- data/lib/bot_mob/development/ambassador.rb +0 -21
- data/lib/bot_mob/development/connection.rb +0 -34
- data/lib/bot_mob/development/inbound_message.rb +0 -17
- data/lib/bot_mob/errors.rb +0 -12
- data/lib/bot_mob/install.rb +0 -16
- data/lib/bot_mob/nil_connection.rb +0 -29
- data/lib/bot_mob/slack.rb +0 -10
- data/lib/bot_mob/slack/ambassador.rb +0 -58
- data/lib/bot_mob/slack/connection.rb +0 -87
- data/lib/bot_mob/slack/inbound_message.rb +0 -52
- data/lib/bot_mob/wire.rb +0 -69
data/lib/bot_mob/ambassador.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
class Ambassador
|
3
|
-
# ## BotMob::Ambassador.setup
|
4
|
-
#
|
5
|
-
# Ambassador setup delegates the ambassadorship
|
6
|
-
# to the correct network.
|
7
|
-
def self.setup(network, args = {})
|
8
|
-
invalid_network_error(network) unless BotMob.valid_network?(network)
|
9
|
-
|
10
|
-
ambassador = network_delegate(network)
|
11
|
-
invalid_delegate_error(network) unless ambassador.respond_to?(:setup)
|
12
|
-
|
13
|
-
ambassador.setup(args)
|
14
|
-
end
|
15
|
-
|
16
|
-
def data
|
17
|
-
{}
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def self.network_delegate(network)
|
23
|
-
BotMob.networks[network].const_get('Ambassador')
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.invalid_network_error(network)
|
27
|
-
raise BotMob::InvalidNetworkError, "The #{network.inspect} network has not been mounted"
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.invalid_delegate_error(network)
|
31
|
-
raise BotMob::InvalidAmbassadorError, "The #{network.inspect} ambassador must implement the `setup` method"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
data/lib/bot_mob/application.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
|
-
module BotMob
|
4
|
-
# ## BotMob::Application
|
5
|
-
#
|
6
|
-
# This is the base application class for BotMob.
|
7
|
-
class Application
|
8
|
-
extend Forwardable
|
9
|
-
|
10
|
-
def_delegators :roster, :register
|
11
|
-
|
12
|
-
def start!
|
13
|
-
BotMob.logger.info("=> BotMob #{BotMob::VERSION} application starting")
|
14
|
-
|
15
|
-
roster.load
|
16
|
-
wire.listen { |auth| roster.connect(auth) }
|
17
|
-
|
18
|
-
loop do
|
19
|
-
sleep(10)
|
20
|
-
# Avoid polling at all for the time being
|
21
|
-
# roster.load if roster.available? && !wire.available?
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
# ## Roster
|
28
|
-
#
|
29
|
-
# The `roster` is the object that keeps track of the registration
|
30
|
-
# and participation of any various bots active on your mob
|
31
|
-
def roster
|
32
|
-
@roster ||= BotMob::Roster.new
|
33
|
-
end
|
34
|
-
|
35
|
-
# ## Wire
|
36
|
-
#
|
37
|
-
# The `wire` is the object that allows for other processes to
|
38
|
-
# tell your bot mob application to take some action.
|
39
|
-
def wire
|
40
|
-
@wire ||= BotMob::Wire.new
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/bot_mob/authority.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
# ## BotMob::Authority
|
3
|
-
#
|
4
|
-
# The Authority class will process an access args
|
5
|
-
# and retrieve an access token from the specified
|
6
|
-
# network
|
7
|
-
#
|
8
|
-
# Example Invocation:
|
9
|
-
#
|
10
|
-
# BotMob::Authority.new(:slack, code: params[:code])
|
11
|
-
class Authority
|
12
|
-
attr_reader :network
|
13
|
-
|
14
|
-
def initialize(network, args = {})
|
15
|
-
@network = network
|
16
|
-
@args = args
|
17
|
-
end
|
18
|
-
|
19
|
-
def process(bot_class)
|
20
|
-
return unless ambassador.success?
|
21
|
-
|
22
|
-
# wire.publish(network: :slack, external_id: 'foo', bot_class: 'MockBot', data: { token: ENV['IOBOT_TOKEN'] } )
|
23
|
-
wire.publish({
|
24
|
-
network: network,
|
25
|
-
external_id: ambassador.external_id,
|
26
|
-
bot_class: bot_class.to_s,
|
27
|
-
data: ambassador.data || {}
|
28
|
-
})
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def ambassador
|
34
|
-
@ambassador ||= BotMob::Ambassador.setup(network, @args)
|
35
|
-
end
|
36
|
-
|
37
|
-
def wire
|
38
|
-
@wire ||= BotMob::Wire.new
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
module Development
|
3
|
-
class Connection < BotMob::Connection
|
4
|
-
|
5
|
-
def initialize(bot, options = {})
|
6
|
-
@bot = bot
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.setup(bot, options = {})
|
10
|
-
new(bot, options)
|
11
|
-
end
|
12
|
-
|
13
|
-
def deliver(outbound_message, options = {})
|
14
|
-
BotMob.logger.info " Dev Connection Sent: #{outbound_message.text.inspect}"
|
15
|
-
end
|
16
|
-
|
17
|
-
def connect
|
18
|
-
BotMob.logger.info 'Connecting... '
|
19
|
-
end
|
20
|
-
|
21
|
-
def reconnect
|
22
|
-
BotMob.logger.info 'Reconnecting... '
|
23
|
-
end
|
24
|
-
|
25
|
-
def refresh
|
26
|
-
BotMob.logger.info 'Refreshing... '
|
27
|
-
end
|
28
|
-
|
29
|
-
def client
|
30
|
-
self
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
module Development
|
3
|
-
class InboundMessage < BotMob::InboundMessage
|
4
|
-
def initialize(params)
|
5
|
-
@text = params[:text]
|
6
|
-
@network = params[:network]
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.parse(**params)
|
10
|
-
new({
|
11
|
-
network: params[:network],
|
12
|
-
text: params[:text]
|
13
|
-
})
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/bot_mob/errors.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
class InvalidAmbassadorError < StandardError; end
|
3
|
-
class InvalidConnectionError < StandardError; end
|
4
|
-
class InvalidInboundMessageError < StandardError; end
|
5
|
-
|
6
|
-
class InvalidNetworkError < StandardError; end
|
7
|
-
class InvalidClientIdError < StandardError; end
|
8
|
-
class InvalidClientSecretError < StandardError; end
|
9
|
-
class InvalidCodeError < StandardError; end
|
10
|
-
class ConnectionNotEstablished < StandardError; end
|
11
|
-
class UnregisteredBotError < StandardError; end
|
12
|
-
end
|
data/lib/bot_mob/install.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
class Install < ActiveRecord::Base
|
3
|
-
self.table_name = "bot_mob_installs"
|
4
|
-
|
5
|
-
def self.registered_bot(auth)
|
6
|
-
where(bot_class: auth['bot_class'], external_id: auth['external_id'])
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.create_with_auth(auth)
|
10
|
-
registered_bot(auth).first_or_initialize.tap do |i|
|
11
|
-
i.data = auth['data']
|
12
|
-
i.save!
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
class NilConnection
|
3
|
-
|
4
|
-
def initialize(bot)
|
5
|
-
@bot = bot
|
6
|
-
end
|
7
|
-
|
8
|
-
def deliver(outbound_message, options = {})
|
9
|
-
BotMob.logger.info '! Missing connection attempting to deliver... '
|
10
|
-
BotMob.logger.info " Message sent: #{outbound_message.text.inspect}"
|
11
|
-
end
|
12
|
-
|
13
|
-
def connect
|
14
|
-
BotMob.logger.info '! Missing connection attempting to connect... '
|
15
|
-
end
|
16
|
-
|
17
|
-
def reconnect
|
18
|
-
BotMob.logger.info '! Missing connection attempting to reconnect... '
|
19
|
-
end
|
20
|
-
|
21
|
-
def refresh
|
22
|
-
BotMob.logger.info '! Missing connection attempting to refresh... '
|
23
|
-
end
|
24
|
-
|
25
|
-
def client
|
26
|
-
self
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/lib/bot_mob/slack.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
module Slack
|
3
|
-
class Ambassador < BotMob::Ambassador
|
4
|
-
def initialize(code)
|
5
|
-
@code = code
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.setup(args)
|
9
|
-
new(args[:code])
|
10
|
-
end
|
11
|
-
|
12
|
-
def token
|
13
|
-
oauth_response.bot_access_token
|
14
|
-
end
|
15
|
-
|
16
|
-
def external_id
|
17
|
-
oauth_response.bot_user_id
|
18
|
-
end
|
19
|
-
|
20
|
-
def data
|
21
|
-
{ token: token }
|
22
|
-
end
|
23
|
-
|
24
|
-
def success?
|
25
|
-
!!(external_id && token)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def oauth_response
|
31
|
-
return @oauth_response if defined?(@oauth_response)
|
32
|
-
|
33
|
-
response = client.oauth_access({
|
34
|
-
code: @code,
|
35
|
-
client_id: ENV['SLACK_CLIENT_ID'],
|
36
|
-
client_secret: ENV['SLACK_CLIENT_SECRET']
|
37
|
-
})
|
38
|
-
|
39
|
-
@oauth_response = response.bot
|
40
|
-
rescue ::Slack::Web::Api::Error => e
|
41
|
-
case e.message
|
42
|
-
when 'invalid_client_id'
|
43
|
-
raise BotMob::InvalidClientIdError, 'Invalid SLACK_CLIENT_ID environment variable'
|
44
|
-
when 'bad_client_secret'
|
45
|
-
raise BotMob::InvalidClientSecretError, 'Invalid SLACK_CLIENT_SECRET environment variable'
|
46
|
-
when 'invalid_code'
|
47
|
-
raise BotMob::InvalidCodeError, 'Invalid access code'
|
48
|
-
else
|
49
|
-
raise e
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def client
|
54
|
-
@client ||= ::Slack::Web::Client.new
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
module Slack
|
3
|
-
class Connection < BotMob::Connection
|
4
|
-
attr_reader :bot, :token
|
5
|
-
|
6
|
-
def initialize(bot, options = {})
|
7
|
-
@bot = bot
|
8
|
-
@token = options['token']
|
9
|
-
token.nil? ? set_state(:inactive) : setup
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.setup(bot, options = {})
|
13
|
-
new(bot, options)
|
14
|
-
end
|
15
|
-
|
16
|
-
def deliver(outbound_message, options = {})
|
17
|
-
BotMob.logger.info(" Sending to Slack: \"#{options.inspect}\"\n")
|
18
|
-
BotMob.logger.info(" Text: \"#{outbound_message.text.inspect}\"\n")
|
19
|
-
client.web_client.chat_postMessage(outbound_message.to_h)
|
20
|
-
end
|
21
|
-
|
22
|
-
def connect
|
23
|
-
return unless active?
|
24
|
-
set_state(:connecting)
|
25
|
-
establish
|
26
|
-
end
|
27
|
-
|
28
|
-
def reconnect
|
29
|
-
return unless active?
|
30
|
-
set_state(:reconnecting)
|
31
|
-
renew_client
|
32
|
-
setup
|
33
|
-
establish
|
34
|
-
end
|
35
|
-
|
36
|
-
def refresh
|
37
|
-
return unless active?
|
38
|
-
|
39
|
-
case true
|
40
|
-
when waiting?
|
41
|
-
connect
|
42
|
-
when disconnected?
|
43
|
-
reconnect
|
44
|
-
else
|
45
|
-
BotMob.logger.info "State[#{bot.class.to_s}##{bot.key}] - No Change"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def welcome_message
|
50
|
-
"Successfully connected, '#{client.team.name}' team at https://#{client.team.domain}.slack.com."
|
51
|
-
end
|
52
|
-
|
53
|
-
def client
|
54
|
-
@client ||= renew_client
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def establish
|
60
|
-
client.start_async
|
61
|
-
rescue ::Slack::Web::Api::Error => e
|
62
|
-
BotMob.logger.info e.message
|
63
|
-
set_state(:waiting)
|
64
|
-
end
|
65
|
-
|
66
|
-
def setup
|
67
|
-
set_state(:waiting)
|
68
|
-
client.on(:hello) { set_state(:connected) }
|
69
|
-
client.on(:close) { set_state(:disconnecting) }
|
70
|
-
client.on(:closed) { set_state(:closed) }
|
71
|
-
|
72
|
-
client.on :message do |data|
|
73
|
-
message = BotMob::InboundMessage.parse({
|
74
|
-
network: :slack,
|
75
|
-
format: :websocket
|
76
|
-
}.merge(data))
|
77
|
-
|
78
|
-
bot.receive message
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def renew_client
|
83
|
-
@client = ::Slack::RealTime::Client.new(token: @token)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module BotMob
|
2
|
-
module Slack
|
3
|
-
class InboundMessage < BotMob::InboundMessage
|
4
|
-
attr_reader :token, :team_id, :team_domain, :params, :format,
|
5
|
-
:channel_id, :channel_name, :external_id, :user_name,
|
6
|
-
:command, :bot_id, :response_url, :ts
|
7
|
-
|
8
|
-
def initialize(params)
|
9
|
-
@format = params[:format] || :websocket
|
10
|
-
@network = params[:network]
|
11
|
-
@params = params
|
12
|
-
send("parse_#{format}".to_sym, @params)
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.parse(params)
|
16
|
-
new(params)
|
17
|
-
end
|
18
|
-
|
19
|
-
def human?
|
20
|
-
bot_id.nil?
|
21
|
-
end
|
22
|
-
|
23
|
-
def command?
|
24
|
-
!command.nil?
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def parse_websocket(data)
|
30
|
-
@text = data['text']
|
31
|
-
@channel_id = data['channel_id'] || data['channel']
|
32
|
-
@bot_id = data['bot_id']
|
33
|
-
@team = data['team']
|
34
|
-
@ts = data['ts']
|
35
|
-
@external_id = data['user_id']
|
36
|
-
end
|
37
|
-
|
38
|
-
def parse_webhook(data)
|
39
|
-
@token = data['token']
|
40
|
-
@team_id = data['team_id']
|
41
|
-
@team_domain = data['team_domain']
|
42
|
-
@channel_id = data['channel_id']
|
43
|
-
@channel_name = data['channel_name']
|
44
|
-
@external_id = data['user_id']
|
45
|
-
@user_name = data['user_name']
|
46
|
-
@command = data['command']
|
47
|
-
@text = data['text']
|
48
|
-
@response_url = data['response_url']
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|