lightstreamer 0.10 → 0.11
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +2 -2
- data/lib/lightstreamer/post_request.rb +3 -3
- data/lib/lightstreamer/session.rb +58 -26
- data/lib/lightstreamer/subscription.rb +51 -25
- data/lib/lightstreamer/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 712d0f7cae7367c26efde5f75b0481bb5a3d90a3
|
4
|
+
data.tar.gz: 77a6882d44273754bb5c85a7739bb614860b7b82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6eec1efbbd9e79c891798f8833a820396caa40b0bbb275eee686b95cc93689651e7703495949953d66ea80e95278e0b3f2203e2ad032a1861981426d082473b
|
7
|
+
data.tar.gz: 6164a9f932129439f3870081d55962ebae8f35f44169269f366bd64d2222d66d6bbd14e25fd92b9d59bfe7d3bff8ec52f8f8a5af8ee44a4cd6c144ccd9635377
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Lightstreamer Changelog
|
2
2
|
|
3
|
+
### 0.11 — August 20, 2016
|
4
|
+
|
5
|
+
- Added `Lightstreamer::Session#stop_subscriptions` for stopping multiple subscriptions in one request
|
6
|
+
- Renamed `Lightstreamer::Session#bulk_subscription_start` to `Lightstreamer::Session#start_subscriptions`
|
7
|
+
- Added support for combining all subscription actions via `Lightstreamer::Session#perform_subscription_actions`
|
8
|
+
which allows subscription start, unsilence and stop requests to be easily bundled together
|
9
|
+
- Fixed `Subscription#id` only being callable on the main thread
|
10
|
+
|
3
11
|
### 0.10 — August 5, 2016
|
4
12
|
|
5
13
|
- Added support for shared subscription start options to `Lightstreamer::Session#bulk_subscription_start`
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@ Includes support for:
|
|
20
20
|
- Silent subscriptions
|
21
21
|
- Item snapshots and end-of-snapshot notifications
|
22
22
|
- Unfiltered subscriptions and overflow notifications
|
23
|
-
-
|
23
|
+
- Performing multiple subscription actions in a single request
|
24
24
|
- Synchronous and asynchronous message sending
|
25
25
|
- Detailed error reporting and error handling callbacks
|
26
26
|
|
@@ -64,7 +64,7 @@ session.connect
|
|
64
64
|
# Create a new subscription that subscribes to thirty items and to four fields on each item
|
65
65
|
subscription = session.build_subscription data_adapter: 'QUOTE_ADAPTER', mode: :merge,
|
66
66
|
items: (1..30).map { |i| "item#{i}" },
|
67
|
-
fields: [:ask, :bid, :stock_name, :time]
|
67
|
+
fields: [:ask, :bid, :stock_name, :time]
|
68
68
|
|
69
69
|
# Create a thread-safe queue
|
70
70
|
queue = Queue.new
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Lightstreamer
|
2
|
-
# This module contains helper methods for sending single and
|
2
|
+
# This module contains helper methods for sending single and multiple POST requests to a Lightstreamer server and
|
3
3
|
# handling the possible error responses.
|
4
4
|
#
|
5
5
|
# @private
|
@@ -12,7 +12,7 @@ module Lightstreamer
|
|
12
12
|
# @param [String] url The URL to send the POST request to.
|
13
13
|
# @param [Hash] query The POST request's query params.
|
14
14
|
def execute(url, query)
|
15
|
-
errors =
|
15
|
+
errors = execute_multiple url, [request_body(query)]
|
16
16
|
raise errors.first if errors.first
|
17
17
|
end
|
18
18
|
|
@@ -26,7 +26,7 @@ module Lightstreamer
|
|
26
26
|
#
|
27
27
|
# @return [Array<LightstreamerError, nil>] The execution result of each of the passed bodies. If an entry is `nil`
|
28
28
|
# then no error occurred when executing that body.
|
29
|
-
def
|
29
|
+
def execute_multiple(url, bodies)
|
30
30
|
response = Excon.post url, body: bodies.join("\r\n"), expects: 200, connect_timeout: 15
|
31
31
|
|
32
32
|
response_lines = response.body.split("\n").map(&:strip)
|
@@ -2,7 +2,7 @@ module Lightstreamer
|
|
2
2
|
# This class is responsible for managing a Lightstreamer session, and along with the {Subscription} class forms the
|
3
3
|
# primary API for working with Lightstreamer. Start by calling {#initialize} with the desired server URL and other
|
4
4
|
# options, then call {#connect} to initiate the session. Once connected create subscriptions using
|
5
|
-
# {#build_subscription} and then start streaming data by calling {Subscription#start} or {#
|
5
|
+
# {#build_subscription} and then start streaming data by calling {Subscription#start} or {#start_subscriptions}.
|
6
6
|
# See the {Subscription} class for details on how to consume the streaming data as it arrives.
|
7
7
|
class Session
|
8
8
|
# The URL of the Lightstreamer server to connect to. Set by {#initialize}.
|
@@ -94,14 +94,14 @@ module Lightstreamer
|
|
94
94
|
|
95
95
|
# Disconnects this Lightstreamer session and terminates the session on the server. All worker threads are exited.
|
96
96
|
def disconnect
|
97
|
-
control_request :destroy if @stream_connection
|
97
|
+
control_request LS_op: :destroy if @stream_connection
|
98
98
|
|
99
99
|
@processing_thread.join 5 if @processing_thread
|
100
100
|
ensure
|
101
101
|
@stream_connection.disconnect if @stream_connection
|
102
102
|
@processing_thread.exit if @processing_thread
|
103
103
|
|
104
|
-
@subscriptions.each { |subscription| subscription.
|
104
|
+
@subscriptions.each { |subscription| subscription.after_control_request :stop }
|
105
105
|
|
106
106
|
@processing_thread = @stream_connection = nil
|
107
107
|
end
|
@@ -113,7 +113,7 @@ module Lightstreamer
|
|
113
113
|
# it forces the stream connection to rebind using the new setting. If an error occurs then a {LightstreamerError}
|
114
114
|
# subclass will be raised.
|
115
115
|
def force_rebind
|
116
|
-
control_request :force_rebind if @stream_connection
|
116
|
+
control_request LS_op: :force_rebind if @stream_connection
|
117
117
|
end
|
118
118
|
|
119
119
|
# Builds a new subscription for this session with the specified options. Note that ths does not activate the
|
@@ -152,29 +152,62 @@ module Lightstreamer
|
|
152
152
|
@mutex.synchronize { @subscriptions.delete subscription }
|
153
153
|
end
|
154
154
|
|
155
|
-
# This method performs
|
156
|
-
#
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
160
|
-
# if no error occurred.
|
155
|
+
# This method performs {Subscription#start} on all the passed subscriptions. Calling {Subscription#start} on each
|
156
|
+
# subscription individually would also work but requires a separate POST request to be sent for every subscription,
|
157
|
+
# whereas this method starts all of the passed subscriptions in a single POST request which is significantly faster
|
158
|
+
# for a large number of subscriptions. The return value is an array with one entry per subscription and indicates
|
159
|
+
# the error state returned by the server for that subscription's start request, or `nil` if no error occurred.
|
161
160
|
#
|
162
161
|
# @param [Array<Subscription>] subscriptions The subscriptions to start.
|
163
|
-
# @param [Hash] options The options to start
|
162
|
+
# @param [Hash] options The options to start the subscriptions with. See {Subscription#start} for details on the
|
164
163
|
# supported options.
|
165
164
|
#
|
166
165
|
# @return [Array<LightstreamerError, nil>]
|
167
|
-
def
|
168
|
-
|
169
|
-
|
170
|
-
|
166
|
+
def start_subscriptions(subscriptions, options = {})
|
167
|
+
details = subscriptions.map { |subscription| { subscription: subscription, action: :start, options: options } }
|
168
|
+
|
169
|
+
perform_subscription_actions details
|
170
|
+
end
|
171
|
+
|
172
|
+
# This method performs {Subscription#stop} on all the passed subscriptions. Calling {Subscription#stop} on each
|
173
|
+
# subscription individually would also work but requires a separate POST request to be sent for every subscription,
|
174
|
+
# whereas this method stops all of the passed subscriptions in a single POST request which is significantly faster
|
175
|
+
# for a large number of subscriptions. The return value is an array with one entry per subscription and indicates
|
176
|
+
# the error state returned by the server for that subscription's stop request, or `nil` if no error occurred.
|
177
|
+
#
|
178
|
+
# @param [Array<Subscription>] subscriptions The subscriptions to stop.
|
179
|
+
#
|
180
|
+
# @return [Array<LightstreamerError, nil>]
|
181
|
+
def stop_subscriptions(subscriptions)
|
182
|
+
details = subscriptions.map { |subscription| { subscription: subscription, action: :stop } }
|
183
|
+
|
184
|
+
perform_subscription_actions details
|
185
|
+
end
|
186
|
+
|
187
|
+
# This method takes an array of subscriptions and actions to perform on those subscriptions. The supported actions
|
188
|
+
# are `:start`, `:unsilence` and `:stop`. Calling {Subscription#start}, {Subscription#unsilence} or
|
189
|
+
# {Subscription#stop} on each subscription individually would also work but requires a separate POST request to be
|
190
|
+
# sent for each action, whereas this method performs all of the specified actions in a single POST request which is
|
191
|
+
# significantly faster for a large number of actions. The return value is an array with one entry per action and
|
192
|
+
# indicates the error state returned by the server for that action, or `nil` if no error occurred. It will have the
|
193
|
+
# same number of entries as the passed `details` array.
|
194
|
+
#
|
195
|
+
# @param [Array<Hash>] actions This array describes the subscription actions to perform. Each entry must be a hash
|
196
|
+
# containing a `:subscription` key specifying the {Subscription}, and an `:action` key specifying the action
|
197
|
+
# to perform on the subscription (either `:start`, `:unsilence` or `:stop`). If `:action` is `:start` then an
|
198
|
+
# `:options` key can be specified, and the supported options are the same as for {Subscription#start}.
|
199
|
+
#
|
200
|
+
# @return [Array<LightstreamerError, nil>]
|
201
|
+
def perform_subscription_actions(actions)
|
202
|
+
request_bodies = actions.map do |hash|
|
203
|
+
PostRequest.request_body hash.fetch(:subscription).control_request_options(hash.fetch(:action), hash[:options])
|
171
204
|
end
|
172
205
|
|
173
|
-
errors = PostRequest.
|
206
|
+
errors = PostRequest.execute_multiple control_request_url, request_bodies
|
174
207
|
|
175
|
-
#
|
208
|
+
# Update the state of subscriptions that did not have an error
|
176
209
|
errors.each_with_index do |error, index|
|
177
|
-
|
210
|
+
actions[index][:subscription].after_control_request actions[index][:action] unless error
|
178
211
|
end
|
179
212
|
end
|
180
213
|
|
@@ -183,7 +216,7 @@ module Lightstreamer
|
|
183
216
|
#
|
184
217
|
# @param [Float] bandwidth The new requested maximum bandwidth, expressed in kbps.
|
185
218
|
def requested_maximum_bandwidth=(bandwidth)
|
186
|
-
control_request :constrain, LS_requested_max_bandwidth: bandwidth if connected?
|
219
|
+
control_request LS_op: :constrain, LS_requested_max_bandwidth: bandwidth if connected?
|
187
220
|
@requested_maximum_bandwidth = bandwidth.to_f
|
188
221
|
end
|
189
222
|
|
@@ -228,16 +261,15 @@ module Lightstreamer
|
|
228
261
|
# Sends a request to this session's control connection. If an error occurs then a {LightstreamerError} subclass will
|
229
262
|
# be raised.
|
230
263
|
#
|
231
|
-
# @param [
|
232
|
-
|
233
|
-
|
234
|
-
PostRequest.execute control_request_url, options.merge(LS_session: session_id, LS_op: operation)
|
264
|
+
# @param [Hash] query The details of the control request query.
|
265
|
+
def control_request(query = {})
|
266
|
+
PostRequest.execute control_request_url, query.merge(LS_session: session_id)
|
235
267
|
end
|
236
268
|
|
237
269
|
# Adds the passed block to the list of callbacks that will be run when this session encounters an error on its
|
238
|
-
# processing thread caused by an error with the
|
239
|
-
# the code that is run by the block must be thread-safe. The argument passed to the block is `|error|`, which
|
240
|
-
# be a {LightstreamerError} subclass detailing the error that occurred.
|
270
|
+
# processing thread caused by an error with the stream connection. The block will be called on a worker thread and
|
271
|
+
# so the code that is run by the block must be thread-safe. The argument passed to the block is `|error|`, which
|
272
|
+
# will be a {LightstreamerError} subclass detailing the error that occurred.
|
241
273
|
#
|
242
274
|
# @param [Proc] callback The callback that is to be run.
|
243
275
|
def on_error(&callback)
|
@@ -76,7 +76,7 @@ module Lightstreamer
|
|
76
76
|
#
|
77
77
|
# @private
|
78
78
|
def id
|
79
|
-
@id ||=
|
79
|
+
@id ||= self.class.next_id
|
80
80
|
end
|
81
81
|
|
82
82
|
# Starts streaming data for this Lightstreamer subscription. If an error occurs then a {LightstreamerError} subclass
|
@@ -97,38 +97,23 @@ module Lightstreamer
|
|
97
97
|
def start(options = {})
|
98
98
|
return if @active
|
99
99
|
|
100
|
-
session.control_request(
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns the arguments to pass to to {Session#control_request} in order to start this subscription with the given
|
105
|
-
# options.
|
106
|
-
#
|
107
|
-
# @param [Hash] options The options to start the subscription with.
|
108
|
-
#
|
109
|
-
# @private
|
110
|
-
def start_control_request_args(options = {})
|
111
|
-
operation = options[:silent] ? :add_silent : :add
|
112
|
-
|
113
|
-
options = { LS_table: id, LS_mode: mode.to_s.upcase, LS_id: items, LS_schema: fields, LS_selector: selector,
|
114
|
-
LS_data_adapter: data_adapter, LS_requested_max_frequency: maximum_update_frequency,
|
115
|
-
LS_snapshot: options.fetch(:snapshot, false) }
|
116
|
-
|
117
|
-
[operation, options]
|
100
|
+
session.control_request control_request_options(:start, options)
|
101
|
+
after_control_request :start
|
118
102
|
end
|
119
103
|
|
120
104
|
# Unsilences this subscription if it was initially started in silent mode by passing `silent: true` to {#start}. If
|
121
105
|
# this subscription was not started in silent mode then this method has no effect. If an error occurs then a
|
122
106
|
# {LightstreamerError} subclass will be raised.
|
123
107
|
def unsilence
|
124
|
-
session.control_request :
|
108
|
+
session.control_request control_request_options(:unsilence)
|
109
|
+
after_control_request :unsilence
|
125
110
|
end
|
126
111
|
|
127
112
|
# Stops streaming data for this Lightstreamer subscription. If an error occurs then a {LightstreamerError} subclass
|
128
113
|
# will be raised.
|
129
114
|
def stop
|
130
|
-
session.control_request :
|
131
|
-
|
115
|
+
session.control_request control_request_options(:stop) if @active
|
116
|
+
after_control_request :stop
|
132
117
|
end
|
133
118
|
|
134
119
|
# Sets this subscription's maximum update frequency. This can be done while a subscription is streaming data in
|
@@ -140,7 +125,7 @@ module Lightstreamer
|
|
140
125
|
# details.
|
141
126
|
def maximum_update_frequency=(new_frequency)
|
142
127
|
new_frequency = sanitize_frequency new_frequency
|
143
|
-
session.control_request :reconf, LS_table: id, LS_requested_max_frequency: new_frequency if @active
|
128
|
+
session.control_request LS_op: :reconf, LS_table: id, LS_requested_max_frequency: new_frequency if @active
|
144
129
|
@maximum_update_frequency = new_frequency
|
145
130
|
end
|
146
131
|
|
@@ -181,7 +166,8 @@ module Lightstreamer
|
|
181
166
|
|
182
167
|
# Adds the passed block to the list of callbacks that will be run when new data for this subscription arrives. The
|
183
168
|
# block will be called on a worker thread and so the code that is run by the block must be thread-safe. The
|
184
|
-
# arguments passed to the block are `|subscription, item_name, item_data, new_data|`.
|
169
|
+
# arguments passed to the block are `|subscription, item_name, item_data, new_data|`. The `item_data` argument will
|
170
|
+
# be an array if {#mode} is `:command`, for all other modes it will be a hash. Note that if {#mode} is `:distinct`
|
185
171
|
# or `:raw` then `item_data` and `new_data` will be the same.
|
186
172
|
#
|
187
173
|
# @param [Proc] callback The callback that is to be run when new data arrives.
|
@@ -230,9 +216,39 @@ module Lightstreamer
|
|
230
216
|
return true if process_end_of_snapshot_message EndOfSnapshotMessage.parse(line, id, items)
|
231
217
|
end
|
232
218
|
|
219
|
+
# Returns the control request arguments to use to perform the specified action on this subscription.
|
220
|
+
#
|
221
|
+
# @private
|
222
|
+
def control_request_options(action, options = nil)
|
223
|
+
case action.to_sym
|
224
|
+
when :start
|
225
|
+
start_control_request_options options
|
226
|
+
when :unsilence
|
227
|
+
{ LS_session: session.session_id, LS_op: :start, LS_table: id }
|
228
|
+
when :stop
|
229
|
+
{ LS_session: session.session_id, LS_op: :delete, LS_table: id }
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Performs any required updates to this subscription's state after a control request succeeds.
|
234
|
+
#
|
235
|
+
# @private
|
236
|
+
def after_control_request(action)
|
237
|
+
@active = true if action == :start
|
238
|
+
@active = false if action == :stop
|
239
|
+
end
|
240
|
+
|
233
241
|
private
|
234
242
|
|
235
|
-
|
243
|
+
class << self
|
244
|
+
# Returns the next unique numeric subscription ID.
|
245
|
+
#
|
246
|
+
# @private
|
247
|
+
def next_id
|
248
|
+
@next_id ||= 0
|
249
|
+
@next_id += 1
|
250
|
+
end
|
251
|
+
end
|
236
252
|
|
237
253
|
def sanitize_frequency(frequency)
|
238
254
|
frequency.to_s == 'unfiltered' ? :unfiltered : frequency.to_f
|
@@ -264,5 +280,15 @@ module Lightstreamer
|
|
264
280
|
|
265
281
|
true
|
266
282
|
end
|
283
|
+
|
284
|
+
def start_control_request_options(options)
|
285
|
+
options ||= {}
|
286
|
+
|
287
|
+
operation = options[:silent] ? :add_silent : :add
|
288
|
+
|
289
|
+
{ LS_session: session.session_id, LS_op: operation, LS_table: id, LS_mode: mode.to_s.upcase, LS_id: items,
|
290
|
+
LS_schema: fields, LS_selector: selector, LS_snapshot: options.fetch(:snapshot, false),
|
291
|
+
LS_requested_max_frequency: maximum_update_frequency, LS_data_adapter: data_adapter }
|
292
|
+
end
|
267
293
|
end
|
268
294
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lightstreamer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.11'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Viney
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: excon
|