ribbon-intercom 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ribbon/intercom/client/mock_sdk.rb +13 -0
  3. data/lib/ribbon/intercom/client/sdk/adapters/adapter/response.rb +38 -0
  4. data/lib/ribbon/intercom/client/sdk/adapters/adapter.rb +51 -0
  5. data/lib/ribbon/intercom/client/sdk/adapters/http_adapter/connection.rb +34 -0
  6. data/lib/ribbon/intercom/client/sdk/adapters/http_adapter.rb +26 -0
  7. data/lib/ribbon/intercom/client/sdk/adapters/local_adapter.rb +54 -0
  8. data/lib/ribbon/intercom/client/sdk/adapters/mock_adapter.rb +40 -0
  9. data/lib/ribbon/intercom/client/sdk/adapters.rb +10 -0
  10. data/lib/ribbon/intercom/client/sdk.rb +71 -26
  11. data/lib/ribbon/intercom/client.rb +35 -7
  12. data/lib/ribbon/intercom/errors.rb +34 -6
  13. data/lib/ribbon/intercom/package.rb +64 -0
  14. data/lib/ribbon/intercom/packageable/mixin.rb +35 -0
  15. data/lib/ribbon/intercom/packageable.rb +6 -0
  16. data/lib/ribbon/intercom/service/channel/stores/mock_store.rb +40 -0
  17. data/lib/ribbon/intercom/service/channel/stores/redis_store.rb +186 -0
  18. data/lib/ribbon/intercom/service/{channel_stores/base.rb → channel/stores/store.rb} +13 -5
  19. data/lib/ribbon/intercom/service/channel/stores.rb +9 -0
  20. data/lib/ribbon/intercom/service/channel.rb +106 -4
  21. data/lib/ribbon/intercom/service.rb +156 -95
  22. data/lib/ribbon/intercom/utils/mixins/mock_safe.rb +26 -0
  23. data/lib/ribbon/intercom/utils/mixins.rb +5 -0
  24. data/lib/ribbon/intercom/utils/signer.rb +71 -0
  25. data/lib/ribbon/intercom/utils.rb +40 -13
  26. data/lib/ribbon/intercom/version.rb +1 -1
  27. data/lib/ribbon/intercom.rb +10 -7
  28. data/lib/tasks/intercom.rake +3 -3
  29. metadata +20 -20
  30. data/lib/ribbon/intercom/client/sdk/connection.rb +0 -35
  31. data/lib/ribbon/intercom/client/sdk/response.rb +0 -59
  32. data/lib/ribbon/intercom/service/channel_stores/redis_store.rb +0 -60
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dc502869702b01539172c77ab6f12fea946251f1
4
- data.tar.gz: 15672af11bd53026f9613035366b5d3b9fe683a5
3
+ metadata.gz: 977c89158ba0646225543c4b65b86fc9db5663b4
4
+ data.tar.gz: 9482ff868c0d2e7974cbf08e329c8e18eb85b21a
5
5
  SHA512:
