wamp_client 0.0.8 → 0.0.9

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.
@@ -0,0 +1,55 @@
1
+ =begin
2
+
3
+ Copyright (c) 2016 Eric Chapman
4
+
5
+ MIT License
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining
8
+ a copy of this software and associated documentation files (the
9
+ "Software"), to deal in the Software without restriction, including
10
+ without limitation the rights to use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and to
12
+ permit persons to whom the Software is furnished to do so, subject to
13
+ the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ =end
27
+
28
+ require 'eventmachine'
29
+ require_relative 'base'
30
+
31
+ module WampClient
32
+ module Transport
33
+ class EventMachineBase < Base
34
+
35
+ def self.start_event_machine(&block)
36
+ EM.run do
37
+ block.call
38
+ end
39
+ end
40
+
41
+ def self.stop_event_machine
42
+ EM.stop
43
+ end
44
+
45
+ def self.add_timer(milliseconds, &callback)
46
+ delay = (milliseconds.to_f/1000.0).ceil
47
+ EM.add_timer(delay) {
48
+ callback.call
49
+ }
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,83 @@
1
+ =begin
2
+
3
+ Copyright (c) 2016 Eric Chapman
4
+
5
+ MIT License
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining
8
+ a copy of this software and associated documentation files (the
9
+ "Software"), to deal in the Software without restriction, including
10
+ without limitation the rights to use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and to
12
+ permit persons to whom the Software is furnished to do so, subject to
13
+ the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ =end
27
+
28
+ require_relative 'event_machine_base'
29
+
30
+ # This implementation uses the 'faye-websocket' Gem.
31
+ module WampClient
32
+ module Transport
33
+ class FayeWebSocket < EventMachineBase
34
+ attr_accessor :socket
35
+
36
+ def initialize(options)
37
+ super(options)
38
+ self.socket = nil
39
+
40
+ # Only make them include the gem if they are going to use it
41
+ require 'faye/websocket'
42
+ end
43
+
44
+ def connect
45
+ options = { :headers => self.headers }
46
+ options[:proxy] = self.proxy if self.proxy != nil
47
+ self.socket = Faye::WebSocket::Client.new(self.uri, [self.protocol], options)
48
+
49
+ self.socket.on(:open) do |event|
50
+ self.connected = true
51
+ @on_open.call if @on_open
52
+ end
53
+
54
+ self.socket.on(:message) do |event|
55
+ @on_message.call(self.serializer.deserialize(event.data)) if @on_message
56
+ end
57
+
58
+ self.socket.on(:close) do |event|
59
+ self.connected = false
60
+ @on_close.call(event.reason) if @on_close
61
+ end
62
+
63
+ self.socket.on(:error) do |event|
64
+ @on_error.call(event.message) if @on_error
65
+ end
66
+ end
67
+
68
+ def disconnect
69
+ self.socket.close
70
+ self.connected = false
71
+ end
72
+
73
+ def send_message(msg)
74
+ if self.connected
75
+ self.socket.send(self.serializer.serialize(msg))
76
+ else
77
+ raise RuntimeError, "Socket must be open to call 'send_message'"
78
+ end
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,86 @@
1
+ =begin
2
+
3
+ Copyright (c) 2016 Eric Chapman
4
+
5
+ MIT License
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining
8
+ a copy of this software and associated documentation files (the
9
+ "Software"), to deal in the Software without restriction, including
10
+ without limitation the rights to use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and to
12
+ permit persons to whom the Software is furnished to do so, subject to
13
+ the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ =end
27
+
28
+ require_relative 'event_machine_base'
29
+
30
+ # This implementation uses the 'websocket-eventmachine-client' Gem.
31
+ # This is the default if no transport is included
32
+ module WampClient
33
+ module Transport
34
+ class WebSocketEventMachine < EventMachineBase
35
+ attr_accessor :socket
36
+
37
+ def initialize(options)
38
+ super(options)
39
+ self.socket = nil
40
+
41
+ # Only make them include the gem if they are going to use it
42
+ require 'websocket-eventmachine-client'
43
+
44
+ # Raise an exception if proxy was included (not supported)
45
+ if self.proxy != nil
46
+ raise RuntimeError, "The WebSocketEventMachine transport does not support 'proxy'. Try using 'faye-websocket' transport instead"
47
+ end
48
+ end
49
+
50
+ def connect
51
+ self.socket = WebSocket::EventMachine::Client.connect(
52
+ :uri => self.uri,
53
+ :headers => self.headers
54
+ )
55
+
56
+ self.socket.onopen do
57
+ self.connected = true
58
+ @on_open.call if @on_open
59
+ end
60
+
61
+ self.socket.onmessage do |msg, type|
62
+ @on_message.call(self.serializer.deserialize(msg)) if @on_message
63
+ end
64
+
65
+ self.socket.onclose do |code, reason|
66
+ self.connected = false
67
+ @on_close.call(reason) if @on_close
68
+ end
69
+ end
70
+
71
+ def disconnect
72
+ self.connected = !self.socket.close # close returns 'true' if the connection was closed immediately
73
+ end
74
+
75
+ def send_message(msg)
76
+ if self.connected
77
+ self.socket.send(self.serializer.serialize(msg), {type: 'text'})
78
+ else
79
+ raise RuntimeError, "Socket must be open to call 'send_message'"
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+
@@ -26,5 +26,5 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
26
  =end
