xconn 0.1.0

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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +29 -0
  4. data/CHANGELOG.md +5 -0
  5. data/LICENSE +22 -0
  6. data/Makefile +9 -0
  7. data/README.md +2 -0
  8. data/Rakefile +14 -0
  9. data/bin/xconn +79 -0
  10. data/docs/index.md +7 -0
  11. data/docs/installation.md +11 -0
  12. data/example/sample/example.rb +23 -0
  13. data/example/sample/included_app.rb +12 -0
  14. data/lib/tasks/tasks.rake +24 -0
  15. data/lib/wamp/app.rb +39 -0
  16. data/lib/wamp/connection/session.rb +35 -0
  17. data/lib/wamp/connection/stream.rb +68 -0
  18. data/lib/wamp/connection/websocket_client.rb +137 -0
  19. data/lib/wamp/connection/websocket_connection.rb +52 -0
  20. data/lib/wamp/manager/base.rb +41 -0
  21. data/lib/wamp/manager/connection.rb +32 -0
  22. data/lib/wamp/manager/event/abort.rb +21 -0
  23. data/lib/wamp/manager/event/authenticate.rb +14 -0
  24. data/lib/wamp/manager/event/base.rb +41 -0
  25. data/lib/wamp/manager/event/call.rb +40 -0
  26. data/lib/wamp/manager/event/challenge.rb +26 -0
  27. data/lib/wamp/manager/event/error.rb +30 -0
  28. data/lib/wamp/manager/event/event.rb +20 -0
  29. data/lib/wamp/manager/event/goodbye.rb +18 -0
  30. data/lib/wamp/manager/event/hello.rb +38 -0
  31. data/lib/wamp/manager/event/invocation.rb +24 -0
  32. data/lib/wamp/manager/event/publish.rb +22 -0
  33. data/lib/wamp/manager/event/published.rb +13 -0
  34. data/lib/wamp/manager/event/register.rb +30 -0
  35. data/lib/wamp/manager/event/registered.rb +37 -0
  36. data/lib/wamp/manager/event/result.rb +13 -0
  37. data/lib/wamp/manager/event/subscribe.rb +39 -0
  38. data/lib/wamp/manager/event/subscribed.rb +26 -0
  39. data/lib/wamp/manager/event/unregister.rb +19 -0
  40. data/lib/wamp/manager/event/unregistered.rb +13 -0
  41. data/lib/wamp/manager/event/unsubscribe.rb +29 -0
  42. data/lib/wamp/manager/event/unsubscribed.rb +13 -0
  43. data/lib/wamp/manager/event/welcome.rb +21 -0
  44. data/lib/wamp/manager/event/yield.rb +13 -0
  45. data/lib/wamp/manager/event.rb +60 -0
  46. data/lib/wamp/manager/hello_event.rb +263 -0
  47. data/lib/wamp/manager/session.rb +91 -0
  48. data/lib/wamp/manager/subscription.rb +38 -0
  49. data/lib/wamp/manager.rb +12 -0
  50. data/lib/wamp/message_handler/api.rb +67 -0
  51. data/lib/wamp/message_handler/base.rb +65 -0
  52. data/lib/wamp/message_handler/call.rb +14 -0
  53. data/lib/wamp/message_handler/challenge.rb +12 -0
  54. data/lib/wamp/message_handler/error.rb +18 -0
  55. data/lib/wamp/message_handler/event.rb +18 -0
  56. data/lib/wamp/message_handler/goodbye.rb +19 -0
  57. data/lib/wamp/message_handler/hello.rb +18 -0
  58. data/lib/wamp/message_handler/invocation.rb +35 -0
  59. data/lib/wamp/message_handler/publish.rb +14 -0
  60. data/lib/wamp/message_handler/published.rb +18 -0
  61. data/lib/wamp/message_handler/register.rb +14 -0
  62. data/lib/wamp/message_handler/registered.rb +30 -0
  63. data/lib/wamp/message_handler/result.rb +17 -0
  64. data/lib/wamp/message_handler/subscribe.rb +14 -0
  65. data/lib/wamp/message_handler/subscribed.rb +30 -0
  66. data/lib/wamp/message_handler/unregister.rb +14 -0
  67. data/lib/wamp/message_handler/unregistered.rb +32 -0
  68. data/lib/wamp/message_handler/unsubscribe.rb +14 -0
  69. data/lib/wamp/message_handler/unsubscribed.rb +33 -0
  70. data/lib/wamp/message_handler/welcome.rb +12 -0
  71. data/lib/wamp/message_handler.rb +75 -0
  72. data/lib/wamp/router/base.rb +45 -0
  73. data/lib/wamp/router/client.rb +55 -0
  74. data/lib/wamp/router/connection.rb +150 -0
  75. data/lib/wamp/router/realm.rb +92 -0
  76. data/lib/wamp/router/server.rb +83 -0
  77. data/lib/wamp/router.rb +12 -0
  78. data/lib/wamp/serializer/cbor.rb +18 -0
  79. data/lib/wamp/serializer/json.rb +18 -0
  80. data/lib/wamp/serializer/message_pack.rb +18 -0
  81. data/lib/wamp/serializer.rb +5 -0
  82. data/lib/wamp/type/error.rb +24 -0
  83. data/lib/wamp/type/event.rb +16 -0
  84. data/lib/wamp/type/invocation.rb +16 -0
  85. data/lib/wamp/type/publication.rb +14 -0
  86. data/lib/wamp/type/registration.rb +14 -0
  87. data/lib/wamp/type/result.rb +16 -0
  88. data/lib/wamp/type/subscription.rb +14 -0
  89. data/lib/wamp/type/success.rb +8 -0
  90. data/lib/wamp/type.rb +16 -0
  91. data/lib/wamp/version.rb +5 -0
  92. data/lib/wamp.rb +15 -0
  93. data/mkdocs.yml +67 -0
  94. data/sig/wamp/serializer/json.rbs +10 -0
  95. data/sig/wamp.rbs +11 -0
  96. data/wamp.gemspec +40 -0
  97. metadata +223 -0
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # Published confirmation message
6
+ class Published < Base
7
+ def handle
8
+ validate_received_message
9
+
10
+ deliver_response(response)
11
+ end
12
+
13
+ def response
14
+ Type::Publication.new(publication_id: message.publication_id)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # publish event to subscriber
6
+ class Register < Base
7
+ def send_message(handler, &callback)
8
+ store[store_key] = { handler: handler, callback: callback, procedure: message.procedure }
9
+
10
+ send_serialized message
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # Registered callback
6
+ class Registered < Base
7
+ def handle
8
+ validate_received_message
9
+
10
+ store[alt_store_key] = { handler: stored_data.fetch(:handler), procedure: stored_data.fetch(:procedure) }
11
+ store_procedure
12
+
13
+ deliver_response(response)
14
+ end
15
+
16
+ def response
17
+ Type::Registration.new(registration_id: message.registration_id)
18
+ end
19
+
20
+ def alt_store_key
21
+ "registration_#{message.registration_id}"
22
+ end
23
+
24
+ def store_procedure
25
+ procedure = stored_data.fetch(:procedure)
26
+ store[procedure] = message.registration_id
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # Result
6
+ class Result < Base
7
+ def handle
8
+ validate_received_message
9
+ stored_data.fetch(:handler).call(response)
10
+ end
11
+
12
+ def response
13
+ Type::Result.new(args: message.args, kwargs: message.kwargs, details: message.details)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # Request subscription
6
+ class Subscribe < Base
7
+ def send_message(handler, &callback)
8
+ store[store_key] = { handler: handler, callback: callback, topic: message.topic }
9
+
10
+ send_serialized message
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # Receive subscribed
6
+ class Subscribed < Base
7
+ def handle
8
+ validate_received_message
9
+
10
+ store[alt_store_key] = { handler: stored_data.fetch(:handler), topic: stored_data.fetch(:topic) }
11
+ store_topic
12
+
13
+ deliver_response(response)
14
+ end
15
+
16
+ def response
17
+ Type::Subscription.new(subscription_id: message.subscription_id)
18
+ end
19
+
20
+ def alt_store_key
21
+ "subscription_#{message.subscription_id}"
22
+ end
23
+
24
+ def store_topic
25
+ topic = stored_data.fetch(:topic)
26
+ store[topic] = message.subscription_id
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # send unregister message
6
+ class Unregister < Base
7
+ def send_message(&callback)
8
+ store[store_key] = { callback: callback, registration_id: message.registration_id }
9
+
10
+ send_serialized message
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # callback for unregister message
6
+ class Unregistered < Base
7
+ def handle
8
+ validate_received_message
9
+
10
+ delete_procedure store.delete(alt_store_key)
11
+
12
+ deliver_response(response)
13
+ end
14
+
15
+ def response
16
+ Type::Success.new
17
+ end
18
+
19
+ def alt_store_key
20
+ "registration_#{registration_id}"
21
+ end
22
+
23
+ def delete_procedure(data)
24
+ store.delete data.fetch(:procedure)
25
+ end
26
+
27
+ def registration_id
28
+ stored_data.fetch(:registration_id)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # Request subscription
6
+ class Unsubscribe < Base
7
+ def send_message(&callback)
8
+ store[store_key] = { callback: callback, subscription_id: message.subscription_id }
9
+
10
+ send_serialized message
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # Receive unsubscribed
6
+ class Unsubscribed < Base
7
+ def handle
8
+ validate_received_message
9
+ delete_topic store.delete(alt_store_key)
10
+
11
+ deliver_response(response)
12
+ end
13
+
14
+ def response
15
+ Type::Success.new
16
+ end
17
+
18
+ private
19
+
20
+ def alt_store_key
21
+ "subscription_#{subscription_id}"
22
+ end
23
+
24
+ def delete_topic(data)
25
+ store.delete data.fetch(:topic)
26
+ end
27
+
28
+ def subscription_id
29
+ stored_data.fetch(:subscription_id)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module MessageHandler
5
+ # Welcome
6
+ class Welcome < Base
7
+ def handle
8
+ connection.executor&.call(connection.api)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "message_handler/base"
4
+
5
+ require_relative "message_handler/hello"
6
+ require_relative "message_handler/welcome"
7
+ require_relative "message_handler/challenge"
8
+ require_relative "message_handler/goodbye"
9
+
10
+ require_relative "message_handler/subscribe"
11
+ require_relative "message_handler/subscribed"
12
+ require_relative "message_handler/unsubscribe"
13
+ require_relative "message_handler/unsubscribed"
14
+
15
+ require_relative "message_handler/publish"
16
+ require_relative "message_handler/published"
17
+ require_relative "message_handler/event"
18
+
19
+ require_relative "message_handler/call"
20
+ require_relative "message_handler/result"
21
+
22
+ require_relative "message_handler/register"
23
+ require_relative "message_handler/registered"
24
+ require_relative "message_handler/unregister"
25
+ require_relative "message_handler/unregistered"
26
+
27
+ require_relative "message_handler/invocation"
28
+
29
+ require_relative "message_handler/error"
30
+
31
+ require_relative "message_handler/api"
32
+
33
+ module Wamp
34
+ # routes messages
35
+ module MessageHandler
36
+ # instantiate correct handler
37
+ module ClassMethods
38
+ def resolve(data, connection)
39
+ # return handle_when_not_joined(data, connection) unless connection.joiner.joined?
40
+
41
+ message = connection.joiner.serializer.deserialize(data)
42
+ klass_name = demodulize(message.class.name)
43
+ klass = constantize("Wamp::MessageHandler::#{klass_name}")
44
+ klass.new(message, connection)
45
+ end
46
+
47
+ def handle_when_not_joined(data, connection)
48
+ authenticate = connection.joiner.receive(data) # maybe welcome message then state should be joined
49
+ connection.transmit authenticate unless connection.joiner.joined?
50
+ connection.executor.call(connection.api) if connection.joiner.joined?
51
+ Struct.new(:handle).new
52
+ end
53
+
54
+ def from(message, connection)
55
+ klass_name = demodulize(message.class.name)
56
+ klass = constantize("Wamp::MessageHandler::#{klass_name}")
57
+ klass.new(message, connection)
58
+ end
59
+
60
+ def demodulize(path)
61
+ path = path.to_s
62
+ if i = path.rindex("::") # rubocop:disable Lint/AssignmentInCondition
63
+ path[(i + 2), path.length]
64
+ else
65
+ path
66
+ end
67
+ end
68
+
69
+ def constantize(camel_cased_word)
70
+ Object.const_get(camel_cased_word)
71
+ end
72
+ end
73
+ extend ClassMethods
74
+ end
75
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "realm"
4
+
5
+ module Wamp
6
+ module Router
7
+ # Router
8
+ class Base
9
+ attr_reader :realms
10
+
11
+ def initialize
12
+ @realms = {}
13
+ end
14
+
15
+ def add_realm(name)
16
+ realms[name] = Realm.new(name)
17
+ end
18
+
19
+ def remove_realm(name)
20
+ realms.delete(name)
21
+ end
22
+
23
+ def attach_client(client)
24
+ error_message = "cannot attach client to non-existent realm #{client.realm}"
25
+ raise Wampproto::ValueError, error_message unless realms.include?(client.realm)
26
+
27
+ realms[client.realm].attach_client(client)
28
+ end
29
+
30
+ def detach_client(client)
31
+ error_message = "cannot attach client to non-existent realm #{client.realm}"
32
+ raise Wampproto::ValueError, error_message unless realms.include?(client.realm)
33
+
34
+ realms[client.realm].detach_client(client)
35
+ end
36
+
37
+ def receive_message(client, message)
38
+ error_message = "cannot attach client to non-existent realm #{client.realm}"
39
+ raise Wampproto::ValueError, error_message unless realms.include?(client.realm)
40
+
41
+ realms[client.realm].receive_message(client.session_id, message)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "realm"
4
+
5
+ module Wamp
6
+ module Router
7
+ # Auth
8
+ class Authenticator
9
+ def self.authenticate(request)
10
+ Wampproto::Acceptor::Response.new(request.authid, "role", "secret")
11
+ end
12
+ end
13
+
14
+ # Server Session
15
+ class Client
16
+ attr_accessor :router, :connection
17
+ attr_reader :acceptor, :serializer
18
+
19
+ def initialize(serializer = Wampproto::Serializer::JSON, authenticator = Authenticator)
20
+ @serializer = serializer
21
+ @acceptor = Wampproto::Acceptor.new(serializer, authenticator)
22
+ end
23
+
24
+ def realm
25
+ acceptor.session_details&.realm
26
+ end
27
+
28
+ def send_message(message)
29
+ transmit(message)
30
+ end
31
+
32
+ def session_id
33
+ acceptor.session_details&.session_id
34
+ end
35
+
36
+ def transmit(data)
37
+ case data
38
+ when Wampproto::Message::Base
39
+ connection.on_message serializer.serialize(data)
40
+ else
41
+ connection.on_message data
42
+ end
43
+ end
44
+
45
+ def on_message(data)
46
+ unless acceptor.accepted?
47
+ msg, is_welcome = acceptor.receive(data)
48
+ transmit msg
49
+ router.attach_client(self) if is_welcome
50
+ end
51
+ router.receive_message(self, serializer.deserialize(data))
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "websocket/driver"
4
+
5
+ # Testing
6
+ class Authenticator
7
+ def self.authenticate(request)
8
+ Wampproto::Acceptor::Response.new(request.authid, "role")
9
+ end
10
+ end
11
+
12
+ module Wamp
13
+ module Router
14
+ # TOP Level Doc
15
+ class Connection < Client # rubocop:disable Metrics/ClassLength
16
+ include WebSocket::Driver::EventEmitter
17
+ CONNECTING = 0
18
+ OPEN = 1
19
+ CLOSING = 2
20
+ CLOSED = 3
21
+
22
+ attr_reader :socket, :session, :acceptor
23
+
24
+ def initialize(socket, &cleanup)
25
+ super()
26
+ @cleanup = cleanup
27
+ @socket = socket
28
+ @driver = WebSocket::Driver.server(self)
29
+ @driver.on(:open) { on_open(_1) }
30
+ @driver.on(:message) { on_message(_1.data) }
31
+ @driver.on(:close) { |evt| begin_close(evt.reason, evt.code) }
32
+ @driver.on(:connect) { on_connect }
33
+ @ready_state = CONNECTING
34
+ end
35
+
36
+ def on_connect
37
+ @driver.start if WebSocket::Driver.websocket?(@driver.env)
38
+ choose_serializer_from @driver.env["HTTP_SEC_WEBSOCKET_PROTOCOL"]
39
+ @acceptor = Wampproto::Acceptor.new(serializer, Authenticator)
40
+ end
41
+
42
+ def connection
43
+ self
44
+ end
45
+
46
+ def begin_close(reason, code)
47
+ return if @ready_state == CLOSED
48
+
49
+ @ready_state = CLOSING
50
+ @close_params = [reason, code]
51
+
52
+ @cleanup&.call(self)
53
+ finalize_close
54
+ end
55
+
56
+ def finalize_close
57
+ return if @ready_state == CLOSED
58
+
59
+ @ready_state = CLOSED
60
+ @driver.close
61
+ socket.close
62
+ end
63
+
64
+ def listen(&block) # rubocop:disable Metrics/MethodLength
65
+ return unless [CONNECTING, OPEN].include?(@ready_state)
66
+
67
+ begin
68
+ data = socket.read_nonblock(4096, exception: false)
69
+ case data
70
+ when :wait_readable
71
+ # do nothing
72
+ when nil
73
+ block&.call
74
+ @driver.close
75
+ else
76
+ receive_data(data)
77
+ end
78
+ rescue StandardError => e
79
+ puts e.message
80
+ puts e.backtrace
81
+ begin
82
+ block&.call
83
+ @driver.close
84
+ rescue StandardError
85
+ # Errno::ECONNRESET
86
+ puts "Failed to handle: Errno::ECONNRESET"
87
+ end
88
+ end
89
+ end
90
+
91
+ # triggers on_message
92
+ def receive_data(data)
93
+ return unless [OPEN, CONNECTING].include?(@ready_state)
94
+
95
+ @driver.parse(data)
96
+ end
97
+
98
+ # called when @driver.text is invoked
99
+ def write(data)
100
+ socket.write(data)
101
+ end
102
+
103
+ def transmit(message)
104
+ # return false if @ready_state > OPEN
105
+
106
+ case message
107
+ when Wampproto::Message::Base then transmit(serializer.serialize(message))
108
+ when Numeric then @driver.text(message.to_s)
109
+ when String then @driver.text(message)
110
+ when Array then @driver.binary(message)
111
+ else false
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ def on_open(_evt)
118
+ return unless @ready_state == CONNECTING
119
+
120
+ @ready_state = OPEN
121
+ end
122
+
123
+ def on_close(message)
124
+ return if @ready_state == CLOSED
125
+
126
+ @ready_state = CLOSED
127
+ socket.close
128
+ @driver.close(message.code, message.reason)
129
+ end
130
+
131
+ def close(_code, _reason)
132
+ @driver.close
133
+ end
134
+
135
+ attr_reader :serializer
136
+
137
+ def choose_serializer_from(protocols)
138
+ @serializer = if protocols.include?("wamp.2.msgpack")
139
+ Wampproto::Serializer::Msgpack
140
+ elsif protocols.include?("wamp.2.cbor")
141
+ Wampproto::Serializer::Cbor
142
+ elsif protocols.include?("wamp.2.json")
143
+ Wampproto::Serializer::JSON
144
+ else
145
+ close
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wamp
4
+ module Router
5
+ # Realm
6
+ class Realm
7
+ attr_reader :broker, :dealer, :name, :clients
8
+
9
+ DEALER_MESSAGES = [
10
+ Wampproto::Message::Call,
11
+ Wampproto::Message::Yield,
12
+ Wampproto::Message::Register,
13
+ Wampproto::Message::Unregister
14
+ ].freeze
15
+
16
+ BROKER_MESSAGES = [
17
+ Wampproto::Message::Publish,
18
+ Wampproto::Message::Subscribe,
19
+ Wampproto::Message::Unsubscribe
20
+ ].freeze
21
+
22
+ GOODBYE_MESSAGE = Wampproto::Message::Goodbye
23
+
24
+ def initialize(name)
25
+ @name = name
26
+ @broker = Wampproto::Broker.new(id_gen)
27
+ @dealer = Wampproto::Dealer.new(id_gen)
28
+ @clients = {}
29
+ end
30
+
31
+ def attach_client(client)
32
+ session_id = client.session_id
33
+ session_details = client.acceptor.session_details
34
+
35
+ clients[session_id] = client
36
+ broker.add_session(session_details)
37
+ dealer.add_session(session_details)
38
+ end
39
+
40
+ def detach_client(client)
41
+ remove_client(client.session_id)
42
+ end
43
+
44
+ def clear
45
+ clients.each { |client| remove_client(client.session_id) }
46
+ end
47
+
48
+ def receive_message(session_id, message)
49
+ case message
50
+ when *DEALER_MESSAGES then handle_dealer(session_id, message)
51
+ when *BROKER_MESSAGES then handle_broker(session_id, message)
52
+ when GOODBYE_MESSAGE then handle_goodbye(session_id, message)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def handle_dealer(session_id, message)
59
+ send_message dealer.receive_message(session_id, message)
60
+ end
61
+
62
+ def handle_broker(session_id, message)
63
+ send_message broker.receive_message(session_id, message)
64
+ end
65
+
66
+ def handle_goodbye(session_id, _message)
67
+ goodbye = Wampproto::Message::Goodbye.new({}, "wamp.close.goodbye_and_out")
68
+ send_message Wampproto::MessageWithRecipient.new(goodbye, session_id)
69
+ end
70
+
71
+ def send_message(message_with_receipient)
72
+ Array(message_with_receipient).each do |object|
73
+ client = clients[object.recipient]
74
+
75
+ next unless client
76
+
77
+ client.send_message object.message
78
+ end
79
+ end
80
+
81
+ def id_gen
82
+ @id_gen ||= Wampproto::IdGenerator.new
83
+ end
84
+
85
+ def remove_client(session_id)
86
+ broker.remove_session(session_id)
87
+ dealer.remove_session(session_id)
88
+ clients.delete(session_id)
89
+ end
90
+ end
91
+ end
92
+ end