6
- metadata.gz: 110c7d7b8f7b5f19ac51eaad0d85f7f8ff19f05bbcf8a10aa12b53ec6d5d6ca7887d1034a573de8179bb466f9025b5bc7c0ff5a7dcfbbc5384759f20b72afb9b
7
- data.tar.gz: 44f4a6fbb476e2f80ce65250488ea50405908e6f1ccb3410923b4c4f35e6bab5e74b3545cd00cdd61830d5ee09c23e5aca08737b2a5c83ec260331278037d15e
6
+ metadata.gz: 6ac6cdc49ae1e738c21ad1cdc91a1d02340c7d04d35fe50a3eab1d9ca08e767366b3725b828b21f2e29b132a5bec70668683b337e80096e5b02e1c8f4063650f
7
+ data.tar.gz: ed7da55ea2c9dca75e712cf83f691977ed3aec4bb01f6ed0f5dcdf6999320d59b6dd091b954107f19cdaa7bc20985882c1293177e74f5f2e281720ca0080e5f0
@@ -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,38 @@
1
+ module Ribbon::Intercom
2
+ class Client::SDK::Adapters::Adapter
3
+ class Response < Rack::Response
4
+ attr_reader :method_name
5
+
6
+ def initialize(body, status, headers, method_name)
7
+ super(body, status, headers)
8
+ @method_name = method_name.to_sym
9
+ end
10
+
11
+ def missing_permissions
12
+ @__missing_permissions ||= _intercom_permissions_missing
13
+ end
14
+
15
+ def body
16
+ super.join
17
+ end
18
+
19
+ ##
20
+ # Decode the response body received from the service.
21
+ def retval
22
+ @__retval ||= Marshal.load(Base64.strict_decode64(body)) unless body.empty?
23
+ end
24
+
25
+ private
26
+
27
+ def _intercom_permissions_missing
28
+ key = _intercom_permissions_missing_header
29
+ headers[key] && headers[key].split(',').to_set
30
+ end
31
+
32
+ def _intercom_permissions_missing_header
33
+ missing_keys = ['X-Intercom-Permissions-Missing', :x_intercom_permissions_missing]
34
+ missing_keys.detect { |key| headers.key?(key) }
35
+ end
36
+ end # Response
37
+ end # Client::SDK::Adapters::Adapter
38
+ end # Ribbon::Intercom
@@ -0,0 +1,51 @@
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
+ def call(method_name, *args)
13
+ call!(method_name, _encode_args(*args)).tap { |response|
14
+ raise TypeError, "call! should return an Adapter::Response" unless response.is_a?(Response)
15
+ raise "response should have correct method name" unless response.method_name == method_name.to_sym
16
+ }
17
+ end
18
+
19
+ def headers(h={})
20
+ (@__headers ||= {}).merge!(h)
21
+ end
22
+
23
+ ##
24
+ # Connect to a service. The specific arguments depend on the Adapter
25
+ # subclass.
26
+ def connect(*args)
27
+ raise NotImplementedError
28
+ end
29
+
30
+ ##
31
+ # Returns whether or not the Adapter is connected to a service.
32
+ def connected?
33
+ raise NotImplementedError
34
+ end
35
+
36
+ ##
37
+ # Actually call the method on the service. Should return an Adapter::Response object.
38
+ def call!(method_name, *args)
39
+ raise NotImplementedError
40
+ end
41
+
42
+ private
43
+
44
+ ##
45
+ # Encode the arguments for transmission to the service.
46
+ def _encode_args(*args)
47
+ Base64.strict_encode64(Marshal.dump(Utils.sanitize(args)))
48
+ end
49
+ end # Adapter
50
+ end # Client::SDK::Adapters
51
+ 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,26 @@
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 = Connection.new(*args)
10
+ end
11
+
12
+ def connected?
13
+ !!connection
14
+ end
15
+
16
+ def call!(method_name, encoded_args)
17
+ response = connection.put(
18
+ headers: headers.merge("X-Intercom-Method" => method_name),
19
+ body: encoded_args
20
+ )
21
+
22
+ Adapter::Response.new(response.body, response.code.to_i, response, method_name)
23
+ end
24
+ end # HttpAdapter
25
+ end # Client::SDK::Adapters
26
+ end # Ribbon::Intercom
@@ -0,0 +1,54 @@
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
+ def call!(method_name, encoded_args)
27
+ response = service.call(
28
+ _http_headers.merge(
29
+ 'HTTP_AUTHORIZATION' => _http_auth,
30
+ 'HTTP_X_INTERCOM_METHOD' => method_name.to_s,
31
+ 'REQUEST_METHOD' => 'PUT',
32
+ 'rack.input' => StringIO.new(encoded_args)
33
+ )
34
+ )
35
+
36
+ Response.new(response[2], response[0], response[1], method_name)
37
+ end
38
+
39
+ private
40
+
41
+ def _http_auth
42
+ "Basic #{Base64.strict_encode64("#{channel_token}:#{channel_secret}")}"
43
+ end
44
+
45
+ def _http_headers
46
+ Hash[headers.map { |name, value| [_header_to_http(name), value] }]
47
+ end
48
+
49
+ def _header_to_http(name)
50
+ name.to_s.upcase.gsub('-', '_')
51
+ end
52
+ end # MockAdapter
53
+ end # Client::SDK::Adapters
54
+ end # Ribbon::Intercom
@@ -0,0 +1,40 @@
1
+ module Ribbon::Intercom
2
+ module Client::SDK::Adapters
3
+ class MockAdapter < LocalAdapter
4
+ attr_reader :store
5
+
6
+ def connect(service)
7
+ if service.is_a?(Class) && service < Service
8
+ service = service.new(store: Service::Channel::Stores::MockStore.new)
9
+ end
10
+
11
+ unless service.is_a?(Service)
12
+ raise ArgumentError, "Expected a service, got: #{service.inspect}"
13
+ end
14
+
15
+ unless service.store.is_a?(Service::Channel::Stores::MockStore)
16
+ raise ArgumentError, "Expected service to have a MockStore, got: #{service.store.inspect}"
17
+ end
18
+
19
+ super(service)
20
+ @store = service.store
21
+ end
22
+
23
+ def with_permissions(*perms, &block)
24
+ channel = store.open_channel(name: 'mock channel', may: perms)
25
+ secret = channel.rotate_secret!
26
+ with_channel(channel.token, secret, &block)
27
+ ensure
28
+ channel.close
29
+ end
30
+
31
+ def with_channel(token, secret)
32
+ token_prv, secret_prv = self.channel_token, self.channel_secret
33
+ self.channel_token, self.channel_secret = token, secret
34
+ yield
35
+ ensure
36
+ self.channel_token, self.channel_secret = token_prv, secret_prv
37
+ end
38
+ end # MockAdapter
39
+ end # Client::SDK::Adapters
40
+ 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
@@ -1,49 +1,94 @@
1
+ require 'base64'
2
+
1
3
  module Ribbon::Intercom