27
27
 
28
28
  module WampClient
29
- VERSION = '0.0.8'
29
+ VERSION = '0.0.9'
30
30
  end
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+
3
+ describe WampClient::Connection do
4
+ include RSpec::EM::FakeClock
5
+
6
+ before { clock.stub }
7
+ after { clock.reset }
8
+
9
+ before(:each) { SpecHelper::TestTransport.stop_event_machine }
10
+
11
+ let(:options) {
12
+ {
13
+ uri: 'wss://example.com',
14
+ realm: 'realm1',
15
+ transport: SpecHelper::TestTransport,
16
+ }
17
+ }
18
+ let(:connection) { described_class.new(options) }
19
+ let(:transport) { connection.transport }
20
+ let(:session) { connection.session }
21
+
22
+ def open_connection
23
+ connection.open
24
+ clock.tick(1)
25
+ end
26
+
27
+ def open_session_from_server
28
+ # Send welcome form server
29
+ welcome = WampClient::Message::Welcome.new(1234, {})
30
+ transport.receive_message(welcome.payload)
31
+ end
32
+
33
+ def close_session_from_server
34
+ # Send goodbye from server
35
+ goodbye = WampClient::Message::Goodbye.new({}, 'felt.like.it')
36
+ transport.receive_message(goodbye.payload)
37
+ end
38
+
39
+ def check_em_on
40
+ expect(SpecHelper::TestTransport.event_machine_on?).to eq(true)
41
+ end
42
+
43
+ def check_em_off
44
+ expect(SpecHelper::TestTransport.event_machine_on?).to eq(false)
45
+ end
46
+
47
+ describe 'transport' do
48
+ it 'selects the default transport' do
49
+ connection = described_class.new({})
50
+ expect(connection.transport_class).to be(WampClient::Transport::WebSocketEventMachine)
51
+ end
52
+
53
+ it 'overrides the default transport' do
54
+ connection = described_class.new({ transport: WampClient::Transport::FayeWebSocket })
55
+ expect(connection.transport_class).to be(WampClient::Transport::FayeWebSocket)
56
+ end
57
+ end
58
+
59
+ it 'opens the transport/session and sends the hello message' do
60
+ called = false
61
+ connection.on(:connect) do
62
+ called = true
63
+ end
64
+
65
+ open_connection
66
+
67
+ expect(transport).not_to be_nil
68
+ expect(session).not_to be_nil
69
+ expect(transport.messages.count).to eq(1)
70
+ expect(transport.messages[0][0]).to eq(WampClient::Message::Types::HELLO)
71
+
72
+ expect(called).to eq(true)
73
+ end
74
+
75
+ it 'opens the transport/session and joins' do
76
+ called = false
77
+ connection.on(:join) do
78
+ called = true
79
+ end
80
+
81
+ open_connection
82
+ open_session_from_server
83
+
84
+ check_em_on
85
+ expect(called).to eq(true)
86
+ end
87
+
88
+ it 'closes the connection' do
89
+ left = false
90
+ connection.on(:leave) do
91
+ left = true
92
+ end
93
+ disconnected = false
94
+ connection.on(:disconnect) do
95
+ disconnected = true
96
+ end
97
+
98
+ open_connection
99
+ open_session_from_server
100
+
101
+ connection.close
102
+
103
+ # Nothing happens until the server responds
104
+ check_em_on
105
+ expect(left).to eq(false)
106
+ expect(disconnected).to eq(false)
107
+
108
+ close_session_from_server
109
+
110
+ check_em_off
111
+ expect(left).to eq(true)
112
+ expect(disconnected).to eq(true)
113
+ end
114
+
115
+ it 'retries if the session is closed from the server' do
116
+ left = false
117
+ connection.on(:leave) do
118
+ left = true
119
+ end
120
+
121
+ joined = false
122
+ connection.on(:join) do
123
+ joined = true
124
+ end
125
+
126
+ open_connection
127
+ open_session_from_server
128
+
129
+ check_em_on
130
+ expect(joined).to eq(true)
131
+ joined = false
132
+ expect(left).to eq(false)
133
+
134
+ close_session_from_server
135
+
136
+ check_em_on
137
+ expect(joined).to eq(false)
138
+ expect(left).to eq(true)
139
+ left = false
140
+
141
+ clock.tick(5)
142
+ open_session_from_server
143
+
144
+ check_em_on
145
+
146
+ expect(joined).to eq(true)
147
+ joined = false
148
+ expect(left).to eq(false)
149
+ end
150
+ end
data/spec/session_spec.rb CHANGED
@@ -1115,6 +1115,11 @@ describe WampClient::Session do
1115
1115
  end
1116
1116
 
1117
1117
  context 'timeout' do
1118
+ include RSpec::EM::FakeClock
1119
+
1120
+ before { clock.stub }
1121
+ after { clock.reset }
1122
+
1118
1123
  it 'does not cancel a call if no timeout specified' do
1119
1124
  @defer = WampClient::Defer::ProgressiveCallDefer.new
1120
1125
 
@@ -1123,7 +1128,7 @@ describe WampClient::Session do
1123
1128
  count += 1
1124
1129
  end
1125
1130
 
1126
- expect(transport.timer_callback).to be_nil
1131
+ clock.tick(2)
1127
1132
  expect(transport.messages.count).to eq(1)
1128
1133
  end
1129
1134
 
@@ -1135,8 +1140,7 @@ describe WampClient::Session do
1135
1140
  count += 1
1136
1141
  end
1137
1142
 
1138
- expect(transport.timer_callback).not_to be_nil
1139
- transport.timer_callback.call
1143
+ clock.tick(2)
1140
1144
 
1141
1145
  expect(transport.messages.count).to eq(2)
1142
1146
 
data/spec/spec_helper.rb CHANGED
@@ -9,12 +9,13 @@ if ENV['CODECOV_TOKEN']
9
9
  end
10
10
 
11
11
  require 'wamp_client'
12
+ require "rspec/em"
12
13
 
13
14
  module SpecHelper
14
15
 
15
- class TestTransport < WampClient::Transport::Base
16
-
17
- attr_accessor :messages, :timer_callback
16
+ class TestTransport < WampClient::Transport::EventMachineBase
17
+ @@event_machine_on = false
18
+ attr_accessor :messages
18
19
 
19
20
  def initialize(options)
20
21
  super(options)
@@ -23,7 +24,27 @@ module SpecHelper
23
24
  end
24
25
 
25
26
  def connect
27
+ self.add_timer(1000) do
28
+ @on_open.call if @on_open
29
+ end
30
+ end
31
+
32
+ def disconnect
33
+ @connected = false
34
+ @on_close.call if @on_close
35
+ end
36
+
37
+ def self.start_event_machine(&block)
38
+ @@event_machine_on = true
39
+ block.call
40
+ end
41
+
42
+ def self.stop_event_machine
43
+ @@event_machine_on = false
44
+ end
26
45
 
46
+ def self.event_machine_on?
47
+ @@event_machine_on
27
48
  end
28
49
 
29
50
  def send_message(msg)
@@ -37,13 +58,91 @@ module SpecHelper
37
58
  deserialize = self.serializer.deserialize(serialize)
38
59
 
39
60
  # Call the received message
40
- @on_message.call(deserialize) unless @on_message.nil?
61
+ @on_message.call(deserialize) if @on_message
62
+ end
63
+
64
+ end
65
+
66
+ class WebSocketEventMachineClientStub
67
+ attr_accessor :last_message
68
+
69
+ def initialize
70
+ EM.add_timer(1) {
71
+ @onopen.call if @onopen != nil
72
+ }
73
+ end
74
+
75
+ @onopen
76
+ def onopen(&onopen)
77
+ @onopen = onopen
78
+ end
79
+
80
+ @onmessage
81
+ def onmessage(&onmessage)
82
+ @onmessage = onmessage
83
+ end
84
+
85
+ @onclose
86
+ def onclose(&onclose)
87
+ @onclose = onclose
41
88
  end
42
89
 
43
- def timer(milliseconds, &callback)
44
- self.timer_callback = callback
90
+ def close
91
+ @onclose.call if @onclose != nil
92
+ true
93
+ end
94
+
95
+ def send(message, type)
96
+ self.last_message = message
97
+ end
98
+
99
+ def receive(message)
100
+ @onmessage.call(message, {type:'text'}) if @onmessage != nil
45
101
  end
46
102
 
47
103
  end
48
104
 
105
+ class FayeWebSocketClientStub
106
+ class Event
107
+ attr_accessor :data, :reason
108
+ end
109
+
110
+ attr_accessor :last_message
111
+
112
+ def initialize
113
+ EM.add_timer(1) {
114
+ @on_open.call(Event.new) if @on_open != nil
115
+ }
116
+ end
117
+
118
+ @on_open
119
+ @on_message
120
+ @on_close
121
+ def on(event, &block)
122
+ if event == :open
123
+ @on_open = block
124
+ elsif event == :close
125
+ @on_close = block
126
+ elsif event == :message
127
+ @on_message = block
128
+ end
129
+ end
130
+
131
+ def close
132
+ event = Event.new
133
+ event.reason = 'closed'
134
+ @on_close.call(event) if @on_close != nil
135
+ end
136
+
137
+ def send(message)
138
+ self.last_message = message
139
+ end
140
+
141
+ def receive(message)
142
+ event = Event.new
143
+ event.data = message
144
+ @on_message.call(event) if @on_message != nil
145
+ end
146
+
147
+ end
49
148
  end