mos-eisley 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +37 -17
- data/lib/http-client/client.rb +12 -12
- data/lib/http-client/webapi.rb +12 -11
- data/lib/http-server/helper.rb +1 -1
- data/lib/http-server/server.rb +5 -6
- data/lib/mos-eisley/config.rb +2 -2
- data/lib/mos-eisley/handler.rb +51 -23
- data/lib/mos-eisley/version.rb +1 -1
- data/lib/s3po/message.rb +4 -0
- data/lib/s3po/s3po.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a35fd6879c702d39965d72c48add4ee90b47fcf
|
4
|
+
data.tar.gz: 4238234e33680a356e40d89f4fb6c2f53daa42d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce68accb9a686f22f76afd09dc9b5cad10b2336e685c0b4eae604497f6a97b021b2cb77db8a60e058659dc9c0bc2d12ebf2e2afb4083c5efb1d9366cb54db836
|
7
|
+
data.tar.gz: c4b6901abd0f0cd07961660ab76d5f52c29cf1691f24bc58d8d003cf9c8cde6612441ce1314caa6fe3908057758f252388a592477cf2ff1e930b3c09ce9ae673
|
data/README.md
CHANGED
@@ -1,35 +1,41 @@
|
|
1
1
|
# mos-eisley
|
2
2
|
|
3
|
-
```markdown
|
4
3
|
[![Gem Version](https://badge.fury.io/rb/mos-eisley.svg)](http://badge.fury.io/rb/mos-eisley) [![Code Climate](https://codeclimate.com/github/kenjij/mos-eisley/badges/gpa.svg)](https://codeclimate.com/github/kenjij/mos-eisley) [![security](https://hakiri.io/github/kenjij/mos-eisley/master.svg)](https://hakiri.io/github/kenjij/mos-eisley/master)
|
5
|
-
```
|
6
4
|
|
7
|
-
Ruby server
|
5
|
+
A Ruby based [Slack app](https://api.slack.com/slack-apps) server. It provides API endpoints to Slack as well as functions to access Slack API and manages events with handlers you create.
|
8
6
|
|
9
|
-
##
|
7
|
+
## Environment
|
10
8
|
|
9
|
+
- UNIX-like systems
|
11
10
|
- [Ruby](https://www.ruby-lang.org/) >= 2.1
|
12
|
-
|
13
|
-
|
11
|
+
- [Sinatra](http://www.sinatrarb.com/) ~> 2.0 – for inbound API server
|
12
|
+
- [em-http-request](https://github.com/igrigorik/em-http-request) ~> 1.1 – for outbound API access
|
14
13
|
|
15
14
|
## Getting Started
|
16
15
|
|
17
|
-
|
16
|
+
Install the gem.
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
gem install mos-eisley
|
19
|
+
|
20
|
+
Create a configuration file and register some handlers. Handlers are your code that gets executed when events are received from Slack. See below for [more details](#).
|
22
21
|
|
23
|
-
|
22
|
+
Run Mos Eisley.
|
24
23
|
|
25
|
-
|
24
|
+
mos-eisley -c config.rb start
|
25
|
+
|
26
|
+
## Setup
|
27
|
+
|
28
|
+
### Configuration File
|
29
|
+
|
30
|
+
This is a standard Ruby file and anything can go in it. It'll be executed at the very beginning of app launch, before the HTTP server is started. Here is an example.
|
26
31
|
|
27
32
|
```ruby
|
28
33
|
# Configure application logging
|
29
34
|
MosEisley.logger = Logger.new(STDOUT)
|
30
35
|
MosEisley.logger.level = Logger::DEBUG
|
31
36
|
|
32
|
-
MosEisley
|
37
|
+
# Main configuration block (MosEisley namespace can be abbrv. to ME)
|
38
|
+
ME::Config.setup do |c|
|
33
39
|
# User custom data
|
34
40
|
c.user = {my_data1: 'Something', my_data2: 'Somethingelse'}
|
35
41
|
|
@@ -43,14 +49,28 @@ MosEisley::Config.setup do |c|
|
|
43
49
|
]
|
44
50
|
|
45
51
|
# Slack info
|
46
|
-
c.
|
47
|
-
'vErIf1c4t0k3n5'
|
48
|
-
]
|
52
|
+
c.verification_token = 'vErIf1c4t0k3n5'
|
49
53
|
c.bot_access_token = 'xoxb-1234567890-b0t4cCe5sToK3N'
|
50
54
|
end
|
51
55
|
```
|
52
56
|
|
53
|
-
###
|
57
|
+
### Handlers
|
58
|
+
|
59
|
+
Define handlers, also a Ruby file, and they'll be executed as incoming Slack events are processed. You can define as many handlers as you want. You'll store the file(s) in the directory you've identified in the configuration file above.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
ME::Handler.add(:event, 'debug') do |e, h|
|
63
|
+
e.event.each { |k, v| puts "#{k}: #{v}" }
|
64
|
+
h.stop unless e.for_me?
|
65
|
+
end
|
66
|
+
|
67
|
+
```
|
68
|
+
|
69
|
+
### Slack
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
## Usage
|
54
74
|
|
55
75
|
To see help:
|
56
76
|
|
data/lib/http-client/client.rb
CHANGED
@@ -6,36 +6,36 @@ module MosEisley
|
|
6
6
|
|
7
7
|
class HTTPClient
|
8
8
|
|
9
|
-
def self.post_form(url:, params
|
9
|
+
def self.post_form(url:, params: nil, head: nil, &block)
|
10
10
|
if EM.reactor_running?
|
11
|
-
MosEisley.logger.debug(
|
12
|
-
MosEisley::HTTPClient.request(url: url, body: params, &block)
|
11
|
+
MosEisley.logger.debug("POSTing form to #{url}")
|
12
|
+
MosEisley::HTTPClient.request(url: url, head: head, body: params, &block)
|
13
13
|
else
|
14
14
|
MosEisley.logger.debug('Starting reactor...')
|
15
15
|
EM.run {
|
16
|
-
MosEisley.logger.debug(
|
17
|
-
MosEisley::HTTPClient.request(url: url, body: params, stop: true, &block)
|
16
|
+
MosEisley.logger.debug("POSTing form to #{url}")
|
17
|
+
MosEisley::HTTPClient.request(url: url, head: head, body: params, stop: true, &block)
|
18
18
|
}
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def self.post_json(url:, params: nil, body: nil, &block)
|
23
|
-
head
|
22
|
+
def self.post_json(url:, params: nil, body: nil, head: {}, &block)
|
23
|
+
head.merge!({'Content-Type' => 'application/json'})
|
24
24
|
body = S3PO.json_with_object(params) if params
|
25
25
|
if EM.reactor_running?
|
26
|
-
MosEisley.logger.debug(
|
27
|
-
MosEisley::HTTPClient.request(url: url,
|
26
|
+
MosEisley.logger.debug("POSTing JSON to: #{url}")
|
27
|
+
MosEisley::HTTPClient.request(url: url, head: head, body: body, &block)
|
28
28
|
else
|
29
29
|
MosEisley.logger.debug('Starting reactor...')
|
30
30
|
EM.run {
|
31
|
-
MosEisley.logger.debug(
|
32
|
-
MosEisley::HTTPClient.request(url: url,
|
31
|
+
MosEisley.logger.debug("POSTing JSON to #{url}")
|
32
|
+
MosEisley::HTTPClient.request(url: url, head: head, body: body, stop: true, &block)
|
33
33
|
}
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
def self.request(url:, head: nil, body:, stop: false, &block)
|
38
|
-
http = EM::HttpRequest.new(url).post(body: body)
|
38
|
+
http = EM::HttpRequest.new(url).post(body: body, head: head)
|
39
39
|
http.errback {
|
40
40
|
MosEisley.logger.error('HTTP error')
|
41
41
|
if stop
|
data/lib/http-client/webapi.rb
CHANGED
@@ -5,32 +5,33 @@ module MosEisley
|
|
5
5
|
BaseURL = 'https://slack.com/api/'
|
6
6
|
|
7
7
|
def self.auth_test
|
8
|
-
MosEisley.logger.debug('auth_test')
|
9
8
|
m = 'auth.test'
|
10
9
|
url = BaseURL + m
|
11
|
-
|
12
|
-
|
13
|
-
HTTPClient.post_form(url: url, params: params) do |h|
|
10
|
+
head = {authorization: "Bearer #{MosEisley.config.bot_access_token}"}
|
11
|
+
HTTPClient.post_form(url: url, head: head) do |h|
|
14
12
|
MosEisley.config.meta.merge!(S3PO.parse_json(h.response))
|
15
|
-
MosEisley.logger.
|
13
|
+
MosEisley.logger.info('Meta data updated by auth.test call.')
|
14
|
+
MosEisley.logger.debug("Meta data:\n#{MosEisley.config.meta}")
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
18
|
def self.post_message(msg)
|
20
19
|
m = 'chat.postMessage'
|
21
20
|
url = BaseURL + m
|
22
|
-
|
23
|
-
HTTPClient.
|
24
|
-
MosEisley.logger.
|
21
|
+
head = {authorization: "Bearer #{MosEisley.config.bot_access_token}"}
|
22
|
+
HTTPClient.post_json(url: url, params: msg, head: head) do |h|
|
23
|
+
MosEisley.logger.info('POSTed chat.postMessage')
|
24
|
+
MosEisley.logger.debug("chat.postMessage echo:\n#{h.response}")
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.post_ephemeral(msg)
|
29
29
|
m = 'chat.postEphemeral'
|
30
30
|
url = BaseURL + m
|
31
|
-
|
32
|
-
HTTPClient.
|
33
|
-
MosEisley.logger.
|
31
|
+
head = {authorization: "Bearer #{MosEisley.config.bot_access_token}"}
|
32
|
+
HTTPClient.post_json(url: url, params: msg, head: head) do |h|
|
33
|
+
MosEisley.logger.info('POSTed chat.postEphemeral')
|
34
|
+
MosEisley.logger.debug("chat.postEphemeral echo:\n#{h.response}")
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
data/lib/http-server/helper.rb
CHANGED
data/lib/http-server/server.rb
CHANGED
@@ -24,11 +24,11 @@ module MosEisley
|
|
24
24
|
# Interactive message buttons
|
25
25
|
# Receive POST form with payload containing JSON string; use "token" to verify
|
26
26
|
post '/action' do
|
27
|
-
logger.info('Incoming request received.')
|
27
|
+
logger.info('Incoming request received at /action.')
|
28
28
|
logger.debug("Body size: #{request.content_length} bytes")
|
29
29
|
event = parse_json(params[:payload])
|
30
30
|
halt 400 if event.nil?
|
31
|
-
logger.debug("#{event}")
|
31
|
+
logger.debug("Parsed JSON data:\n#{event}")
|
32
32
|
unless valid_token?(event[:token])
|
33
33
|
logger.debug("Invalid Slack Events token: #{event[:token]}")
|
34
34
|
halt 401
|
@@ -46,6 +46,7 @@ module MosEisley
|
|
46
46
|
# Respond within 3 sec directly; raw text or formatted
|
47
47
|
# OR, use response_url
|
48
48
|
post '/command' do
|
49
|
+
logger.info('Incoming request received at /command.')
|
49
50
|
cmd = parse_command(params)
|
50
51
|
unless valid_token?(cmd[:token])
|
51
52
|
logger.debug("Invalid Slack Events token: #{cmd[:token]}")
|
@@ -62,12 +63,12 @@ module MosEisley
|
|
62
63
|
# Event API
|
63
64
|
# Receive POST JSON; use "token" to verify
|
64
65
|
post '/event' do
|
65
|
-
logger.info('Incoming request received.')
|
66
|
+
logger.info('Incoming request received at /event.')
|
66
67
|
logger.debug("Body size: #{request.content_length} bytes")
|
67
68
|
request.body.rewind
|
68
69
|
event = parse_json(request.body.read)
|
69
70
|
halt 400 if event.nil?
|
70
|
-
logger.debug("#{event}")
|
71
|
+
logger.debug("Parsed JSON data:\n#{event}")
|
71
72
|
|
72
73
|
unless valid_token?(event[:token])
|
73
74
|
logger.debug("Invalid Slack Events token: #{event[:token]}")
|
@@ -83,8 +84,6 @@ module MosEisley
|
|
83
84
|
else
|
84
85
|
resp[:text] = "Unknown event type: #{event[:type]}"
|
85
86
|
end
|
86
|
-
logger.debug("#{resp}")
|
87
|
-
logger.debug("#{ME.config.meta}")
|
88
87
|
json_with_object(resp)
|
89
88
|
end
|
90
89
|
|
data/lib/mos-eisley/config.rb
CHANGED
@@ -34,7 +34,7 @@ module MosEisley
|
|
34
34
|
|
35
35
|
attr_reader :meta
|
36
36
|
|
37
|
-
attr_accessor :
|
37
|
+
attr_accessor :verification_token
|
38
38
|
attr_accessor :bot_access_token
|
39
39
|
|
40
40
|
def initialize
|
@@ -44,7 +44,7 @@ module MosEisley
|
|
44
44
|
|
45
45
|
@meta = {}
|
46
46
|
|
47
|
-
@
|
47
|
+
@verification_token = nil
|
48
48
|
@bot_access_token = ''
|
49
49
|
end
|
50
50
|
|
data/lib/mos-eisley/handler.rb
CHANGED
@@ -21,14 +21,16 @@ module MosEisley
|
|
21
21
|
}
|
22
22
|
end
|
23
23
|
|
24
|
-
# Call as often as necessary to add handlers; each call creates a MosEisley::Handler object
|
25
|
-
|
24
|
+
# Call as often as necessary to add handlers with blocks; each call creates a MosEisley::Handler object
|
25
|
+
# @param type [Symbol] :action | :command | :event
|
26
|
+
# @param name [String]
|
27
|
+
def self.add(type, name = nil, &block)
|
26
28
|
@handlers ||= {
|
27
29
|
action: [],
|
28
30
|
command: [],
|
29
31
|
event: []
|
30
32
|
}
|
31
|
-
@handlers[type] << Handler.new(type, &block)
|
33
|
+
@handlers[type] << Handler.new(type, name, &block)
|
32
34
|
MosEisley.logger.debug("Added #{type} handler: #{@handlers[type].last}")
|
33
35
|
end
|
34
36
|
|
@@ -41,47 +43,73 @@ module MosEisley
|
|
41
43
|
# @param event [Hash] from Slack Events API JSON data
|
42
44
|
def self.run(type, event)
|
43
45
|
logger = MosEisley.logger
|
44
|
-
logger.info("Running #{type} handlers...")
|
45
46
|
responses = []
|
46
|
-
@handlers[type].each
|
47
|
+
@handlers[type].each do |h|
|
48
|
+
responses << h.run(event)
|
49
|
+
if h.stopped?
|
50
|
+
logger.debug('Handler stop was requested.')
|
51
|
+
break
|
52
|
+
end
|
53
|
+
end
|
47
54
|
logger.info("Done running #{type} handlers.")
|
48
55
|
responses = [] if type == :event
|
49
56
|
merged_res = {}
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
57
|
+
# Only take the last response
|
58
|
+
r = responses.last
|
59
|
+
merged_res = r if r.class == Hash
|
60
|
+
# ## Accumulative Response routine ##
|
61
|
+
# responses.each do |r|
|
62
|
+
# next unless r.class == Hash
|
63
|
+
# [:response_type, :replace_original].each { |k| merged_res[k] = r[k] if r.has_key?(k) }
|
64
|
+
# if r[:text]
|
65
|
+
# if merged_res[:text]
|
66
|
+
# merged_res[:text] += "\n#{r[:text]}"
|
67
|
+
# else
|
68
|
+
# merged_res[:text] = r[:text]
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
# if r[:attachments]
|
72
|
+
# merged_res[:attachments] ||= []
|
73
|
+
# merged_res[:attachments] += r[:attachments]
|
74
|
+
# end
|
75
|
+
# end
|
65
76
|
return nil if merged_res.empty?
|
66
77
|
return merged_res
|
67
78
|
end
|
68
79
|
|
69
|
-
|
70
|
-
|
80
|
+
attr_reader :type, :name
|
81
|
+
|
82
|
+
def initialize(t, n = nil, &block)
|
83
|
+
@type = t
|
84
|
+
@name = n
|
71
85
|
@block = block
|
86
|
+
@stopped = false
|
72
87
|
end
|
73
88
|
|
74
89
|
def run(event)
|
75
90
|
logger = MosEisley.logger
|
76
91
|
logger.warn("No block to execute for #{@type} handler: #{self}") unless @block
|
77
92
|
logger.debug("Running #{@type} handler: #{self}")
|
78
|
-
@
|
93
|
+
@stopped = false
|
94
|
+
@block.call(event, self)
|
79
95
|
rescue => e
|
80
96
|
logger.error(e.message)
|
81
97
|
logger.error(e.backtrace.join("\n"))
|
82
98
|
{text: "Woops, encountered an error."}
|
83
99
|
end
|
84
100
|
|
101
|
+
def stop
|
102
|
+
@stopped = true
|
103
|
+
end
|
104
|
+
|
105
|
+
def stopped?
|
106
|
+
@stopped
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_s
|
110
|
+
"#<#{self.class}:#{self.object_id.to_s(16)}(#{name})>"
|
111
|
+
end
|
112
|
+
|
85
113
|
end
|
86
114
|
|
87
115
|
end
|
data/lib/mos-eisley/version.rb
CHANGED
data/lib/s3po/message.rb
CHANGED
data/lib/s3po/s3po.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mos-eisley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken J.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kajiki
|