2
4
  class Client
3
5
  class SDK
4
- autoload(:Connection, 'ribbon/intercom/client/sdk/connection')
5
- autoload(:Response, 'ribbon/intercom/client/sdk/response')
6
+ autoload(:Adapters, 'ribbon/intercom/client/sdk/adapters')
7
+
8
+ include Utils::Mixins::MockSafe
6
9
 
7
- attr_reader :connection
10
+ attr_reader :adapter
8
11
 
9
12
  def initialize(*args)
10
- connect(*args)
13
+ case args.first
14
+ when Adapters::Adapter
15
+ @adapter = args.first
16
+ else
17
+ @adapter = Adapters::HttpAdapter.new(*args)
18
+ end
19
+ end
20
+
21
+ def headers(h={})
22
+ adapter.headers(h)
11
23
  end
12
24
 
13
25
  def connect(*args)
14
- @connection = Connection.new(*args)
26
+ adapter.connect(*args)
15
27
  end
16
28
 
17
29
  def connected?
18
- !!connection
30
+ adapter.connected?
19
31
  end
20
32
 
21
- def method_missing(meth, *args, &block)
22
- _send_request(meth, *args)
33
+ ##
34
+ # Calls the method on the adapter returning the Adapter::Response.
35
+ #
36
+ # Intended to be called by Package.
37
+ def call(method_name, *args)
38
+ _process_response(adapter.call(method_name, *args))
23
39
  end
24
40
 
25
41
  private
26
42
 
27
- def _send_request(method_name, *args)
28
- response = connection.put("", method_name, args)
43
+ ##
44
+ # Simulates calling the remote method as if it were a local method.
45
+ #
46
+ # Intended to be called by end-users.
47
+ def method_missing(meth, *args, &block)
48
+ call(meth, *args).retval
49
+ end
29
50
 
30
- if response.success?
31
- response.body
32
- else
33
- case response.code
34
- when 401
35
- raise Errors::AuthenticationError, request.body
36
- when 403
37
- raise Errors::MissingPermissionsError, response.missing_permissions.to_a.join(', ')
38
- when 404
39
- raise Errors::InvalidMethodError, "#{method_name} is not a valid method"
40
- when 500
41
- raise Errors::ServerError, response.body
42
- else
43
- raise Errors::RequestFailureError, response.body
51
+ ##
52
+ # Process an Adapter::Response object returned by Adapter#call.
53
+ def _process_response(response)
54
+ _handle_response_error(response) unless response.successful?
55
+
56
+ _init_packages(response.retval)
57
+ response
58
+ end
59
+
60
+ ##
61
+ # Raises an error depending on what went wrong.
62
+ def _handle_response_error(response)
63
+ raise 'called for successful response' if response.successful?
64
+
65
+ encoded_error = response.headers['X-Intercom-Error']
66
+
67
+ if encoded_error && !encoded_error.empty?
68
+ begin
69
+ decoded_error = Base64.strict_decode64(encoded_error)
70
+ error = Marshal.load(decoded_error)
71
+ rescue
72
+ error = Errors::ServerError.new('unknown server error')
44
73
  end
