noam_lemma 0.2.1
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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +20 -0
- data/Rakefile +11 -0
- data/examples/free_guest_publisher.rb +34 -0
- data/examples/free_guest_subscriber.rb +31 -0
- data/examples/lemma_verification.rb +43 -0
- data/examples/publisher.rb +47 -0
- data/examples/subscriber.rb +35 -0
- data/lib/noam_lemma/beacon.rb +36 -0
- data/lib/noam_lemma/lemma.rb +70 -0
- data/lib/noam_lemma/listener.rb +73 -0
- data/lib/noam_lemma/message/heard.rb +18 -0
- data/lib/noam_lemma/message/marco.rb +57 -0
- data/lib/noam_lemma/message/playable.rb +16 -0
- data/lib/noam_lemma/message/polo.rb +15 -0
- data/lib/noam_lemma/message/register.rb +17 -0
- data/lib/noam_lemma/message.rb +15 -0
- data/lib/noam_lemma/message_filter.rb +24 -0
- data/lib/noam_lemma/player.rb +78 -0
- data/lib/noam_lemma/version.rb +3 -0
- data/lib/noam_lemma.rb +16 -0
- data/noam_lemma.gemspec +26 -0
- data/spec/noam_lemma/beacon_spec.rb +26 -0
- data/spec/noam_lemma/lemma_spec.rb +88 -0
- data/spec/noam_lemma/message/heard_spec.rb +19 -0
- data/spec/noam_lemma/message/playable_spec.rb +17 -0
- data/spec/noam_lemma/message/register_spec.rb +17 -0
- data/spec/noam_lemma/message_filter_spec.rb +68 -0
- data/spec/noam_lemma/message_spec.rb +8 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/fake_server.rb +187 -0
- metadata +157 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Noam
|
4
|
+
class NoamPlayerException < Exception; end
|
5
|
+
|
6
|
+
class Player
|
7
|
+
def initialize(remote_host, remote_port)
|
8
|
+
begin
|
9
|
+
@socket = TCPSocket.new(remote_host, remote_port)
|
10
|
+
rescue Errno::ECONNREFUSED
|
11
|
+
raise NoamPlayerException.new("Unable to connect to the Noam server at #{remote_host}:#{remote_port}. Is it running?")
|
12
|
+
end
|
13
|
+
|
14
|
+
@queue = Queue.new
|
15
|
+
manage_queue_on_thread
|
16
|
+
end
|
17
|
+
|
18
|
+
def put(message)
|
19
|
+
@queue.push(message)
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop
|
23
|
+
put(:soft_exit)
|
24
|
+
@thread.join
|
25
|
+
end
|
26
|
+
|
27
|
+
def stop!
|
28
|
+
put(:hard_exit)
|
29
|
+
@thread.join
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def manage_queue_on_thread
|
35
|
+
@thread = Thread.new do |t|
|
36
|
+
begin
|
37
|
+
loop do
|
38
|
+
message = @queue.pop
|
39
|
+
break if exit?(message)
|
40
|
+
process(message)
|
41
|
+
end
|
42
|
+
ensure
|
43
|
+
@socket.close
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def process(message)
|
49
|
+
case message
|
50
|
+
when :soft_exit
|
51
|
+
finish_queue
|
52
|
+
when :hard_exit
|
53
|
+
else
|
54
|
+
@socket.print(message.noam_encode)
|
55
|
+
@socket.flush
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def exit?(message)
|
60
|
+
message == :hard_exit || message == :soft_exit
|
61
|
+
end
|
62
|
+
|
63
|
+
def finish_queue
|
64
|
+
queue_to_array.each do |message|
|
65
|
+
@socket.print(message.noam_encode)
|
66
|
+
@socket.flush
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def queue_to_array
|
71
|
+
result = []
|
72
|
+
while(@queue.size > 0) do
|
73
|
+
result << @queue.pop
|
74
|
+
end
|
75
|
+
result
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/noam_lemma.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Thread.abort_on_exception = true
|
2
|
+
|
3
|
+
module Noam
|
4
|
+
BEACON_PORT = 1030
|
5
|
+
|
6
|
+
VERSION = '0.2.1'
|
7
|
+
DEVICE_TYPE = 'ruby-script'
|
8
|
+
|
9
|
+
class NoamThreadCancelled < Exception; end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'noam_lemma/beacon'
|
13
|
+
require 'noam_lemma/lemma'
|
14
|
+
require 'noam_lemma/listener'
|
15
|
+
require 'noam_lemma/message'
|
16
|
+
require 'noam_lemma/player'
|
data/noam_lemma.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'noam_lemma/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "noam_lemma"
|
8
|
+
spec.version = NoamLemma::VERSION
|
9
|
+
spec.authors = ["John Van Enk"]
|
10
|
+
spec.email = ["vanenkj@gmail.com"]
|
11
|
+
spec.description = %q{A lemma factory for the Noam pub-sub system.}
|
12
|
+
spec.summary = %q{A lemma factory for the Noam pub-sub system.}
|
13
|
+
spec.homepage = "https://github.com/noam-io/lemma-ruby"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "require_all"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.3"
|
24
|
+
spec.add_development_dependency "rspec", "~> 2.14"
|
25
|
+
spec.add_development_dependency "mocha", "~> 1.1"
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
describe Noam::Beacon do
|
2
|
+
describe "#new" do
|
3
|
+
it "creates a new beacon" do
|
4
|
+
beacon = Noam::Beacon.new(:name, :host, :noam)
|
5
|
+
beacon.name.should == :name
|
6
|
+
beacon.host.should == :host
|
7
|
+
beacon.port.should == :noam
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "::discover" do
|
12
|
+
before do
|
13
|
+
FakeManager.start
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
FakeManager.stop
|
18
|
+
end
|
19
|
+
|
20
|
+
it "creates a Beacon based on server beacons" do
|
21
|
+
beacon = Noam::Beacon.discover
|
22
|
+
beacon.should be_a(Noam::Beacon)
|
23
|
+
beacon.port.should == NoamTest::FakeServer::PORT
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
describe Noam::Lemma do
|
2
|
+
SERVER_DELAY = 0.05
|
3
|
+
|
4
|
+
before(:each) do
|
5
|
+
FakeManager.start
|
6
|
+
@server = FakeManager.server
|
7
|
+
@lemma = Noam::Lemma.new("Example Lemma", ["event1"], ["event1"])
|
8
|
+
@lemma.discover
|
9
|
+
sleep(SERVER_DELAY)
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
@lemma.stop
|
14
|
+
FakeManager.stop
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#new" do
|
18
|
+
context "with provided arguments" do
|
19
|
+
let(:lemma) { Noam::Lemma.new("Example Lemma", ["event1"], ["event1"]) }
|
20
|
+
|
21
|
+
it "sets #name to the given name" do
|
22
|
+
lemma.name.should == "Example Lemma"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sets #hears to the given hears" do
|
26
|
+
lemma.hears.should == ["event1"]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "sets #speaks to the given speaks" do
|
30
|
+
lemma.speaks.should == ["event1"]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with default arguments" do
|
35
|
+
let(:lemma) { Noam::Lemma.new("Example Lemma") }
|
36
|
+
|
37
|
+
it "sets #hears to an empty array" do
|
38
|
+
lemma.hears.should == []
|
39
|
+
end
|
40
|
+
|
41
|
+
it "sets #speaks to an empty array" do
|
42
|
+
lemma.speaks.should == []
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#hears" do
|
48
|
+
let(:lemma) { Noam::Lemma.new("Example Lemma", ["example_event"]) }
|
49
|
+
|
50
|
+
it "delegates to the MessageFilter when set" do
|
51
|
+
message_filter = Noam::MessageFilter.new
|
52
|
+
message_filter.hear("sample_event") {}
|
53
|
+
lemma.set_message_filter(message_filter)
|
54
|
+
lemma.hears.should == message_filter.hears
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#discover" do
|
59
|
+
it "sends a registration message" do
|
60
|
+
@server.clients.length.should == 1
|
61
|
+
@server.clients.first.port.should be_an(Integer)
|
62
|
+
@server.clients.first.port.should_not == 0
|
63
|
+
end
|
64
|
+
|
65
|
+
it "initializes listener and player" do
|
66
|
+
@lemma.listener.should_not be_nil
|
67
|
+
@lemma.player.should_not be_nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#speak" do
|
72
|
+
it "sends an event to the server" do
|
73
|
+
@lemma.speak("an event", "some value")
|
74
|
+
sleep(SERVER_DELAY)
|
75
|
+
@server.messages.map{|m| m[2]}.include?("an event").should be_true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#listen" do
|
80
|
+
it "returns a message from the server" do
|
81
|
+
@server.send_message(["event", "test-server", "event1", "noam event"])
|
82
|
+
message = @lemma.listen
|
83
|
+
message.source.should == "test-server"
|
84
|
+
message.event.should == "event1"
|
85
|
+
message.value.should == "noam event"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe Noam::Message::Heard do
|
2
|
+
describe "#new" do
|
3
|
+
it "creates a new Heard message" do
|
4
|
+
h = Noam::Message::Heard.new("source", "event", "value")
|
5
|
+
h.source.should == "source"
|
6
|
+
h.event.should == "event"
|
7
|
+
h.value.should == "value"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "::from_noam" do
|
12
|
+
it "ceates a new Heard message from the noam event structure" do
|
13
|
+
h = Noam::Message::Heard.from_noam(["event", "source", "event", "value"].to_json)
|
14
|
+
h.source.should == "source"
|
15
|
+
h.event.should == "event"
|
16
|
+
h.value.should == "value"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe Noam::Message::Playable do
|
2
|
+
describe "#new" do
|
3
|
+
it "can be built" do
|
4
|
+
Noam::Message::Playable.new(
|
5
|
+
:host, :event, :value
|
6
|
+
).class.should == Noam::Message::Playable
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#noam_encode" do
|
11
|
+
it "encodes the Playable" do
|
12
|
+
Noam::Message::Playable.new(
|
13
|
+
"host", "event", "value"
|
14
|
+
).noam_encode.should == '000032["event","host","event","value"]'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe Noam::Message::Register do
|
2
|
+
describe "#new" do
|
3
|
+
it "creates a new Register object" do
|
4
|
+
message = Noam::Message::Register.new(:devid, :port, :hears, :speaks)
|
5
|
+
message.should be_a(Noam::Message::Register)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#noam_encode" do
|
10
|
+
it "encodes the Register message" do
|
11
|
+
message = Noam::Message::Register.new("an_id", 1234, ["e1"], ["e2", "e3"]).noam_encode
|
12
|
+
expected = '000066["register","an_id",1234,["e1"],["e2","e3"],"' +
|
13
|
+
Noam::DEVICE_TYPE + '","' + Noam::VERSION + '"]'
|
14
|
+
message.should == expected
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
describe Noam::MessageFilter do
|
2
|
+
let(:filter) { Noam::MessageFilter.new }
|
3
|
+
let(:message) { stub_message("example_event") }
|
4
|
+
|
5
|
+
describe "#hear" do
|
6
|
+
it "registers event names with the filter" do
|
7
|
+
filter.hear("example_event") {}
|
8
|
+
filter.hear("sample_event") {}
|
9
|
+
filter.hears.should == ["example_event", "sample_event"]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#hears" do
|
14
|
+
it "includes single entries for event names registered multiple times" do
|
15
|
+
filter.hear("example_event") {}
|
16
|
+
filter.hear("example_event") {}
|
17
|
+
filter.hears.should == ["example_event"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#receive" do
|
22
|
+
it "calls blocks associated with the given event name" do
|
23
|
+
messages_received = 0
|
24
|
+
filter.hear("example_event") {|message| messages_received += 1}
|
25
|
+
filter.receive(message)
|
26
|
+
messages_received.should == 1
|
27
|
+
end
|
28
|
+
|
29
|
+
it "calls multiple blocks associated with the given event name" do
|
30
|
+
message_one = nil, message_two = nil
|
31
|
+
filter.hear("example_event") {|message| message_one = message}
|
32
|
+
filter.hear("example_event") {|message| message_two = message}
|
33
|
+
filter.receive(message)
|
34
|
+
message_one.should be(message)
|
35
|
+
message_two.should be(message)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "ignores blocks associated with other event names" do
|
39
|
+
example_received = nil, sample_received = nil
|
40
|
+
filter.hear("example_event") {|message| example_received = true}
|
41
|
+
filter.hear("sample_event") {|message| sample_received = true}
|
42
|
+
filter.receive(stub_message("example_event"))
|
43
|
+
example_received.should be_true
|
44
|
+
sample_received.should be_false
|
45
|
+
end
|
46
|
+
|
47
|
+
it "returns the given message" do
|
48
|
+
message = stub_message("example_event")
|
49
|
+
result = filter.receive(message)
|
50
|
+
result.should be(message)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "ignores event names with no associations" do
|
54
|
+
message = stub_message("example_event")
|
55
|
+
lambda { filter.receive(message) }.should_not raise_error
|
56
|
+
end
|
57
|
+
|
58
|
+
it "ignores event names with empty blocks" do
|
59
|
+
message = stub_message("example_event")
|
60
|
+
filter.hear("example_event") {}
|
61
|
+
lambda { filter.receive(message) }.should_not raise_error
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def stub_message(event_name, value = "")
|
66
|
+
stub("message", event: event_name, value: value)
|
67
|
+
end
|
68
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'require_all'
|
2
|
+
|
3
|
+
libs = Dir[File.dirname(File.expand_path(__FILE__)) + "/../lib/**/*.rb"]
|
4
|
+
require_all(libs)
|
5
|
+
|
6
|
+
support_libs = Dir[File.dirname(File.expand_path(__FILE__)) + "/support/**/*.rb"]
|
7
|
+
require_all(support_libs)
|
8
|
+
|
9
|
+
class FakeManager
|
10
|
+
def self.start
|
11
|
+
@@beacon = NoamTest::FakeBeacon.new(Noam::BEACON_PORT)
|
12
|
+
@@beacon.start
|
13
|
+
|
14
|
+
@@server = NoamTest::FakeServer.new
|
15
|
+
@@server.start
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.stop
|
19
|
+
@@beacon.stop
|
20
|
+
@@server.stop
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.server
|
24
|
+
@@server
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
config.mock_framework = :mocha
|
30
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
class FakeBeaconThreadCancelled < Exception; end
|
5
|
+
class FakeServerThreadCancelled < Exception; end
|
6
|
+
|
7
|
+
class UnexpectedRegisterText < Exception; end
|
8
|
+
class UnexpectedSystemVersion < Exception; end
|
9
|
+
|
10
|
+
module NoamTest
|
11
|
+
class FakeBeacon
|
12
|
+
LOOP_DELAY = 0.001
|
13
|
+
|
14
|
+
def initialize(udp_broadcast_port)
|
15
|
+
@socket = UDPSocket.new
|
16
|
+
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
@thread = Thread.new do |t|
|
21
|
+
begin
|
22
|
+
loop do
|
23
|
+
msg = ["beacon", "fake_beacon", NoamTest::FakeServer::PORT].to_json
|
24
|
+
@socket.send(msg, 0, "255.255.255.255", Noam::BEACON_PORT)
|
25
|
+
|
26
|
+
# This is normally at 5.0 seconds, but we run faster in order to
|
27
|
+
# make tests faster.
|
28
|
+
sleep(LOOP_DELAY)
|
29
|
+
end
|
30
|
+
rescue FakeBeaconThreadCancelled
|
31
|
+
# going down
|
32
|
+
ensure
|
33
|
+
@socket.close
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def stop
|
39
|
+
@thread.raise(FakeBeaconThreadCancelled)
|
40
|
+
@thread.join
|
41
|
+
@thread = nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class FakeServer
|
46
|
+
PORT = 7733
|
47
|
+
|
48
|
+
def initialize
|
49
|
+
@sock = TCPServer.new(FakeServer::PORT)
|
50
|
+
end
|
51
|
+
|
52
|
+
def start
|
53
|
+
@clients = []
|
54
|
+
@thread = Thread.new do |t|
|
55
|
+
begin
|
56
|
+
loop do
|
57
|
+
s = @sock.accept
|
58
|
+
@clients << (c = Client.new(s))
|
59
|
+
c.start
|
60
|
+
end
|
61
|
+
rescue FakeServerThreadCancelled
|
62
|
+
# going down
|
63
|
+
ensure
|
64
|
+
@sock.close
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def stop
|
70
|
+
@thread.raise(FakeServerThreadCancelled)
|
71
|
+
@thread.join
|
72
|
+
@thread = nil
|
73
|
+
|
74
|
+
@clients.each do |c|
|
75
|
+
c.stop
|
76
|
+
end
|
77
|
+
@clients = nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def clients
|
81
|
+
@clients.reject {|c| c.closed}
|
82
|
+
end
|
83
|
+
|
84
|
+
def messages
|
85
|
+
clients.map {|c| c.messages}.flatten(1)
|
86
|
+
end
|
87
|
+
|
88
|
+
def send_message(m)
|
89
|
+
s = m.to_json
|
90
|
+
l = "%06u" % s.length
|
91
|
+
|
92
|
+
msg = l + s
|
93
|
+
|
94
|
+
clients.each do |c|
|
95
|
+
c.send_message(msg)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Client
|
101
|
+
attr_reader :closed, :responder, :port, :hears, :speaks
|
102
|
+
|
103
|
+
def initialize(client_socket)
|
104
|
+
@sock = client_socket
|
105
|
+
@client_host = @sock.peeraddr[2]
|
106
|
+
@queue = Queue.new
|
107
|
+
end
|
108
|
+
|
109
|
+
def start
|
110
|
+
@thread = Thread.new do |t|
|
111
|
+
begin
|
112
|
+
read_register_msg
|
113
|
+
@responder = ClientResponder.new(@client_host, @port)
|
114
|
+
|
115
|
+
loop do
|
116
|
+
# Ignoring bad message.
|
117
|
+
#
|
118
|
+
# It seems the order in which sockets get shut down are a little
|
119
|
+
# weird. The following two checks give us a means to try and bail
|
120
|
+
# out in the circumstance that a socket dies. In that case, it
|
121
|
+
# *should* have been shut down and we're probably just spinning
|
122
|
+
# until the exception finally bubbles up.
|
123
|
+
if (len = @sock.read(6)) == ""
|
124
|
+
next
|
125
|
+
end
|
126
|
+
if (str = @sock.read(len.to_i)) == ""
|
127
|
+
next
|
128
|
+
end
|
129
|
+
|
130
|
+
msg = JSON.parse(str)
|
131
|
+
@queue.push(msg)
|
132
|
+
end
|
133
|
+
rescue FakeServerThreadCancelled
|
134
|
+
# going down
|
135
|
+
@closed = true
|
136
|
+
@responder.stop
|
137
|
+
ensure
|
138
|
+
@sock.close
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def stop
|
144
|
+
@thread.raise(FakeServerThreadCancelled)
|
145
|
+
@thread.join
|
146
|
+
end
|
147
|
+
|
148
|
+
def messages
|
149
|
+
@queue.length.times.map { @queue.pop }
|
150
|
+
end
|
151
|
+
|
152
|
+
def send_message(m)
|
153
|
+
@responder.send_message(m)
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def read_register_msg
|
159
|
+
len = @sock.read(6)
|
160
|
+
m = JSON.parse(@sock.read(len.to_i))
|
161
|
+
txt, _, @port, @hears, @speaks, _, ver = m
|
162
|
+
|
163
|
+
unless txt == "register"
|
164
|
+
raise UnexpectedRegisterText.new(txt)
|
165
|
+
end
|
166
|
+
|
167
|
+
unless ver == Noam::VERSION
|
168
|
+
raise UnexpectedSystemVersion.new(ver)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class ClientResponder
|
174
|
+
def initialize(host, port)
|
175
|
+
@sock = TCPSocket.new(host, port)
|
176
|
+
end
|
177
|
+
|
178
|
+
def send_message(m)
|
179
|
+
@sock.write(m)
|
180
|
+
@sock.flush
|
181
|
+
end
|
182
|
+
|
183
|
+
def stop
|
184
|
+
@sock.close
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|