bows 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 +7 -0
- data/lib/ribbon/intercom.rb +42 -0
- data/lib/ribbon/intercom/client.rb +61 -0
- data/lib/ribbon/intercom/client/mock_sdk.rb +13 -0
- data/lib/ribbon/intercom/client/sdk.rb +99 -0
- data/lib/ribbon/intercom/client/sdk/adapters.rb +10 -0
- data/lib/ribbon/intercom/client/sdk/adapters/adapter.rb +77 -0
- data/lib/ribbon/intercom/client/sdk/adapters/adapter/response.rb +13 -0
- data/lib/ribbon/intercom/client/sdk/adapters/http_adapter.rb +32 -0
- data/lib/ribbon/intercom/client/sdk/adapters/http_adapter/connection.rb +34 -0
- data/lib/ribbon/intercom/client/sdk/adapters/local_adapter.rb +55 -0
- data/lib/ribbon/intercom/client/sdk/adapters/mock_adapter.rb +40 -0
- data/lib/ribbon/intercom/errors.rb +66 -0
- data/lib/ribbon/intercom/package.rb +121 -0
- data/lib/ribbon/intercom/packageable.rb +6 -0
- data/lib/ribbon/intercom/packageable/mixin.rb +29 -0
- data/lib/ribbon/intercom/packet.rb +52 -0
- data/lib/ribbon/intercom/packet/method_queue.rb +28 -0
- data/lib/ribbon/intercom/railtie.rb +14 -0
- data/lib/ribbon/intercom/service.rb +273 -0
- data/lib/ribbon/intercom/service/channel.rb +203 -0
- data/lib/ribbon/intercom/service/channel/stores.rb +9 -0
- data/lib/ribbon/intercom/service/channel/stores/mock_store.rb +40 -0
- data/lib/ribbon/intercom/service/channel/stores/redis_store.rb +196 -0
- data/lib/ribbon/intercom/service/channel/stores/store.rb +31 -0
- data/lib/ribbon/intercom/utils.rb +72 -0
- data/lib/ribbon/intercom/utils/method_chain.rb +38 -0
- data/lib/ribbon/intercom/utils/mixins.rb +5 -0
- data/lib/ribbon/intercom/utils/mixins/mock_safe.rb +26 -0
- data/lib/ribbon/intercom/utils/signer.rb +71 -0
- data/lib/ribbon/intercom/version.rb +5 -0
- data/lib/tasks/intercom.rake +24 -0
- metadata +215 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1f136b3b94c864c9bdfff6829ee3add739e565ec
|
4
|
+
data.tar.gz: 34d7ab35c8d8e417f040faa34d1bf16dcb3f553e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 759458f070d855822f8597379c8ad392935d1548d039bd85ac281719ac5114054ef18fab3beeed7625fb93c1704ee26ce511796b8f5eac8e8b589e59feb720b8
|
7
|
+
data.tar.gz: 926eb6957418a8564100da028b20b66b132636103dc8f963b74de747a6c0793964c500fad994fc3ae0e6af635ae3ef50b072a2b1529687e94c27ace520920b50
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'ribbon/intercom/version'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
module Ribbon
|
5
|
+
module Intercom
|
6
|
+
require 'ribbon/intercom/railtie' if defined?(Rails)
|
7
|
+
autoload(:Service, 'ribbon/intercom/service')
|
8
|
+
autoload(:Errors, 'ribbon/intercom/errors')
|
9
|
+
autoload(:Client, 'ribbon/intercom/client')
|
10
|
+
autoload(:Package, 'ribbon/intercom/package')
|
11
|
+
autoload(:Packageable, 'ribbon/intercom/packageable')
|
12
|
+
autoload(:Packet, 'ribbon/intercom/packet')
|
13
|
+
autoload(:Utils, 'ribbon/intercom/utils')
|
14
|
+
|
15
|
+
module_function
|
16
|
+
|
17
|
+
def load_tasks
|
18
|
+
Dir[
|
19
|
+
File.expand_path("../../tasks", __FILE__) + '/**.rake'
|
20
|
+
].each { |rake_file| load rake_file }
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(meth, *args, &block)
|
24
|
+
client.send(meth, *args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def client
|
28
|
+
@_client ||= Client.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def mock_safe
|
32
|
+
orig_client = client
|
33
|
+
@_client = @_client.mock_safe
|
34
|
+
yield
|
35
|
+
ensure
|
36
|
+
@_client = orig_client
|
37
|
+
end
|
38
|
+
end # Intercom
|
39
|
+
end # Ribbon
|
40
|
+
|
41
|
+
# Create a shortcut to the module
|
42
|
+
Intercom = Ribbon::Intercom
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'ribbon/config'
|
2
|
+
|
3
|
+
module Ribbon::Intercom
|
4
|
+
class Client
|
5
|
+
autoload(:SDK, 'ribbon/intercom/client/sdk')
|
6
|
+
autoload(:MockSDK, 'ribbon/intercom/client/mock_sdk')
|
7
|
+
|
8
|
+
def config(&block)
|
9
|
+
(@__config ||= Ribbon::Config.new).tap { |config|
|
10
|
+
if block_given?
|
11
|
+
config.define(&block)
|
12
|
+
end
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](handle)
|
17
|
+
_load_sdk(handle)
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Return a mock safe version of this client.
|
22
|
+
def mock_safe
|
23
|
+
dup.tap { |client|
|
24
|
+
client.preload_sdks
|
25
|
+
|
26
|
+
# Make SDK instances mock safe
|
27
|
+
client.sdk_instances = Hash[
|
28
|
+
client.sdk_instances.map { |service, sdk| [service, sdk.mock_safe] }
|
29
|
+
]
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def preload_sdks
|
34
|
+
if config.service?
|
35
|
+
config.service.each { |name, *args|
|
36
|
+
_load_sdk(name)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
attr_accessor :sdk_instances
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def _load_sdk(handle)
|
48
|
+
raise Errors::ServiceNotDefinedError unless config.service?
|
49
|
+
|
50
|
+
(self.sdk_instances ||= Hash.new { |hash, key|
|
51
|
+
# Get the last service if there are duplicates
|
52
|
+
if (service_def = config.service.select { |r| r.first == key }.last)
|
53
|
+
name, config = service_def
|
54
|
+
hash[key] = SDK.new(config[:url], config[:token], config[:secret])
|
55
|
+
else
|
56
|
+
raise Errors::ServiceNotDefinedError
|
57
|
+
end
|
58
|
+
})[handle.to_sym]
|
59
|
+
end
|
60
|
+
end # Client
|
61
|
+
end # Ribbon::Intercom
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Ribbon::Intercom
|
2
|
+
class Client
|
3
|
+
class MockSDK < SDK
|
4
|
+
def initialize(service)
|
5
|
+
super(Adapters::MockAdapter.new(service))
|
6
|
+
end
|
7
|
+
|
8
|
+
def with_permissions(*perms, &block)
|
9
|
+
adapter.with_permissions(*perms, &block)
|
10
|
+
end
|
11
|
+
end # MockSDK
|
12
|
+
end # Client
|
13
|
+
end # Ribbon::Intercom
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Ribbon::Intercom
|
4
|
+
class Client
|
5
|
+
class SDK
|
6
|
+
autoload(:Adapters, 'ribbon/intercom/client/sdk/adapters')
|
7
|
+
|
8
|
+
include Utils::Mixins::MockSafe
|
9
|
+
|
10
|
+
attr_reader :adapter
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
case args.first
|
14
|
+
when Adapters::Adapter
|
15
|
+
self.adapter = args.first
|
16
|
+
else
|
17
|
+
self.adapter = Adapters::HttpAdapter.new(*args)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def begin
|
22
|
+
Utils::MethodChain.begin { |methods|
|
23
|
+
queue = Packet::MethodQueue.new
|
24
|
+
methods.each { |meth, *args| queue.enqueue(meth, *args) }
|
25
|
+
send_packet(method_queue: queue).retval
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Returns the headers defined for this SDK. Optionally, you may also define
|
31
|
+
# additional headers you'd like to add/override.
|
32
|
+
def headers(new_headers={})
|
33
|
+
adapter.headers(new_headers)
|
34
|
+
end
|
35
|
+
|
36
|
+
def connect(*args)
|
37
|
+
adapter.connect(*args)
|
38
|
+
end
|
39
|
+
|
40
|
+
def connected?
|
41
|
+
adapter.connected?
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Calls the method on the adapter returning the response Packet
|
46
|
+
def call(method_name, *args)
|
47
|
+
send_packet(
|
48
|
+
method_queue: Packet::MethodQueue.new.enqueue(method_name, *args)
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Sends the packet with the adapter, returning the response Packet.
|
54
|
+
#
|
55
|
+
# Intended to be called by Package.
|
56
|
+
def send_packet(packet)
|
57
|
+
_process_response(adapter.send_packet(packet))
|
58
|
+
end
|
59
|
+
|
60
|
+
def dup
|
61
|
+
super.tap { |sdk|
|
62
|
+
sdk.adapter = adapter.dup
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
def adapter=(adapter)
|
69
|
+
@adapter = adapter
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
##
|
75
|
+
# Simulates calling the remote method as if it were a local method.
|
76
|
+
#
|
77
|
+
# Intended to be called by end-users.
|
78
|
+
def method_missing(meth, *args, &block)
|
79
|
+
call(meth, *args).retval
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Process a Packet object returned by Adapter#send_packet.
|
84
|
+
def _process_response(packet)
|
85
|
+
_handle_response_error(packet) if packet.error?
|
86
|
+
|
87
|
+
Package.init_packages(packet.retval, self)
|
88
|
+
packet
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Raises an error depending on what went wrong.
|
93
|
+
def _handle_response_error(packet)
|
94
|
+
raise 'packet contains no error' unless packet.error?
|
95
|
+
raise packet.error
|
96
|
+
end
|
97
|
+
end # SDK
|
98
|
+
end # Client
|
99
|
+
end # Ribbon::Intercom
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Ribbon::Intercom
|
2
|
+
class Client::SDK
|
3
|
+
module Adapters
|
4
|
+
autoload(:Adapter, 'ribbon/intercom/client/sdk/adapters/adapter')
|
5
|
+
autoload(:HttpAdapter, 'ribbon/intercom/client/sdk/adapters/http_adapter')
|
6
|
+
autoload(:LocalAdapter, 'ribbon/intercom/client/sdk/adapters/local_adapter')
|
7
|
+
autoload(:MockAdapter, 'ribbon/intercom/client/sdk/adapters/mock_adapter')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Ribbon::Intercom
|
2
|
+
module Client::SDK::Adapters
|
3
|
+
class Adapter
|
4
|
+
autoload(:Response, 'ribbon/intercom/client/sdk/adapters/adapter/response')
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
connect(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Call the method on the service.
|
12
|
+
#
|
13
|
+
# @deprecated This method is only called by tests. Don't call it elsewhere.
|
14
|
+
def call(method_name, *args)
|
15
|
+
send_packet(
|
16
|
+
method_queue: Packet::MethodQueue.new.enqueue(method_name, *args)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Send a packet to the service and returns the Packet returned by the service.
|
22
|
+
def send_packet(packet)
|
23
|
+
packet = Packet.new(packet) if packet.is_a?(Hash)
|
24
|
+
|
25
|
+
send_packet!(packet.encode).tap { |response|
|
26
|
+
raise TypeError, "send_packet! should return an Adapter::Response" unless response.is_a?(Response)
|
27
|
+
}.packet
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Returns the headers defined for this Adapter. Optionally, you may also
|
32
|
+
# define additional headers you'd like to add/override.
|
33
|
+
def headers(new_headers={})
|
34
|
+
(@headers ||= {}).merge!(new_headers)
|
35
|
+
end
|
36
|
+
|
37
|
+
def dup
|
38
|
+
super.tap { |adapter|
|
39
|
+
adapter.headers = @headers.dup if @headers
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Connect to a service. The specific arguments depend on the Adapter
|
45
|
+
# subclass.
|
46
|
+
def connect(*args)
|
47
|
+
raise NotImplementedError
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Returns whether or not the Adapter is connected to a service.
|
52
|
+
def connected?
|
53
|
+
raise NotImplementedError
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Actually send the packet to the service. Should return an Adapter::Response object.
|
58
|
+
def send_packet!(packet)
|
59
|
+
raise NotImplementedError
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def headers=(h)
|
65
|
+
@headers = h
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
##
|
71
|
+
# Encode the arguments for transmission to the service.
|
72
|
+
def _encode_args(*args)
|
73
|
+
Base64.strict_encode64(Marshal.dump(Utils.sanitize(args)))
|
74
|
+
end
|
75
|
+
end # Adapter
|
76
|
+
end # Client::SDK::Adapters
|
77
|
+
end # Ribbon::Intercom
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Ribbon::Intercom
|
2
|
+
class Client::SDK::Adapters::Adapter
|
3
|
+
class Response < Rack::Response
|
4
|
+
def body
|
5
|
+
super.join
|
6
|
+
end
|
7
|
+
|
8
|
+
def packet
|
9
|
+
@__packet ||= Packet.decode(body) unless body.empty?
|
10
|
+
end
|
11
|
+
end # Response
|
12
|
+
end # Client::SDK::Adapters::Adapter
|
13
|
+
end # Ribbon::Intercom
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Ribbon::Intercom
|
2
|
+
module Client::SDK::Adapters
|
3
|
+
class HttpAdapter < Adapter
|
4
|
+
autoload(:Connection, 'ribbon/intercom/client/sdk/adapters/http_adapter/connection')
|
5
|
+
|
6
|
+
attr_reader :connection
|
7
|
+
|
8
|
+
def connect(*args)
|
9
|
+
@_connection_args = args.dup
|
10
|
+
end
|
11
|
+
|
12
|
+
def connected?
|
13
|
+
!!connection
|
14
|
+
end
|
15
|
+
|
16
|
+
def connection
|
17
|
+
@__connection ||= Connection.new(*@_connection_args)
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Send the encoded packet up to the service via an HTTP PUT.
|
22
|
+
def send_packet!(encoded_packet)
|
23
|
+
response = connection.put(
|
24
|
+
headers: headers,
|
25
|
+
body: encoded_packet
|
26
|
+
)
|
27
|
+
|
28
|
+
Adapter::Response.new(response.body, response.code.to_i, response)
|
29
|
+
end
|
30
|
+
end # HttpAdapter
|
31
|
+
end # Client::SDK::Adapters
|
32
|
+
end # Ribbon::Intercom
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'openssl'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Ribbon::Intercom
|
6
|
+
module Client::SDK::Adapters
|
7
|
+
class HttpAdapter::Connection
|
8
|
+
attr_reader :url
|
9
|
+
|
10
|
+
def initialize(url, token, secret)
|
11
|
+
@url = url.is_a?(String) ? URI(url) : url
|
12
|
+
|
13
|
+
@_client = Net::HTTP.new(@url.hostname, @url.port)
|
14
|
+
@_client.use_ssl = @url.is_a?(URI::HTTPS)
|
15
|
+
@_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
16
|
+
@_client.cert_store = OpenSSL::X509::Store.new.tap { |s| s.set_default_paths }
|
17
|
+
|
18
|
+
@_headers = {
|
19
|
+
'Authorization' => "Basic #{Base64.strict_encode64("#{token}:#{secret}")}"
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def put(params={})
|
24
|
+
@_client.put(url.request_uri, params[:body], _prepare_headers(params[:headers]).merge(@_headers))
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def _prepare_headers(headers)
|
30
|
+
Hash[(headers || {}).map { |k, v| [k.to_s, v.to_s] }]
|
31
|
+
end
|
32
|
+
end # HttpAdapter::Connection
|
33
|
+
end # Client::SDK::Adapters
|
34
|
+
end # Ribbon::Intercom
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Ribbon::Intercom
|
4
|
+
module Client::SDK::Adapters
|
5
|
+
class LocalAdapter < Adapter
|
6
|
+
attr_reader :service
|
7
|
+
attr_accessor :channel_token
|
8
|
+
attr_accessor :channel_secret
|
9
|
+
|
10
|
+
def connect(service, params={})
|
11
|
+
case service
|
12
|
+
when Service
|
13
|
+
@service = service
|
14
|
+
else
|
15
|
+
raise ArgumentError, "Expected a service, got: #{service.inspect}"
|
16
|
+
end
|
17
|
+
|
18
|
+
@channel_token = params[:channel_token]
|
19
|
+
@channel_secret = params[:channel_secret]
|
20
|
+
end
|
21
|
+
|
22
|
+
def connected?(*args)
|
23
|
+
!!service
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Mimics an HTTP PUT
|
28
|
+
def send_packet!(encoded_packet)
|
29
|
+
response = service.call(
|
30
|
+
_http_headers.merge(
|
31
|
+
'HTTP_AUTHORIZATION' => _http_auth,
|
32
|
+
'REQUEST_METHOD' => 'PUT',
|
33
|
+
'rack.input' => StringIO.new(encoded_packet)
|
34
|
+
)
|
35
|
+
)
|
36
|
+
|
37
|
+
Adapter::Response.new(response[2], response[0], response[1])
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def _http_auth
|
43
|
+
"Basic #{Base64.strict_encode64("#{channel_token}:#{channel_secret}")}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def _http_headers
|
47
|
+
Hash[headers.map { |name, value| [_header_to_http(name), value] }]
|
48
|
+
end
|
49
|
+
|
50
|
+
def _header_to_http(name)
|
51
|
+
"HTTP_#{name.to_s.upcase.gsub('-', '_')}"
|
52
|
+
end
|
53
|
+
end # MockAdapter
|
54
|
+
end # Client::SDK::Adapters
|
55
|
+
end # Ribbon::Intercom
|