45
74
  end
75
+
76
+ raise error || Errors::ServerError.new('unexpected server error')
77
+ end # _handle_response
78
+
79
+ ##
80
+ # Walks the object and initializes all packages (i.e., sets them up to be
81
+ # accessed by the end-user on the client).
82
+ def _init_packages(object)
83
+ Utils.walk(object) { |object|
84
+ if object.is_a?(Package)
85
+ object.sdk = dup
86
+ object.mock_safe! if mock_safe?
87
+ end
88
+
89
+ object
90
+ }
46
91
  end
47
- end # Client
48
- end # SDK
92
+ end # SDK
93
+ end # Client
49
94
  end # Ribbon::Intercom
@@ -3,6 +3,7 @@ require 'ribbon/config'
3
3
  module Ribbon::Intercom
4
4
  class Client
5
5
  autoload(:SDK, 'ribbon/intercom/client/sdk')
6
+ autoload(:MockSDK, 'ribbon/intercom/client/mock_sdk')
6
7
 
7
8
  def config(&block)
8
9
  (@__config ||= Ribbon::Config.new).tap { |config|
@@ -16,16 +17,43 @@ module Ribbon::Intercom
16
17
  _load_sdk(handle)
17
18
  end
18
19
 
19
- def _load_sdk(handle, url=nil, token=nil, secret=nil)
20
- raise Errors::NoRemotesCreatedError unless config.remote?
20
+ ##
21
+ # Return a mock safe version of this client.
22
+ def mock_safe
23
+ dup.tap { |client|
24
+ client.preload_sdks
21
25
 
22
- (@_sdk_instances ||= Hash.new { |hash, key|
23
- if (remote = config.remote.select { |r| r.first == key }.last)
24
- # Get the last remote if there are duplicates
25
- config = remote.last
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
26
54
  hash[key] = SDK.new(config[:url], config[:token], config[:secret])
27
55
  else
28
- raise Errors::RemoteNotFoundError
56
+ raise Errors::ServiceNotDefinedError
29
57
  end
30
58
  })[handle.to_sym]
31
59
  end
@@ -2,14 +2,44 @@ module Ribbon::Intercom
2
2
  module Errors
3
3
  class Error < StandardError; end
4
4
 
5
+ #############
6
+ # Http Errors
7
+ class HttpError < Error; end
8
+
9
+ ##
10
+ # Request Errors
11
+
12
+ # 400 Error
13
+ class RequestError < HttpError; end
14
+ class UnsafeArgumentError < RequestError; end
15
+ class InvalidSubjectSignatureError < RequestError; end
16
+
17
+ # 401 Error
18
+ class AuthenticationError < RequestError; end
19
+
20
+ # 403 Error
21
+ class ForbiddenError < RequestError; end
22
+ class InsufficientPermissionsError < ForbiddenError; end
23
+
24
+ # 404 Not Found
25
+ class NotFoundError < RequestError; end
26
+ class InvalidMethodError < NotFoundError; end
27
+
28
+ # 405 Method Not Allowed
29
+ class MethodNotAllowedError < RequestError; end
30
+
31
+ ##
32
+ # Server Errors
33
+
34
+ # 500 Error
35
+ class ServerError < HttpError; end
36
+ class UnsafeResponseError < ServerError; end
37
+
5
38
  # General Errors
6
- class MissingPermissionsError < Error; end
7
- class ServerError < Error; end
8
39
  class UnsafeValueError < Error; end
9
40
 
10
41
  # Intercom Errors
11
- class RemoteNotFoundError < Error; end
12
- class NoRemotesCreatedError < Error; end
42
+ class ServiceNotDefinedError < Error; end
13
43
 
14
44
  # Service Errors
15
45
  class NoPermissionsError < Error; end
@@ -22,8 +52,6 @@ module Ribbon::Intercom
22
52
 
23
53
  # SDK Errors
24
54
  class RequestFailureError < Error; end
25
- class InvalidMethodError < Error; end
26
- class AuthenticationError < Error; end
27
55
 
28
56
  # Channel Errors
29
57
  class ChannelNameMissingError < Error; end
@@ -0,0 +1,64 @@
1
+ require 'base64'
2
+
3
+ module Ribbon::Intercom
4
+ class Package
5
+ include Utils::Mixins::MockSafe
6
+
7
+ attr_reader :sdk
8
+
9
+ def initialize(subject_data=nil, data=nil)
10
+ self._subject_data = subject_data
11
+ @_data = data
12
+ end
13
+
14
+ def sdk=(sdk)
15
+ _set_sdk_headers(sdk)
16
+ @sdk = sdk
17
+ end
18
+
19
+ protected
20
+
21
+ def _subject_data=(data)
22
+ @_subject_data = data
23
+ _set_sdk_headers
24
+ end
25
+
26
+ private
27
+
28
+ def method_missing(meth, *args, &block)
29
+ if @_data && @_data.key?(meth)
30
+ @_data[meth]
31
+ elsif sdk
32
+ _process_response(sdk.call(meth, *args))
33
+ else
34
+ super
35
+ end
36
+ end
37
+
38
+ def marshal_dump
39
+ [@_subject_data, @_data]
40
+ end
41
+
42
+ def marshal_load(array)
43
+ self._subject_data = array[0]
44
+ @_data = array[1]
45
+
46
+ end
47
+
48
+ def _set_sdk_headers(sdk=sdk)
49
+ sdk.headers('X-Intercom-Subject' => @_subject_data) if sdk
50
+ end
51
+
52
+ def _process_response(response)
53
+ self._subject_data = response.headers['X-Intercom-Subject']
54
+ @_data = _retrieve_data_from_response(response)
55
+
56
+ response.retval
57
+ end
58
+
59
+ def _retrieve_data_from_response(response)
60
+ encoded_data = response.headers['X-Intercom-Package-Data']
61
+ encoded_data && Marshal.load(Base64.strict_decode64(encoded_data))
62
+ end
63
+ end # Package
64
+ end # Ribbon::Intercom
@@ -0,0 +1,35 @@
1
+ require 'set'
2
+
3
+ module Ribbon::Intercom
4
+ class Packageable
5
+ module Mixin
6
+ class << self
7
+ def included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ def package_with(*args)
14
+ args.map { |m| _package_with_methods << m.to_sym }
15
+ end
16
+
17
+ def _package_with_methods
18
+ @__package_with_methods ||= [].to_set
19
+ end
20
+ end # ClassMethods
21
+
22
+ ##
23
+ # Returns the package data for the instance as a hash.
24
+ def package_data
25
+ Utils.sanitize(
26
+ self.class._package_with_methods.map { |meth| [meth, public_send(meth)] }.to_h
27
+ )
28
+ end
29
+
30
+ def encoded_package_data
31
+ Base64.strict_encode64(Marshal.dump(package_data))
32
+ end
33
+ end # Mixin
34
+ end # Service::Subject
35
+ end # Ribbon::Intercom
@@ -0,0 +1,6 @@
1
+ module Ribbon::Intercom
2
+ class Packageable
3
+ autoload(:Mixin, 'ribbon/intercom/packageable/mixin')
4
+ include Mixin
5
+ end # Packageable
6
+ end # Ribbon::Intercom
@@ -0,0 +1,40 @@
1
+ module Ribbon::Intercom
2
+ class Service
3
+ module Channel::Stores
4
+ class MockStore < Store
5
+ def channels
6
+ @__channels ||= {}
7
+ end
8
+
9
+ def lock
10
+ @__lock ||= Mutex.new
11
+ end
12
+
13
+ def token_exists?(token)
14
+ channels.key?(token)
15
+ end
16
+
17
+ def lookup_channel(token)
18
+ channels[token]
19
+ end
20
+
21
+ def persist(channel)
22
+ raise Errors::InvalidChannelError, channel.inspect unless channel.is_a?(Channel)
23
+ channels[channel.token] = channel
24
+ end
25
+
26
+ def delete(channel)
27
+ raise Errors::InvalidChannelError, channel.inspect unless channel.is_a?(Channel)
28
+ channels.delete(channel.token)
29
+ nil
30
+ end
31
+
32
+ def with_lock(channel, &block)
33
+ # This is a global lock, not a per-channel lock, but this store is only
34
+ # for testing so let's KISS.
35
+ lock.synchronize(&block)
36
+ end
37
+ end # RedisStore
38
+ end # Channel::Stores
39
+ end # Service
40
+ end # Ribbon::Intercom