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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ribbon/intercom.rb +42 -0
  3. data/lib/ribbon/intercom/client.rb +61 -0
  4. data/lib/ribbon/intercom/client/mock_sdk.rb +13 -0
  5. data/lib/ribbon/intercom/client/sdk.rb +99 -0
  6. data/lib/ribbon/intercom/client/sdk/adapters.rb +10 -0
  7. data/lib/ribbon/intercom/client/sdk/adapters/adapter.rb +77 -0
  8. data/lib/ribbon/intercom/client/sdk/adapters/adapter/response.rb +13 -0
  9. data/lib/ribbon/intercom/client/sdk/adapters/http_adapter.rb +32 -0
  10. data/lib/ribbon/intercom/client/sdk/adapters/http_adapter/connection.rb +34 -0
  11. data/lib/ribbon/intercom/client/sdk/adapters/local_adapter.rb +55 -0
  12. data/lib/ribbon/intercom/client/sdk/adapters/mock_adapter.rb +40 -0
  13. data/lib/ribbon/intercom/errors.rb +66 -0
  14. data/lib/ribbon/intercom/package.rb +121 -0
  15. data/lib/ribbon/intercom/packageable.rb +6 -0
  16. data/lib/ribbon/intercom/packageable/mixin.rb +29 -0
  17. data/lib/ribbon/intercom/packet.rb +52 -0
  18. data/lib/ribbon/intercom/packet/method_queue.rb +28 -0
  19. data/lib/ribbon/intercom/railtie.rb +14 -0
  20. data/lib/ribbon/intercom/service.rb +273 -0
  21. data/lib/ribbon/intercom/service/channel.rb +203 -0
  22. data/lib/ribbon/intercom/service/channel/stores.rb +9 -0
  23. data/lib/ribbon/intercom/service/channel/stores/mock_store.rb +40 -0
  24. data/lib/ribbon/intercom/service/channel/stores/redis_store.rb +196 -0
  25. data/lib/ribbon/intercom/service/channel/stores/store.rb +31 -0
  26. data/lib/ribbon/intercom/utils.rb +72 -0
  27. data/lib/ribbon/intercom/utils/method_chain.rb +38 -0
  28. data/lib/ribbon/intercom/utils/mixins.rb +5 -0
  29. data/lib/ribbon/intercom/utils/mixins/mock_safe.rb +26 -0
  30. data/lib/ribbon/intercom/utils/signer.rb +71 -0
  31. data/lib/ribbon/intercom/version.rb +5 -0
  32. data/lib/tasks/intercom.rake +24 -0
  33. 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