mos-eisley 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []