action_cable_client 1.3.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 977e65342bdaa2a92cb204a207032d2da9b5a120
4
- data.tar.gz: 079643bcac126fcc798ff4a2b0ec26fd59d5fe35
3
+ metadata.gz: f4efe4e0d3cbf2308ee5deebf64db87704a4518c
4
+ data.tar.gz: f72fa641ad54554816874825eb0f924eaa033cef
5
5
  SHA512:
6
- metadata.gz: 23371f7113817938517a3c26c6dcb58cf71a37e14e3f511856f6cfd1c867cf9b13eb650ee27fd975b19ed2f6b90a73fd25bd3cb288b70f3b7e6f9cb982575de9
7
- data.tar.gz: a183f2bad40d90a8a7db310037ef9aa3784f188f7c9e0fb4a58cb11f07b56820758a883a008a3565446566284f647212cfd2146249f08bbe2d14e35b43151543
6
+ metadata.gz: a8ccddc722216d3ac5533734f4ac42e6541d74eb4c7c668ac0774f702674d813057cd39679a1ba0e11b14a7baa7f185a213f0c3a171b889f29ae8384b5567f62
7
+ data.tar.gz: 6fe25aeb39115aebed3e2caaa76b796e6ec766af521fd323e98cf770168de83a5edf1219e3ca0868fe1590c69b4be49ddff620b1a54bd09c0a6f5cc9b9e7a3d4
@@ -1,26 +1,41 @@
1
+ ## 2.0 - Unreleased
2
+
3
+ **General**
4
+
5
+ * [#18](https://github.com/NullVoxPopuli/action_cable_client/pull/18) Added the ability to reconnect (@NullVoxPopuli)
6
+ * [#19](https://github.com/NullVoxPopuli/action_cable_client/pull/19) Allow for additional params via the identifier (@mcary, @NullVoxPopuli)
7
+ * Support ruby-2.4.x
8
+ * [#20](https://github.com/NullVoxPopuli/action_cable_client/pull/20) Change underlying websocket gem to [websocket-eventmachine-client](https://github.com/imanel/websocket-eventmachine-client)
9
+ * enables SSL
10
+ * allows header usage on handshake
11
+
12
+ **Breaking**
13
+ * [#19](https://github.com/NullVoxPopuli/action_cable_client/pull/19) Removed queued_send in initializer - this allows for a action_cable_client to be simpler, and stay an true to real-time communication as possible -- also it wasn't being used. (@NullVoxPopuli)
14
+ * Drop Support for ruby-2.2.x
15
+
1
16
  ## 1.3.4
2
17
  * [#7](https://github.com/NullVoxPopuli/action_cable_client/pull/7) Avoid crashing on empty JSON data (@MikeAski)
3
18
 
4
19
  ## 1.3.2
5
- * Getting disconnected from the server will now set the result of subscribed? to false
20
+ * Getting disconnected from the server will now set the result of subscribed? to false (@NullVoxPopuli)
6
21
 
7
22
  ## 1.3.0
8
- * subscribed now is a callback instead of a boolean
9
- * subscribed? tells whether or not the client is subscribed to the channel
10
- * added subscribed callback which signifies when the client can start sending messages on the channel
23
+ * subscribed now is a callback instead of a boolean (@NullVoxPopuli)
24
+ * subscribed? tells whether or not the client is subscribed to the channel (@NullVoxPopuli)
25
+ * added subscribed callback which signifies when the client can start sending messages on the channel (@NullVoxPopuli)
11
26
 
12
27
  ## 1.2.4
13
28
  * [#3](https://github.com/NullVoxPopuli/action_cable_client/pull/3) Support Ruby 2.2.2 (@NullVoxPopuli)
14
29
 
15
30
  ## 1.2.3
16
- * The ping message received from the action cable server changed from being identity: _ping to type: ping
17
- * Fixed an issue where subscribing sometimes didn't work.
31
+ * The ping message received from the action cable server changed from being identity: \_ping to type: ping (@NullVoxPopuli)
32
+ * Fixed an issue where subscribing sometimes didn't work. (@NullVoxPopuli)
18
33
 
19
34
  ## 1.2.0
20
- * Made the handling of received messages not all happen in one method. This allows for easier overriding of what is yielded, in case someone wants to also yield the URL for example.
35
+ * Made the handling of received messages not all happen in one method. This allows for easier overriding of what is yielded, in case someone wants to also yield the URL for example. (@NullVoxPopuli)
21
36
 
22
37
  ## 1.1.0
23
- * Made message queuing optional, off by default. This allows for near-instant message sending
38
+ * Made message queuing optional, off by default. This allows for near-instant message sending (@NullVoxPopuli)
24
39
 
25
40
  ## 1.0
26
- * Initial Work
41
+ * Initial Work (@NullVoxPopuli)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 L. Preston Sego III
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -46,6 +46,45 @@ The available hooks to tie in to are:
46
46
  - `errored { |msg| }`
47
47
  - `received { |msg }`
48
48
 
49
+
50
+ #### Connecting on initialization is also configurable.
51
+
52
+ ```ruby
53
+ client = ActionCableClient.new(uri, 'RoomChannel', connect_on_start: false)
54
+ client.connect!
55
+ ```
56
+
57
+ this way if you also enable ping receiving via
58
+ ```ruby
59
+ client.received(false) do |json|
60
+ # now pings will be here as well, because skip_pings is set to false
61
+ end
62
+ ```
63
+
64
+ you could track the time since you last received a ping, if you haven't received one in a while, it could be that your client is disconnected.
65
+
66
+ To reconnect,
67
+
68
+ ```ruby
69
+ client.connect!
70
+ ```
71
+
72
+ #### Sending additional params
73
+
74
+ ```ruby
75
+ params = { channel: 'RoomChannel', favorite_color: 'blue' }
76
+ client = ActionCableClient.new(uri, params)
77
+ ```
78
+
79
+ then on the server end, in your Channel, `params` will give you:
80
+ ```
81
+ {
82
+ "channel" => "RoomChannel",
83
+ "favorite_color" => "blue"
84
+ }
85
+ ```
86
+
87
+
49
88
  ## Demo
50
89
 
51
90
  [![Live Demo](http://img.youtube.com/vi/x9D1wWsVHMY/mqdefault.jpg)](http://www.youtube.com/watch?v=x9D1wWsVHMY&hd=1)
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # required gems
3
- require 'em-websocket-client'
4
+ require 'websocket-eventmachine-client'
4
5
  require 'forwardable'
5
6
  require 'active_support/core_ext/string'
6
7
  require 'json'
7
8
 
8
9
  # local files
10
+ require 'action_cable_client/errors'
9
11
  require 'action_cable_client/message_factory'
10
12
  require 'action_cable_client/message'
11
13
 
@@ -17,44 +19,52 @@ class ActionCableClient
17
19
  MESSAGE = 'message'
18
20
  end
19
21
 
20
- attr_reader :_websocket_client, :_uri, :_channel_name, :_queued_send
22
+ attr_reader :_websocket_client, :_uri
21
23
  attr_reader :_message_factory
22
24
  # The queue should store entries in the format:
23
25
  # [ action, data ]
24
26
  attr_accessor :message_queue, :_subscribed, :_subscribed_callaback
25
27
 
26
- def_delegator :_websocket_client, :errback, :errored
27
- def_delegator :_websocket_client, :send_msg, :send_msg
28
+ def_delegator :_websocket_client, :onerror, :errored
29
+ def_delegator :_websocket_client, :send, :send_msg
28
30
 
29
31
  # @param [String] uri - e.g.: ws://domain:port
30
- # @param [String] channel - the name of the channel on the Rails server
32
+ # @param [String] params - the name of the channel on the Rails server
33
+ # or params. This gets sent with every request.
31
34
  # e.g.: RoomChannel
32
- # @param [Boolean] queued_send - optionally send messages after a ping
33
- # is received, rather than instantly
34
- def initialize(uri, channel = '', queued_send = false)
35
- @_channel_name = channel
35
+ # @param [Boolean] connect_on_start - connects on init when true
36
+ # - otherwise manually call `connect!`
37
+ # @param [Hash] headers - HTTP headers to use in the handshake
38
+ def initialize(uri, params = '', connect_on_start = true, headers = {})
36
39
  @_uri = uri
37
- @_queued_send = queued_send
38
40
  @message_queue = []
39
41
  @_subscribed = false
40
42
 
41
- @_message_factory = MessageFactory.new(channel)
42
- # NOTE:
43
- # EventMachine::WebSocketClient
44
- # https://github.com/mwylde/em-websocket-client/blob/master/lib/em-websocket-client.rb
45
- # is a subclass of
46
- # https://github.com/eventmachine/eventmachine/blob/master/lib/em/connection.rb
47
- @_websocket_client = EventMachine::WebSocketClient.connect(_uri)
43
+ @_message_factory = MessageFactory.new(params)
44
+
45
+ connect!(headers) if connect_on_start
46
+ end
47
+
48
+ def connect!(headers = {})
49
+ # Quick Reference for WebSocket::EM::Client's api
50
+ # - onopen - called after successfully connecting
51
+ # - onclose - called after closing connection
52
+ # - onmessage - called when client recives a message. on `message do |msg, type (text or binary)|``
53
+ # - also called when a ping is received
54
+ # - onerror - called when client encounters an error
55
+ # - onping - called when client receives a ping from the server
56
+ # - onpong - called when client receives a pong from the server
57
+ # - send - sends a message to the server (and also disables any metaprogramming shenanigans :-/)
58
+ # - close - closes the connection and optionally sends close frame to server. `close(code, data)`
59
+ # - ping - sends a ping
60
+ # - pong - sends a pong
61
+ @_websocket_client = WebSocket::EventMachine::Client.connect(uri: @_uri, headers: headers)
48
62
  end
49
63
 
50
64
  # @param [String] action - how the message is being sent
51
65
  # @param [Hash] data - the message to be sent to the channel
52
66
  def perform(action, data)
53
- if _queued_send
54
- message_queue.push([action, data])
55
- else
56
- dispatch_message(action, data)
57
- end
67
+ dispatch_message(action, data)
58
68
  end
59
69
 
60
70
  # callback for received messages as well as
@@ -70,7 +80,7 @@ class ActionCableClient
70
80
  # puts message
71
81
  # end
72
82
  def received(skip_pings = true)
73
- _websocket_client.stream do |message|
83
+ _websocket_client.onmessage do |message, _type|
74
84
  handle_received_message(message, skip_pings) do |json|
75
85
  yield(json)
76
86
  end
@@ -85,7 +95,7 @@ class ActionCableClient
85
95
  # # do things after the client is connected to the server
86
96
  # end
87
97
  def connected
88
- _websocket_client.callback do
98
+ _websocket_client.onopen do
89
99
  subscribe
90
100
  yield
91
101
  end
@@ -122,7 +132,7 @@ class ActionCableClient
122
132
  # # cleanup after the server disconnects from the client
123
133
  # end
124
134
  def disconnected
125
- _websocket_client.disconnect do
135
+ _websocket_client.onclose do
126
136
  self._subscribed = false
127
137
  yield
128
138
  end
@@ -130,40 +140,12 @@ class ActionCableClient
130
140
 
131
141
  private
132
142
 
133
- # @param [WebSocket::Frame::Incoming::Client] message - the websockt message object
134
- # This object is from the websocket-ruby gem:
135
- # https://github.com/imanel/websocket-ruby/blob/master/lib/websocket/frame/incoming/client.rb
136
- #
137
- # [9] pry(#<ActionCableClient>)> ap message.methods - Object.instance_methods
138
- #
139
- # [ 0] <<(data) WebSocket::Frame::Incoming::Client (WebSocket::Frame::Incoming)
140
- # [ 1] code() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
141
- # [ 2] code=(arg1) WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
142
- # [ 3] data() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
143
- # [ 4] data=(arg1) WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
144
- # [ 5] decoded?() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Incoming)
145
- # [ 6] error() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
146
- # [ 7] error=(arg1) WebSocket::Frame::Incoming::Client (WebSocket::ExceptionHandler)
147
- # [ 8] error?() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
148
- # [ 9] incoming_masking?() WebSocket::Frame::Incoming::Client
149
- # [10] initialize_with_rescue(*args) WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
150
- # [11] next(*args) WebSocket::Frame::Incoming::Client (WebSocket::Frame::Incoming)
151
- # [12] next_with_rescue(*args) WebSocket::Frame::Incoming::Client (WebSocket::Frame::Incoming)
152
- # [13] next_without_rescue() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Incoming)
153
- # [14] outgoing_masking?() WebSocket::Frame::Incoming::Client
154
- # [15] support_type?() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
155
- # [16] supported_frames() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
156
- # [17] type() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
157
- # [18] version() WebSocket::Frame::Incoming::Client (WebSocket::Frame::Base)
158
- #
159
- # None of this really seems that importont, other than `data`
160
- #
143
+ # @param [String] message - the websockt message object
161
144
  # @param [Boolean] skip_pings - by default, messages
162
145
  # with the identifier '_ping' are skipped
163
146
  def handle_received_message(message, skip_pings = true)
164
- string = message.data
165
- return if string.empty?
166
- json = JSON.parse(string)
147
+ return if message.empty?
148
+ json = JSON.parse(message)
167
149
 
168
150
  if is_ping?(json)
169
151
  yield(json) unless skip_pings
@@ -174,17 +156,15 @@ class ActionCableClient
174
156
  # maybe just make it extensible?
175
157
  yield(json)
176
158
  end
177
-
178
- deplete_queue if _queued_send
179
159
  end
180
160
 
181
161
  # {"identifier" => "_ping","type" => "confirm_subscription"}
182
162
  def check_for_subscribe_confirmation(message)
183
163
  message_type = message[Message::TYPE_KEY]
184
- if Message::TYPE_CONFIRM_SUBSCRIPTION == message_type
185
- self._subscribed = true
186
- _subscribed_callaback.call if _subscribed_callaback
187
- end
164
+ return unless Message::TYPE_CONFIRM_SUBSCRIPTION == message_type
165
+
166
+ self._subscribed = true
167
+ _subscribed_callaback&.call
188
168
  end
189
169
 
190
170
  # {"identifier" => "_ping","message" => 1460201942}
@@ -199,23 +179,12 @@ class ActionCableClient
199
179
  send_msg(msg.to_json)
200
180
  end
201
181
 
202
- def deplete_queue
203
- # if we haven't yet subscribed, don't deplete the queue
204
- if subscribed?
205
- # only try to send if we have messages to send
206
- until message_queue.empty?
207
- action, data = message_queue.pop
208
- dispatch_message(action, data)
209
- end
210
- end
211
- end
212
-
213
182
  def dispatch_message(action, data)
214
183
  # can't send messages if we aren't subscribed
215
- if subscribed?
216
- msg = _message_factory.create(Commands::MESSAGE, action, data)
217
- json = msg.to_json
218
- send_msg(json)
219
- end
184
+ return unless subscribed?
185
+
186
+ msg = _message_factory.create(Commands::MESSAGE, action, data)
187
+ json = msg.to_json
188
+ send_msg(json)
220
189
  end
221
190
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ActionCableClient
4
+ module Errors
5
+ class ChannelNotSpecified < StandardError; end
6
+ end
7
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class ActionCableClient
3
4
  class Message
4
5
  IDENTIFIER_KEY = 'identifier'
@@ -1,11 +1,23 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class ActionCableClient
3
4
  class MessageFactory
4
- attr_reader :_channel
5
+ attr_reader :channel, :identifier
5
6
 
6
- # @param [String] channel - the name of the subscribed channel
7
+ # @param [String or Hash] channel - the name of the subscribed channel, or
8
+ # a hash that includes the :channel key and any other params to send.
7
9
  def initialize(channel)
8
- @_channel = channel
10
+ # the ending result should look like
11
+ # "{"channel":"RoomChannel"}" but that's up to
12
+ # the Mesage to format it
13
+ @channel = channel
14
+ @identifier =
15
+ case channel
16
+ when String then { channel: channel }
17
+ when Hash then channel
18
+ else
19
+ raise ActionCableClient::Errors::ChannelNotSpecified, 'channel is invalid'
20
+ end
9
21
  end
10
22
 
11
23
  # @param [String] command - the type of message that this is
@@ -22,12 +34,5 @@ class ActionCableClient
22
34
  def build_data(action, message)
23
35
  message.merge(action: action) if message.is_a?(Hash)
24
36
  end
25
-
26
- # the ending result should look like
27
- # "{"channel":"RoomChannel"}" but that's up to
28
- # the Mesage to format it
29
- def identifier
30
- { channel: _channel }
31
- end
32
37
  end
33
38
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class ActionCableClient
3
- VERSION = '1.3.4'
4
+ VERSION = '2.0.0'
4
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_cable_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.4
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - L. Preston Sego III
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-07 00:00:00.000000000 Z
11
+ date: 2017-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.0.0.beta4
27
27
  - !ruby/object:Gem::Dependency
28
- name: em-websocket-client
28
+ name: websocket-eventmachine-client
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.1.2
33
+ version: 1.2.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.1.2
40
+ version: 1.2.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -101,8 +101,10 @@ extensions: []
101
101
  extra_rdoc_files: []
102
102
  files:
103
103
  - CHANGELOG.md
104
+ - LICENSE
104
105
  - README.md
105
106
  - lib/action_cable_client.rb
107
+ - lib/action_cable_client/errors.rb
106
108
  - lib/action_cable_client/message.rb
107
109
  - lib/action_cable_client/message_factory.rb
108
110
  - lib/action_cable_client/version.rb
@@ -126,8 +128,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
128
  version: '0'
127
129
  requirements: []
128
130
  rubyforge_project:
129
- rubygems_version: 2.6.6
131
+ rubygems_version: 2.5.1
130
132
  signing_key:
131
133
  specification_version: 4
132
- summary: ActionCableClient-1.3.4
134
+ summary: ActionCableClient-2.0.0
133
135
  test_files: []
136
+ has_rdoc: