lightstreamer 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|