mos-eisley 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 04aa61103f6ecc6125a9c6ee418ba29f83e21c60
4
+ data.tar.gz: 0afb292fddbfa032b38f59a4c3395bd3d19e26b3
5
+ SHA512:
6
+ metadata.gz: 02396f7926f9c24e5c4985a75f377dc474cb496bc30dcb527cf84e3701f26f810e6a5a2d2fcec8b0bde4089f65404c0c0fea4cfd8a655154095aa5c70c0b2162
7
+ data.tar.gz: 99601b8d3ac02b31ec45d9673c3c85fdfe7733aaf579af4d9f696be0b913da1c526224610359ee86c57e097497c9cc4f41647db0b9176946f5f0f1b2e5e71877
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # mos-eisley
2
+
3
+ ```markdown
4
+ [![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
+
7
+ Ruby server for running a Slackbot.
8
+
9
+ ## Requirements
10
+
11
+ - [Ruby](https://www.ruby-lang.org/) >= 2.1
12
+
13
+ Powered by [Sinatra](http://www.sinatrarb.com/).
14
+
15
+ ## Getting Started
16
+
17
+ ### Install
18
+
19
+ ```
20
+ $ gem install mos-eisley
21
+ ```
22
+
23
+ ### Configure
24
+
25
+ Create a configuration file following the example below.
26
+
27
+ ```ruby
28
+ # Configure application logging
29
+ MosEisley.logger = Logger.new(STDOUT)
30
+ MosEisley.logger.level = Logger::DEBUG
31
+
32
+ MosEisley::Config.setup do |c|
33
+ # User custom data
34
+ c.user = {my_data1: 'Something', my_data2: 'Somethingelse'}
35
+
36
+ # HTTP server (Sinatra) settings
37
+ c.dump_errors = true
38
+ c.logging = true
39
+
40
+ # Your handlers
41
+ c.handler_paths = [
42
+ 'handlers'
43
+ ]
44
+
45
+ # Slack info
46
+ c.verification_tokens = [
47
+ 'vErIf1c4t0k3n5'
48
+ ]
49
+ c.bot_access_token = 'xoxb-1234567890-b0t4cCe5sToK3N'
50
+ end
51
+ ```
52
+
53
+ ### Use
54
+
55
+ To see help:
56
+
57
+ ```
58
+ $ mos-eisley -h
59
+ Usage: mos-eisley [options] {start|stop}
60
+ -c, --config=<s> Load config from file
61
+ -d, --daemonize Run in the background
62
+ -l, --log=<s> Log output to file
63
+ -P, --pid=<s> Store PID to file
64
+ -p, --port=<i> Use port (default: 4567)
65
+ ```
66
+
67
+ The minimum to start a server:
68
+
69
+ ```
70
+ $ mos-eisley -c config.rb start
71
+ ```
data/bin/mos-eisley ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ require 'kajiki'
3
+ require 'mos-eisley'
4
+
5
+
6
+ opts = Kajiki.preset_options(:server, {config: true})
7
+
8
+ Kajiki.run(opts) do |cmd|
9
+ case cmd
10
+ when 'start'
11
+ MosEisley::Config.load_config(opts[:config]) if opts[:config]
12
+ MosEisley::Handler.autoload
13
+ require 'http-server/server'
14
+ MosEisley.logger.warn('Mos Eisley server starting...')
15
+ MosEisley::Server.run!({Host: opts[:address], Port: opts[:port]})
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ require 'eventmachine'
2
+ require 'em-http'
3
+
4
+
5
+ module MosEisley
6
+
7
+ class HTTPClient
8
+
9
+ def self.post_form(url:, params:, &block)
10
+ if EM.reactor_running?
11
+ MosEisley.logger.debug('POSTing form')
12
+ MosEisley::HTTPClient.request(url: url, body: params, &block)
13
+ else
14
+ MosEisley.logger.debug('Starting reactor...')
15
+ EM.run {
16
+ MosEisley.logger.debug('POSTing form')
17
+ MosEisley::HTTPClient.request(url: url, body: params, stop: true, &block)
18
+ }
19
+ end
20
+ end
21
+
22
+ def self.post_json(url:, params: nil, body: nil, &block)
23
+ head = {'Content-Type' => 'application/json'}
24
+ body = S3PO.json_with_object(params) if params
25
+ if EM.reactor_running?
26
+ MosEisley.logger.debug('POSTing JSON')
27
+ MosEisley::HTTPClient.request(url: url, body: body, head: head, &block)
28
+ else
29
+ MosEisley.logger.debug('Starting reactor...')
30
+ EM.run {
31
+ MosEisley.logger.debug('POSTing JSON')
32
+ MosEisley::HTTPClient.request(url: url, body: body, head: head, stop: true, &block)
33
+ }
34
+ end
35
+ end
36
+
37
+ def self.request(url:, head: nil, body:, stop: false, &block)
38
+ http = EM::HttpRequest.new(url).post(body: body)
39
+ http.errback {
40
+ MosEisley.logger.error('HTTP error')
41
+ if stop
42
+ EM.stop
43
+ MosEisley.logger.debug('Stopped reactor.')
44
+ end
45
+ }
46
+ http.callback {
47
+ block.call(http) if block_given?
48
+ if stop
49
+ EM.stop
50
+ MosEisley.logger.debug('Stopped reactor.')
51
+ end
52
+ }
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,44 @@
1
+ module MosEisley
2
+
3
+ class WebAPI
4
+
5
+ BaseURL = 'https://slack.com/api/'
6
+
7
+ def self.auth_test
8
+ MosEisley.logger.debug('auth_test')
9
+ m = 'auth.test'
10
+ url = BaseURL + m
11
+ params = {token: MosEisley.config.bot_access_token}
12
+ MosEisley.logger.debug("#{url}\n#{params}")
13
+ HTTPClient.post_form(url: url, params: params) do |h|
14
+ MosEisley.config.meta.merge!(S3PO.parse_json(h.response))
15
+ MosEisley.logger.debug("meta data updated:\n#{MosEisley.config.meta}")
16
+ end
17
+ end
18
+
19
+ def self.post_message(msg)
20
+ m = 'chat.postMessage'
21
+ url = BaseURL + m
22
+ msg[:token] = MosEisley.config.bot_access_token
23
+ HTTPClient.post_form(url: url, params: msg) do |h|
24
+ MosEisley.logger.debug("chat.postMessage POSTed: #{h.response}")
25
+ end
26
+ end
27
+
28
+ def self.post_ephemeral(msg)
29
+ m = 'chat.postEphemeral'
30
+ url = BaseURL + m
31
+ msg[:token] = MosEisley.config.bot_access_token
32
+ HTTPClient.post_form(url: url, params: msg) do |h|
33
+ MosEisley.logger.debug("chat.postEphemeral POSTed: #{h.response}")
34
+ end
35
+ end
36
+
37
+ # def self.me_message()
38
+ # m = 'chat.meMessage'
39
+ # url = BaseURL + m
40
+ # end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,36 @@
1
+ require 's3po/s3po'
2
+
3
+ module MosEisley
4
+
5
+ module Helper
6
+
7
+ def logger
8
+ MosEisley.logger
9
+ end
10
+
11
+ def parse_command(params)
12
+ cmd = {}
13
+ params.each { |k, v| cmd[k.to_sym] = v }
14
+ return cmd
15
+ end
16
+
17
+ # Parse JSON to Hash with key symbolization by default
18
+ def parse_json(json)
19
+ MosEisley::S3PO.parse_json(json)
20
+ end
21
+
22
+ def valid_token?(token)
23
+ Config.shared.verification_tokens.include?(token)
24
+ end
25
+
26
+ # Convert object into JSON, optionally pretty-format
27
+ # @param obj [Object] any Ruby object
28
+ # @param opts [Hash] any JSON options
29
+ # @return [String] JSON string
30
+ def json_with_object(obj, pretty: true, opts: nil)
31
+ MosEisley::S3PO.json_with_object(obj, pretty: pretty, opts: opts)
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,118 @@
1
+ require 'thin'
2
+ require 'sinatra/base'
3
+ require 'http-server/helper'
4
+
5
+ module MosEisley
6
+
7
+ # The Sinatra server
8
+ class Server < Sinatra::Base
9
+
10
+ helpers Helper
11
+
12
+ configure do
13
+ set :environment, :production
14
+ c = Config.shared
15
+ # set :public_folder, c.public_folder if c.public_folder
16
+ # set :dump_errors, c.dump_errors
17
+ # set :logging, c.logging
18
+ enable :logging
19
+ MosEisley::WebAPI.auth_test
20
+ end
21
+
22
+ before do
23
+ end
24
+
25
+ # Interactive message buttons
26
+ # Receive POST form with payload containing JSON string; use "token" to verify
27
+ post '/action' do
28
+ logger.info('Incoming request received.')
29
+ logger.debug("Body size: #{request.content_length} bytes")
30
+ event = parse_json(params[:payload])
31
+ halt 400 if event.nil?
32
+ logger.debug("#{event}")
33
+ unless valid_token?(event[:token])
34
+ logger.debug("Invalid Slack Events token: #{event[:token]}")
35
+ halt 401
36
+ end
37
+ res = Handler.run(:action, S3PO.create_event(event, :action))
38
+ if res
39
+ json_with_object(res)
40
+ else
41
+ 200
42
+ end
43
+ end
44
+
45
+ # Slash commands
46
+ # Receive POST form; use "token" to verify
47
+ # Respond within 3 sec directly; raw text or formatted
48
+ # OR, use response_url
49
+ post '/command' do
50
+ cmd = parse_command(params)
51
+ unless valid_token?(cmd[:token])
52
+ logger.debug("Invalid Slack Events token: #{cmd[:token]}")
53
+ halt 401
54
+ end
55
+ res = Handler.run(:command, cmd)
56
+ if res
57
+ json_with_object(res)
58
+ else
59
+ 200
60
+ end
61
+ end
62
+
63
+ # Event API
64
+ # Receive POST JSON; use "token" to verify
65
+ post '/event' do
66
+ logger.info('Incoming request received.')
67
+ logger.debug("Body size: #{request.content_length} bytes")
68
+ request.body.rewind
69
+ event = parse_json(request.body.read)
70
+ halt 400 if event.nil?
71
+ logger.debug("#{event}")
72
+
73
+ unless valid_token?(event[:token])
74
+ logger.debug("Invalid Slack Events token: #{event[:token]}")
75
+ halt 401
76
+ end
77
+ resp = {}
78
+ case event[:type]
79
+ when 'url_verification'
80
+ resp[:challenge] = event[:challenge]
81
+ when 'event_callback'
82
+ Handler.run(:event, S3PO.create_event(event[:event]))
83
+ resp[:text] = 'OK'
84
+ else
85
+ resp[:text] = "Unknown event type: #{event[:type]}"
86
+ end
87
+ logger.debug("#{resp}")
88
+ logger.debug("#{ME.config.meta}")
89
+ json_with_object(resp)
90
+ end
91
+
92
+ not_found do
93
+ logger.info('Invalid request.')
94
+ logger.debug("Request method and path: #{request.request_method} #{request.path}")
95
+ json_with_object({message: 'Huh, nothing here.'})
96
+ end
97
+
98
+ error 400 do
99
+ json_with_object({message: 'Um, I did not get that.'})
100
+ end
101
+
102
+ error 401 do
103
+ json_with_object({message: 'Oops, need a valid token.'})
104
+ end
105
+
106
+ error do
107
+ status 500
108
+ err = env['sinatra.error']
109
+ logger.error "#{err.class.name} - #{err}"
110
+ json_with_object({message: 'Yikes, internal error.'})
111
+ end
112
+
113
+ after do
114
+ content_type 'application/json'
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,53 @@
1
+ module MosEisley
2
+
3
+ def self.config
4
+ Config.shared
5
+ end
6
+
7
+ class Config
8
+
9
+ # Load Ruby config file
10
+ # @param path [String] config file
11
+ def self.load_config(path)
12
+ MosEisley.logger.debug("Loading config file: #{path}")
13
+ require File.expand_path(path)
14
+ MosEisley.logger.info('Config.load_config done.')
15
+ end
16
+
17
+ # Returns the shared instance
18
+ # @return [MosEisley::Config]
19
+ def self.shared
20
+ @shared_config ||= Config.new
21
+ end
22
+
23
+ # Call this from your config file
24
+ def self.setup
25
+ yield Config.shared
26
+ MosEisley.logger.debug('Config.setup block executed.')
27
+ end
28
+
29
+ attr_accessor :user
30
+ attr_accessor :handler_paths
31
+ attr_accessor :public_folder
32
+ attr_accessor :dump_errors
33
+ attr_accessor :logging
34
+
35
+ attr_reader :meta
36
+
37
+ attr_accessor :verification_tokens
38
+ attr_accessor :bot_access_token
39
+
40
+ def initialize
41
+ @handler_paths = []
42
+ @dump_errors = false
43
+ @logging = false
44
+
45
+ @meta = {}
46
+
47
+ @verification_tokens = []
48
+ @bot_access_token = ''
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,87 @@
1
+ module MosEisley
2
+
3
+ def self.handlers
4
+ Handler.handlers
5
+ end
6
+
7
+ class Handler
8
+
9
+ # Load handlers from directories designated in config
10
+ def self.autoload
11
+ MosEisley.config.handler_paths.each { |path|
12
+ load_from_path(path)
13
+ }
14
+ end
15
+
16
+ # Load handlers from a directory
17
+ # @param path [String] directory name
18
+ def self.load_from_path(path)
19
+ Dir.chdir(path) {
20
+ Dir.foreach('.') { |f| load f unless File.directory?(f) }
21
+ }
22
+ end
23
+
24
+ # Call as often as necessary to add handlers; each call creates a MosEisley::Handler object
25
+ def self.add(type, &block)
26
+ @handlers ||= {
27
+ action: [],
28
+ command: [],
29
+ event: []
30
+ }
31
+ @handlers[type] << Handler.new(type, &block)
32
+ MosEisley.logger.debug("Added #{type} handler: #{@handlers[type].last}")
33
+ end
34
+
35
+ # @return [Hash<Symbol, Array>] containing all the handlers
36
+ def self.handlers
37
+ @handlers
38
+ end
39
+
40
+ # Run the handlers, typically called by the server
41
+ # @param event [Hash] from Slack Events API JSON data
42
+ def self.run(type, event)
43
+ logger = MosEisley.logger
44
+ logger.info("Running #{type} handlers...")
45
+ responses = []
46
+ @handlers[type].each { |h| responses << h.run(event) }
47
+ logger.info("Done running #{type} handlers.")
48
+ responses = [] if type == :event
49
+ merged_res = {}
50
+ responses.each do |r|
51
+ next unless r.class == Hash
52
+ [:response_type, :replace_original].each { |k| merged_res[k] = r[k] if r.has_key?(k) }
53
+ if r[:text]
54
+ if merged_res[:text]
55
+ merged_res[:text] += "\n#{r[:text]}"
56
+ else
57
+ merged_res[:text] = r[:text]
58
+ end
59
+ end
60
+ if r[:attachments]
61
+ merged_res[:attachments] ||= []
62
+ merged_res[:attachments] += r[:attachments]
63
+ end
64
+ end
65
+ return nil if merged_res.empty?
66
+ return merged_res
67
+ end
68
+
69
+ def initialize(type, &block)
70
+ @type = type
71
+ @block = block
72
+ end
73
+
74
+ def run(event)
75
+ logger = MosEisley.logger
76
+ logger.warn("No block to execute for #{@type} handler: #{self}") unless @block
77
+ logger.debug("Running #{@type} handler: #{self}")
78
+ @block.call(event)
79
+ rescue => e
80
+ logger.error(e.message)
81
+ logger.error(e.backtrace.join("\n"))
82
+ {text: "Woops, encountered an error."}
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,24 @@
1
+ require 'logger'
2
+
3
+
4
+ module MosEisley
5
+
6
+ def self.logger=(logger)
7
+ @logger = logger
8
+ end
9
+
10
+ def self.logger
11
+ @logger ||= NullLogger.new()
12
+ end
13
+
14
+ class NullLogger < Logger
15
+
16
+ def initialize(*args)
17
+ end
18
+
19
+ def add(*args, &block)
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,5 @@
1
+ module MosEisley
2
+
3
+ Version = '0.0.1'
4
+
5
+ end
data/lib/mos-eisley.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'mos-eisley/logger'
2
+ require 'mos-eisley/config'
3
+ require 'mos-eisley/handler'
4
+ require 'http-client/client'
5
+ require 'http-client/webapi'
6
+
7
+ ME = MosEisley
@@ -0,0 +1,53 @@
1
+ module MosEisley
2
+
3
+ module S3PO
4
+
5
+ class Action
6
+
7
+ attr_reader :event
8
+ attr_reader :original_message
9
+
10
+ def initialize(e)
11
+ @event = e
12
+ if e[:original_message]
13
+ @original_message = Message.new(e[:original_message])
14
+ end
15
+ end
16
+
17
+ def action
18
+ event[:actions][0]
19
+ end
20
+
21
+ def callback_id
22
+ event[:callback_id]
23
+ end
24
+
25
+ def channel
26
+ event[:channel][:id]
27
+ end
28
+
29
+ def user
30
+ event[:user][:id]
31
+ end
32
+
33
+ def message_ts
34
+ event[:message_ts]
35
+ end
36
+
37
+ def attachment_id
38
+ event[:attachment_id].to_i
39
+ end
40
+
41
+ def response_url
42
+ event[:response_url]
43
+ end
44
+
45
+ def message_age
46
+ Time.now.to_i - message_ts.to_i
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,17 @@
1
+ module MosEisley
2
+
3
+ module S3PO
4
+
5
+ class GenericEvent
6
+
7
+ attr_reader :event
8
+
9
+ def initialize(e)
10
+ @event = e
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,111 @@
1
+ module MosEisley
2
+
3
+ module S3PO
4
+
5
+ class Message
6
+
7
+ attr_reader :event
8
+
9
+ def initialize(e)
10
+ @event = e
11
+ end
12
+
13
+ def message_type
14
+ return nil if event[:channel].nil?
15
+ t = :na
16
+ case event[:channel][0]
17
+ when 'C'
18
+ t = :channel
19
+ when 'D'
20
+ t = :im
21
+ when 'G'
22
+ t = :group
23
+ end
24
+ return t
25
+ end
26
+
27
+ def simple_message?
28
+ event[:subtype].nil?
29
+ end
30
+
31
+ def for_me?
32
+ # check user is not myself
33
+ myid = MosEisley.config.meta[:user_id]
34
+ return false if event[:user] == myid
35
+ return true if message_type == :im && simple_message?
36
+ return true if (event[:text] =~ /^<@#{myid}[|>]/) && simple_message?
37
+ return false
38
+ end
39
+
40
+ def text
41
+ event[:text]
42
+ end
43
+
44
+ def text=(t)
45
+ event[:text] = t
46
+ end
47
+
48
+ def attachments
49
+ event[:attachments]
50
+ end
51
+
52
+ def attachments=(a)
53
+ event[:attachments] = a
54
+ end
55
+
56
+ def user
57
+ event[:user]
58
+ end
59
+
60
+ def ts
61
+ event[:ts]
62
+ end
63
+
64
+ def channel
65
+ event[:channel]
66
+ end
67
+
68
+ def thread_ts
69
+ event[:thread_ts]
70
+ end
71
+
72
+ def arguments
73
+ return nil unless simple_message?
74
+ t = event[:text]
75
+ t = t.sub(/^<@#{MosEisley.config.meta[:user_id]}[|]?[^>]*>/, '') if for_me?
76
+ t.split
77
+ end
78
+
79
+ def postable_object
80
+ obj = @event.dup
81
+ return obj unless obj[:attachments]
82
+ obj[:attachments] = S3PO.json_with_object(obj[:attachments])
83
+ return obj
84
+ end
85
+
86
+ def reply(t = nil)
87
+ s = {
88
+ channel: channel,
89
+ as_user: true,
90
+ attachments: []
91
+ }
92
+ s[:text] = "<@#{user}> " unless message_type == :im
93
+ if thread_ts
94
+ s[:thread_ts] = thread_ts
95
+ elsif t
96
+ s[:thread_ts] = t
97
+ end
98
+ Message.new(s)
99
+ end
100
+
101
+ def reply_in_thread
102
+ t = thread_ts
103
+ t ||= ts
104
+ reply(t)
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+
111
+ end
data/lib/s3po/s3po.rb ADDED
@@ -0,0 +1,68 @@
1
+ require 'json'
2
+ require 'time'
3
+ require 's3po/generic'
4
+ require 's3po/action'
5
+ require 's3po/message'
6
+
7
+ module MosEisley
8
+
9
+ module S3PO
10
+
11
+ def self.parse_json(json)
12
+ return JSON.parse(json, {symbolize_names: true})
13
+ rescue => e
14
+ MosEisley.logger.warn("JSON parse error: #{e}")
15
+ return nil
16
+ end
17
+
18
+ # Convert object into JSON, optionally pretty-format
19
+ # @param obj [Object] any Ruby object
20
+ # @param opts [Hash] any JSON options
21
+ # @return [String] JSON string
22
+ def self.json_with_object(obj, pretty: false, opts: nil)
23
+ return '{}' if obj.nil?
24
+ if pretty
25
+ opts = {
26
+ indent: ' ',
27
+ space: ' ',
28
+ object_nl: "\n",
29
+ array_nl: "\n"
30
+ }
31
+ end
32
+ JSON.fast_generate(MosEisley::S3PO.format_json_value(obj), opts)
33
+ end
34
+
35
+ # Return Ruby object/value to JSON standard format
36
+ # @param val [Object]
37
+ # @return [Object]
38
+ def self.format_json_value(val)
39
+ s3po = MosEisley::S3PO
40
+ case val
41
+ when Array
42
+ val.map { |v| s3po.format_json_value(v) }
43
+ when Hash
44
+ val.reduce({}) { |h, (k, v)| h.merge({k => s3po.format_json_value(v)}) }
45
+ when String
46
+ val.encode!('UTF-8', {invalid: :replace, undef: :replace})
47
+ when Time
48
+ val.utc.iso8601
49
+ else
50
+ val
51
+ end
52
+ end
53
+
54
+ def self.create_event(e, type = nil)
55
+ type = e[:type] if e[:type]
56
+ case type
57
+ when 'message'
58
+ return Message.new(e)
59
+ when :action
60
+ return Action.new(e)
61
+ else
62
+ return GenericEvent.new(e)
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
2
+ require 'mos-eisley/version'
3
+
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'mos-eisley'
7
+ s.version = MosEisley::Version
8
+ s.authors = ['Ken J.']
9
+ s.email = ['kenjij@gmail.com']
10
+ s.summary = %q{A Ruby based multi-purpose Slack app server}
11
+ s.description = %q{A Ruby based HTTP server for accepting Slack actions, commands, events.}
12
+ s.homepage = 'https://github.com/kenjij/mos-eisley'
13
+ s.license = 'MIT'
14
+
15
+ s.files = `git ls-files`.split($/)
16
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ s.require_paths = ['lib']
18
+
19
+ s.required_ruby_version = '>= 2.1'
20
+ s.add_runtime_dependency 'kajiki', '~> 1.1'
21
+ s.add_runtime_dependency 'thin', '~> 1.7'
22
+ s.add_runtime_dependency 'sinatra', '~> 2.0'
23
+ s.add_runtime_dependency 'em-http-request', '~> 1.1'
24
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mos-eisley
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ken J.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kajiki
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thin
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: em-http-request
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
69
+ description: A Ruby based HTTP server for accepting Slack actions, commands, events.
70
+ email:
71
+ - kenjij@gmail.com
72
+ executables:
73
+ - mos-eisley
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - README.md
78
+ - bin/mos-eisley
79
+ - lib/http-client/client.rb
80
+ - lib/http-client/webapi.rb
81
+ - lib/http-server/helper.rb
82
+ - lib/http-server/server.rb
83
+ - lib/mos-eisley.rb
84
+ - lib/mos-eisley/config.rb
85
+ - lib/mos-eisley/handler.rb
86
+ - lib/mos-eisley/logger.rb
87
+ - lib/mos-eisley/version.rb
88
+ - lib/s3po/action.rb
89
+ - lib/s3po/generic.rb
90
+ - lib/s3po/message.rb
91
+ - lib/s3po/s3po.rb
92
+ - mos-eisley.gemspec
93
+ homepage: https://github.com/kenjij/mos-eisley
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '2.1'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.4.8
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: A Ruby based multi-purpose Slack app server
117
+ test_files: []