lightstreamer 0.1 → 0.2
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 -1
- data/README.md +1 -1
- data/lib/lightstreamer.rb +1 -1
- data/lib/lightstreamer/cli/{stream_command.rb → commands/stream_command.rb} +7 -5
- data/lib/lightstreamer/control_connection.rb +1 -4
- data/lib/lightstreamer/protocol_error.rb +1 -1
- data/lib/lightstreamer/session.rb +30 -12
- data/lib/lightstreamer/stream_connection.rb +11 -2
- data/lib/lightstreamer/subscription.rb +32 -22
- data/lib/lightstreamer/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7dd1721bffbb480dfa570531e520c727084a58d9
|
|
4
|
+
data.tar.gz: 67ee866151859546536fca838dabfe05e84a1d2d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e52c034fa5c273733b97373038f1ccb9ac18959b9ab8c47b47c515ce64a954f3b397966cb02d5e924183364ec47d0402454faf117e4dbef3d3451fb5cfdaafa
|
|
7
|
+
data.tar.gz: 8a79799ea6def575bd5aed0bbbe9d514512d4db4bd32b5dd6417a320d8b929739931714403f4312b3316f326280dc049c15ca883c5af929be9ba92c62687451a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Lightstreamer Changelog
|
|
2
2
|
|
|
3
|
-
### 0.
|
|
3
|
+
### 0.2 — July 23, 2016
|
|
4
|
+
|
|
5
|
+
- Added complete test suite
|
|
6
|
+
- Added `Lightstreamer::Session#subscribed?` and `Lightstreamer::Session#disconnect`
|
|
7
|
+
- Fixed `Lightstreamer::ProtocolError#code` not being set
|
|
8
|
+
- Renamed the command-line client's `--address` option to `--server-url`
|
|
9
|
+
|
|
10
|
+
### 0.1 — July 22, 2016
|
|
4
11
|
|
|
5
12
|
- Initial release
|
data/README.md
CHANGED
|
@@ -75,7 +75,7 @@ subscription, then print streaming output from the server as it becomes availabl
|
|
|
75
75
|
To print streaming data from the demo server run the following command:
|
|
76
76
|
|
|
77
77
|
```
|
|
78
|
-
lightstreamer --
|
|
78
|
+
lightstreamer --server-url http://push.lightstreamer.com --adapter-set DEMO --adapter QUOTE_ADAPTER \
|
|
79
79
|
--items item1 item2 item3 item4 item5 --fields time stock_name bid ask bid
|
|
80
80
|
```
|
|
81
81
|
|
data/lib/lightstreamer.rb
CHANGED
|
@@ -11,7 +11,7 @@ require 'lightstreamer/subscription'
|
|
|
11
11
|
require 'lightstreamer/version'
|
|
12
12
|
|
|
13
13
|
require 'lightstreamer/cli/main'
|
|
14
|
-
require 'lightstreamer/cli/stream_command'
|
|
14
|
+
require 'lightstreamer/cli/commands/stream_command'
|
|
15
15
|
|
|
16
16
|
# This module contains all the code for the Lightstreamer gem. See `README.md` to get started with using this gem.
|
|
17
17
|
module Lightstreamer
|
|
@@ -4,7 +4,7 @@ module Lightstreamer
|
|
|
4
4
|
class Main < Thor
|
|
5
5
|
desc 'stream', 'Streams a set of items and fields from a Lightstreamer server and prints the live output'
|
|
6
6
|
|
|
7
|
-
option :
|
|
7
|
+
option :server_url, required: true, desc: 'The URL of the Lightstreamer server'
|
|
8
8
|
option :username, desc: 'The username for the session'
|
|
9
9
|
option :password, desc: 'The password for the session'
|
|
10
10
|
option :adapter_set, desc: 'The name of the adapter set for the session'
|
|
@@ -30,7 +30,7 @@ module Lightstreamer
|
|
|
30
30
|
|
|
31
31
|
# Creates a new session from the specified options.
|
|
32
32
|
def create_session
|
|
33
|
-
Lightstreamer::Session.new server_url: options[:
|
|
33
|
+
Lightstreamer::Session.new server_url: options[:server_url], username: options[:username],
|
|
34
34
|
password: options[:password], adapter_set: options[:adapter_set]
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -39,12 +39,14 @@ module Lightstreamer
|
|
|
39
39
|
subscription = Lightstreamer::Subscription.new items: options[:items], fields: options[:fields],
|
|
40
40
|
mode: options[:mode], adapter: options[:adapter]
|
|
41
41
|
|
|
42
|
-
subscription.add_data_callback
|
|
43
|
-
@queue.push "#{item_name} - #{new_values.map { |key, value| "#{key}: #{value}" }.join ', '}"
|
|
44
|
-
end
|
|
42
|
+
subscription.add_data_callback(&method(:subscription_data_callback))
|
|
45
43
|
|
|
46
44
|
subscription
|
|
47
45
|
end
|
|
46
|
+
|
|
47
|
+
def subscription_data_callback(_subscription, item_name, _item_data, new_values)
|
|
48
|
+
@queue.push "#{item_name} - #{new_values.map { |key, value| "#{key}: #{value}" }.join ', '}"
|
|
49
|
+
end
|
|
48
50
|
end
|
|
49
51
|
end
|
|
50
52
|
end
|
|
@@ -26,10 +26,7 @@ module Lightstreamer
|
|
|
26
26
|
def execute(options)
|
|
27
27
|
result = execute_post_request build_payload(options)
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
raise ProtocolError, result[2], result[1] if result.first == 'ERROR'
|
|
31
|
-
|
|
32
|
-
warn "Lightstreamer: unexpected response from server: #{result}"
|
|
29
|
+
raise ProtocolError.new(result[2], result[1]) if result.first == 'ERROR'
|
|
33
30
|
end
|
|
34
31
|
|
|
35
32
|
private
|
|
@@ -34,8 +34,9 @@ module Lightstreamer
|
|
|
34
34
|
# Creates a new Lightstreamer session using the details passed to {#initialize}. If an error occurs then
|
|
35
35
|
# {ProtocolError} will be raised.
|
|
36
36
|
def connect
|
|
37
|
+
return if @stream_connection
|
|
38
|
+
|
|
37
39
|
@stream_connection = StreamConnection.new self
|
|
38
|
-
@subscriptions = []
|
|
39
40
|
|
|
40
41
|
first_line = @stream_connection.read_line
|
|
41
42
|
|
|
@@ -48,6 +49,19 @@ module Lightstreamer
|
|
|
48
49
|
end
|
|
49
50
|
end
|
|
50
51
|
|
|
52
|
+
# Disconnects this session and shuts down its stream and processing threads.
|
|
53
|
+
def disconnect
|
|
54
|
+
@stream_connection.disconnect if @stream_connection
|
|
55
|
+
|
|
56
|
+
if @processing_thread
|
|
57
|
+
Thread.kill @processing_thread
|
|
58
|
+
@processing_thread.join
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@processing_thread = @stream_connection = @control_connection = nil
|
|
62
|
+
@subscriptions = []
|
|
63
|
+
end
|
|
64
|
+
|
|
51
65
|
# Subscribes this Lightstreamer session to the specified subscription.
|
|
52
66
|
#
|
|
53
67
|
# @param [Subscription] subscription The new subscription to subscribe to.
|
|
@@ -66,13 +80,20 @@ module Lightstreamer
|
|
|
66
80
|
end
|
|
67
81
|
end
|
|
68
82
|
|
|
83
|
+
# Returns whether the specified subscription is currently active on this session.
|
|
84
|
+
#
|
|
85
|
+
# @param [Subscription] subscription The subscription to return the status for.
|
|
86
|
+
#
|
|
87
|
+
# @return [Boolean] Whether the specified subscription is currently active on this session.
|
|
88
|
+
def subscribed?(subscription)
|
|
89
|
+
@subscriptions_mutex.synchronize { @subscriptions.include? subscription }
|
|
90
|
+
end
|
|
91
|
+
|
|
69
92
|
# Unsubscribes this Lightstreamer session from the specified subscription.
|
|
70
93
|
#
|
|
71
94
|
# @param [Subscription] subscription The existing subscription to unsubscribe from.
|
|
72
95
|
def unsubscribe(subscription)
|
|
73
|
-
|
|
74
|
-
raise ArgumentError, 'Unknown subscription' unless @subscriptions.detect subscription
|
|
75
|
-
end
|
|
96
|
+
raise ArgumentError, 'Unknown subscription' unless subscribed? subscription
|
|
76
97
|
|
|
77
98
|
@control_connection.execute table: subscription.id, operation: :delete
|
|
78
99
|
|
|
@@ -105,13 +126,10 @@ module Lightstreamer
|
|
|
105
126
|
# Starts the processing thread that reads and processes incoming data from the stream connection.
|
|
106
127
|
def create_processing_thread
|
|
107
128
|
@processing_thread = Thread.new do
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
rescue StandardError => error
|
|
113
|
-
warn "Lightstreamer: exception in processing thread: #{error}"
|
|
114
|
-
exit 1
|
|
129
|
+
loop do
|
|
130
|
+
line = @stream_connection.read_line
|
|
131
|
+
|
|
132
|
+
process_stream_data line unless line.empty?
|
|
115
133
|
end
|
|
116
134
|
end
|
|
117
135
|
end
|
|
@@ -137,7 +155,7 @@ module Lightstreamer
|
|
|
137
155
|
@stream_connection = nil
|
|
138
156
|
@control_connection = nil
|
|
139
157
|
|
|
140
|
-
raise ProtocolError
|
|
158
|
+
raise ProtocolError.new(error_message, error_code)
|
|
141
159
|
end
|
|
142
160
|
end
|
|
143
161
|
end
|
|
@@ -2,6 +2,9 @@ module Lightstreamer
|
|
|
2
2
|
# Manages a long-running Lightstreamer connection that handles incoming streaming data on a separate thread and
|
|
3
3
|
# makes it available for consumption via the {#read_line} method.
|
|
4
4
|
class StreamConnection
|
|
5
|
+
# @return [Thread] The thread used to process incoming streaming data.
|
|
6
|
+
attr_reader :thread
|
|
7
|
+
|
|
5
8
|
# Establishes a new stream connection using the authentication details from the passed session.
|
|
6
9
|
#
|
|
7
10
|
# @param [Session] session The session to create a stream connection for.
|
|
@@ -13,6 +16,14 @@ module Lightstreamer
|
|
|
13
16
|
create_stream_thread
|
|
14
17
|
end
|
|
15
18
|
|
|
19
|
+
# Disconnects this stream connection by shutting down the streaming thread.
|
|
20
|
+
def disconnect
|
|
21
|
+
return unless @thread
|
|
22
|
+
|
|
23
|
+
Thread.kill @thread
|
|
24
|
+
@thread.join
|
|
25
|
+
end
|
|
26
|
+
|
|
16
27
|
# Reads the next line of streaming data. This method blocks the calling thread until a line of data is available.
|
|
17
28
|
def read_line
|
|
18
29
|
@queue.pop
|
|
@@ -29,8 +40,6 @@ module Lightstreamer
|
|
|
29
40
|
@thread = Thread.new do
|
|
30
41
|
begin
|
|
31
42
|
connect_stream_and_queue_data
|
|
32
|
-
|
|
33
|
-
warn 'Lightstreamer: stream connection closed'
|
|
34
43
|
rescue StandardError => error
|
|
35
44
|
warn "Lightstreamer: exception in stream thread: #{error}"
|
|
36
45
|
exit 1
|
|
@@ -8,10 +8,10 @@ module Lightstreamer
|
|
|
8
8
|
# in incoming Lightstreamer data.
|
|
9
9
|
attr_reader :id
|
|
10
10
|
|
|
11
|
-
# @return [Array
|
|
11
|
+
# @return [Array] The names of the items to subscribe to.
|
|
12
12
|
attr_reader :items
|
|
13
13
|
|
|
14
|
-
# @return [Array
|
|
14
|
+
# @return [Array] The names of the fields to subscribe to on the items.
|
|
15
15
|
attr_reader :fields
|
|
16
16
|
|
|
17
17
|
# @return [:distinct, :merge] The operation mode of this subscription.
|
|
@@ -25,8 +25,8 @@ module Lightstreamer
|
|
|
25
25
|
# {Session#subscribe} to activate the subscription on a Lightstreamer session.
|
|
26
26
|
#
|
|
27
27
|
# @param [Hash] options The options to create the subscription with.
|
|
28
|
-
# @option options [Array
|
|
29
|
-
# @option options [Array
|
|
28
|
+
# @option options [Array] :items The names of the items to subscribe to.
|
|
29
|
+
# @option options [Array] :fields The names of the fields to subscribe to on the items.
|
|
30
30
|
# @option options [:distinct, :merge] :mode The operation mode of this subscription.
|
|
31
31
|
# @option options [String] :adapter The name of the data adapter from the Lightstreamer session's adapter set that
|
|
32
32
|
# should be used. If `nil` then the default data adapter will be used.
|
|
@@ -55,7 +55,7 @@ module Lightstreamer
|
|
|
55
55
|
# Clears the current data stored for the specified item. This is important to do when {#mode} is `:distinct` as
|
|
56
56
|
# otherwise the incoming data will build up indefinitely.
|
|
57
57
|
#
|
|
58
|
-
# @param [String] item_name The name of the item to clear the current data
|
|
58
|
+
# @param [String] item_name The name of the item to clear the current data for.
|
|
59
59
|
def clear_data_for_item(item_name)
|
|
60
60
|
index = @items.index item_name
|
|
61
61
|
raise ArgumentError, 'Unrecognized item name' unless index
|
|
@@ -74,8 +74,6 @@ module Lightstreamer
|
|
|
74
74
|
# @return [Proc] The same `Proc` object that was passed to this method. This can be used to remove this data
|
|
75
75
|
# callback at a later stage using {#remove_data_callback}.
|
|
76
76
|
def add_data_callback(&block)
|
|
77
|
-
raise ArgumentError, 'Data callbacks must take four arguments' unless block.arity == 4
|
|
78
|
-
|
|
79
77
|
@data_mutex.synchronize { @data_callbacks << block }
|
|
80
78
|
|
|
81
79
|
block
|
|
@@ -111,16 +109,16 @@ module Lightstreamer
|
|
|
111
109
|
# @return [Boolean] Whether the passed line of stream data was relevant to this subscription and was successfully
|
|
112
110
|
# processed by it.
|
|
113
111
|
def process_stream_data(line)
|
|
114
|
-
item_index,
|
|
112
|
+
item_index, new_values = parse_stream_data line
|
|
115
113
|
return false unless item_index
|
|
116
114
|
|
|
117
115
|
@data_mutex.synchronize do
|
|
118
116
|
data = @data[item_index]
|
|
119
117
|
|
|
120
|
-
data <<
|
|
121
|
-
data.merge!(
|
|
118
|
+
data << new_values if mode == :distinct
|
|
119
|
+
data.merge!(new_values) if mode == :merge
|
|
122
120
|
|
|
123
|
-
|
|
121
|
+
call_data_callbacks @items[item_index], data, new_values
|
|
124
122
|
end
|
|
125
123
|
|
|
126
124
|
true
|
|
@@ -172,23 +170,35 @@ module Lightstreamer
|
|
|
172
170
|
values.each_with_index do |value, index|
|
|
173
171
|
next if value == ''
|
|
174
172
|
|
|
175
|
-
|
|
176
|
-
value = '' if value == '$'
|
|
177
|
-
value = nil if value == '#'
|
|
178
|
-
value = value[1..-1] if value =~ /^($|#)/
|
|
179
|
-
|
|
180
|
-
hash[fields[index]] = convert_utf16_characters value
|
|
173
|
+
hash[fields[index]] = parse_raw_field_value value
|
|
181
174
|
end
|
|
182
175
|
|
|
183
176
|
hash
|
|
184
177
|
end
|
|
185
178
|
|
|
186
|
-
#
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
179
|
+
# Parses a raw field value according to to the Lightstreamer specification.
|
|
180
|
+
def parse_raw_field_value(value)
|
|
181
|
+
return '' if value == '$'
|
|
182
|
+
return nil if value == '#'
|
|
183
|
+
|
|
184
|
+
value = value[1..-1] if value =~ /^(\$|#)/
|
|
185
|
+
|
|
186
|
+
# TODO: parse any non-ASCII characters which are specified as UTF-16 escape sequences in the form '\uXXXX' or
|
|
187
|
+
# '\uXXXX\uYYYY'. They need to be transformed into native Unicode characters.
|
|
188
|
+
|
|
191
189
|
value
|
|
192
190
|
end
|
|
191
|
+
|
|
192
|
+
# Invokes all of this subscription's data callbacks with the specified arguments. Any exceptions that occur in a
|
|
193
|
+
# data callback are reported on `stderr` but are otherwise ignored.
|
|
194
|
+
def call_data_callbacks(item_name, item_data, new_values)
|
|
195
|
+
@data_callbacks.each do |callback|
|
|
196
|
+
begin
|
|
197
|
+
callback.call self, item_name, item_data, new_values
|
|
198
|
+
rescue StandardError => error
|
|
199
|
+
warn "Lightstreamer: exception occurred in a subscription data callback: #{error}"
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
193
203
|
end
|
|
194
204
|
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.2'
|
|
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-07-
|
|
11
|
+
date: 2016-07-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rest-client
|
|
@@ -176,8 +176,8 @@ files:
|
|
|
176
176
|
- README.md
|
|
177
177
|
- bin/lightstreamer
|
|
178
178
|
- lib/lightstreamer.rb
|
|
179
|
+
- lib/lightstreamer/cli/commands/stream_command.rb
|
|
179
180
|
- lib/lightstreamer/cli/main.rb
|
|
180
|
-
- lib/lightstreamer/cli/stream_command.rb
|
|
181
181
|
- lib/lightstreamer/control_connection.rb
|
|
182
182
|
- lib/lightstreamer/line_buffer.rb
|
|
183
183
|
- lib/lightstreamer/protocol_error.rb
|
|
@@ -209,5 +209,5 @@ rubyforge_project:
|
|
|
209
209
|
rubygems_version: 2.5.1
|
|
210
210
|
signing_key:
|
|
211
211
|
specification_version: 4
|
|
212
|
-
summary:
|
|
212
|
+
summary: Library and command-line client for accessing a Lightstreamer server.
|
|
213
213
|
test_files: []
|