coronet 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Coronet.gemspec +1 -1
- data/README.md +43 -24
- data/Rakefile +6 -0
- data/lib/coronet.rb +2 -2
- data/lib/coronet/listener.rb +5 -9
- data/lib/coronet/mediator.rb +59 -33
- data/lib/coronet/message_format/xml_message_format.rb +7 -3
- data/lib/coronet/protocol.rb +10 -5
- data/lib/coronet/support/echo_server.rb +1 -0
- data/lib/coronet/support/request_reply_server.rb +29 -0
- data/lib/coronet/transport_mechanism/base.rb +3 -13
- data/lib/coronet/transport_mechanism/length_prefixed_tcp_transport.rb +12 -19
- data/lib/coronet/version.rb +3 -0
- data/spec/coronet/listener.spec +2 -2
- data/spec/coronet/mediator.spec +106 -44
- data/spec/coronet/message_format/base.spec +2 -2
- data/spec/coronet/protocol.spec +1 -1
- data/spec/coronet/transport_mechanism/base.spec +4 -2
- data/test/example.rb +14 -0
- metadata +5 -5
- data/lib/Coronet/version.rb +0 -3
- data/lib/coronet/transformation_rule.rb +0 -16
- data/spec/coronet/transformation_rule.spec +0 -29
data/Coronet.gemspec
CHANGED
data/README.md
CHANGED
@@ -20,7 +20,7 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
Coronet requires the definition of message formats, transports, service entry/end-points and mediation
|
23
|
+
Coronet requires the definition of message formats, transports, service entry/end-points and mediation patterns. Once these are defined, it is straightforward to construct a message-transformation and mediation service using Coronet.
|
24
24
|
|
25
25
|
### Message Formats
|
26
26
|
|
@@ -43,11 +43,6 @@ Eventually there should be mappers which can transform hash keys.
|
|
43
43
|
end
|
44
44
|
|
45
45
|
|
46
|
-
### Transformation Rules
|
47
|
-
|
48
|
-
*Transformation rules* adapt one message format to another. Eventually this may support
|
49
|
-
manipulation/mapping of key names.
|
50
|
-
|
51
46
|
### Transport Mechanisms
|
52
47
|
|
53
48
|
*Transport mechanisms* encapsulate functional requirements for message transport to
|
@@ -75,27 +70,51 @@ being transformed, transported to remote endpoints, the responses gathered,
|
|
75
70
|
transformation rules applied, and the initiating actor (client) being sent
|
76
71
|
the transformed response.
|
77
72
|
|
78
|
-
##
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
73
|
+
## Examples
|
74
|
+
|
75
|
+
Specifying explicit constructors for clarity, here is perhaps the most verbose
|
76
|
+
way to setup a mediation framework with Coronet. The example below starts a mediation service
|
77
|
+
listening on $mediation_port for XML messages over binary-length-prefixed TCP,
|
78
|
+
transforms these messages to YAML, and mediates them to a remote host listening
|
79
|
+
at $host_port.
|
80
|
+
|
81
|
+
class SimpleMediator < Mediator
|
82
|
+
with_listener Listener.new($mediator_port,
|
83
|
+
Protocol.new(
|
84
|
+
MessageFormat::XmlMessageFormat.new,
|
85
|
+
TransportMechanism::LengthPrefixedTcpTransport.new))
|
86
|
+
|
87
|
+
for_endpoint RemoteEndpoint.new('localhost', $host_port,
|
88
|
+
Protocol.new(
|
89
|
+
MessageFormat::YamlMessageFormat.new,
|
90
|
+
TransportMechanism::LengthPrefixedTcpTransport.new))
|
91
|
+
end
|
92
|
+
|
93
|
+
# to launch the service, just call the class method 'start_listening'
|
94
|
+
SimpleMediator.start_listening
|
85
95
|
|
86
|
-
|
87
|
-
|
88
|
-
yml = Coronet::MessageFormat::YamlMessageFormat.new
|
96
|
+
The following example makes fuller use of the built-in DSL, and is accordingly
|
97
|
+
much less verbose. The same mediation service is created:
|
89
98
|
|
90
|
-
|
91
|
-
|
92
|
-
|
99
|
+
class SimpleMediatorUsingDSL < Mediator
|
100
|
+
listener $mediator_port, xml_via_tcp
|
101
|
+
endpoint 'localhost', $host_port, yaml_via_tcp
|
102
|
+
end
|
103
|
+
|
104
|
+
You can provide custom processing instructions to the mediation framework. For
|
105
|
+
instance, you might want to log every request/response pattern to the database;
|
106
|
+
or simply keep track of how many messages you've processed. Here is an example
|
107
|
+
of utilizing these callbacks:
|
108
|
+
|
109
|
+
class SimpleMediatorWithCallbacks < SimpleMediatorUsingDSL
|
110
|
+
preprocess do |req|
|
111
|
+
# do something with request object 'req'
|
112
|
+
end
|
113
|
+
|
114
|
+
postprocess do |req, rsp|
|
115
|
+
# do something with request and response objects 'req' and 'rsp'
|
116
|
+
end
|
93
117
|
end
|
94
|
-
|
95
|
-
mediator.start
|
96
|
-
|
97
|
-
|
98
|
-
|
99
118
|
|
100
119
|
## Contributing
|
101
120
|
|
data/Rakefile
CHANGED
data/lib/coronet.rb
CHANGED
data/lib/coronet/listener.rb
CHANGED
@@ -2,24 +2,20 @@ module Coronet
|
|
2
2
|
class Listener < GServer
|
3
3
|
attr_accessor :port
|
4
4
|
attr_accessor :protocol
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :mediator_klass
|
6
6
|
|
7
|
-
def initialize(port, protocol
|
7
|
+
def initialize(port, protocol) #, mediator_klass) #callback=nil)
|
8
8
|
@port = port
|
9
9
|
@protocol = protocol
|
10
|
-
@callback = callback
|
11
|
-
|
12
|
-
# start listening on port
|
13
10
|
super(port)
|
14
11
|
end
|
15
12
|
|
13
|
+
def uses_mediator_class(mediator_klass); @mediator_klass = mediator_klass; end
|
14
|
+
|
16
15
|
def serve(io)
|
17
16
|
request = @protocol.read(io)
|
18
|
-
|
19
|
-
response = callback.call(request)
|
20
|
-
puts "--- listener got response: #{response}"
|
17
|
+
response = @mediator_klass.handle(request)
|
21
18
|
@protocol.write(response, io)
|
22
|
-
# io.close
|
23
19
|
end
|
24
20
|
end
|
25
21
|
end
|
data/lib/coronet/mediator.rb
CHANGED
@@ -1,43 +1,69 @@
|
|
1
1
|
module Coronet
|
2
2
|
class Mediator
|
3
|
-
attr_accessor :listener, :remote_endpoint
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def using_endpoint(remote_endpoint)
|
19
|
-
@remote_endpoint = remote_endpoint
|
20
|
-
self
|
4
|
+
# proxy start/stop to dedicated listener
|
5
|
+
def self.start_listener; @@listener.start; end
|
6
|
+
def self.stop_listener; @@listener.stop; end
|
7
|
+
def self.listen(&block)
|
8
|
+
unless block_given?
|
9
|
+
start_listener
|
10
|
+
else
|
11
|
+
start_listener
|
12
|
+
block.call
|
13
|
+
stop_listener
|
14
|
+
end
|
21
15
|
end
|
22
16
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
17
|
+
def self.handle(request)
|
18
|
+
if defined? @@preprocess_handler
|
19
|
+
@@preprocess_handler.call(request)
|
20
|
+
end
|
21
|
+
|
22
|
+
response = @@remote_endpoint.transmit(request)
|
23
|
+
|
24
|
+
if defined? @@postprocess_handler
|
25
|
+
@@postprocess_handler.call(request, response)
|
26
|
+
end
|
27
|
+
|
28
|
+
return response
|
33
29
|
end
|
34
|
-
|
35
|
-
# proxy start/stop to listener
|
36
|
-
def start; @listener.start; end
|
37
|
-
def stop; @listener.stop; end
|
38
30
|
|
39
|
-
|
40
|
-
|
31
|
+
# DSL support
|
32
|
+
class << self
|
33
|
+
# callbacks
|
34
|
+
def preprocess(&block); puts "--- pre-handler assigned"; @@preprocess_handler = block; end
|
35
|
+
def postprocess(&block); puts "--- post-handler assigned"; @@postprocess_handler = block; end
|
36
|
+
|
37
|
+
# mediation config
|
38
|
+
def with_listener(listener)
|
39
|
+
@@listener = listener
|
40
|
+
@@listener.uses_mediator_class(self)
|
41
|
+
end
|
42
|
+
|
43
|
+
def listener(port, proto)
|
44
|
+
with_listener(Listener.new(port, proto))
|
45
|
+
end
|
46
|
+
|
47
|
+
def for_endpoint(remote_endpoint)
|
48
|
+
@@remote_endpoint = remote_endpoint
|
49
|
+
end
|
50
|
+
|
51
|
+
def endpoint(host, port, proto)
|
52
|
+
for_endpoint(RemoteEndpoint.new(host, port, proto))
|
53
|
+
end
|
54
|
+
|
55
|
+
# message formats
|
56
|
+
def yaml; MessageFormat::YamlMessageFormat.new; end
|
57
|
+
def xml; MessageFormat::XmlMessageFormat.new; end
|
58
|
+
|
59
|
+
# xport
|
60
|
+
def length_prefixed_tcp; TransportMechanism::LengthPrefixedTcpTransport.new; end
|
61
|
+
|
62
|
+
# protocol
|
63
|
+
def protocol(format, transport); Protocol.new(format, transport); end
|
64
|
+
|
65
|
+
def yaml_via_tcp; protocol(yaml, length_prefixed_tcp); end
|
66
|
+
def xml_via_tcp; protocol(xml, length_prefixed_tcp); end
|
41
67
|
end
|
42
68
|
|
43
69
|
end
|
@@ -3,12 +3,16 @@ module Coronet
|
|
3
3
|
class XmlMessageFormat < Base
|
4
4
|
# transform xml string to hash
|
5
5
|
def unpack(xml_str)
|
6
|
-
|
6
|
+
# puts "--- xml message format attempting to unpack: #{xml_str}"
|
7
|
+
unpacked = XmlSimple.xml_in(xml_str, forcearray: false, keeproot: true)
|
8
|
+
unpacked = unpacked['opt'] if unpacked.has_key? 'opt'
|
9
|
+
# puts "--- unpacked: #{unpacked}"
|
10
|
+
unpacked
|
7
11
|
end
|
8
12
|
|
9
13
|
# transform hash to xml string
|
10
|
-
def pack(hash)
|
11
|
-
XmlSimple.xml_out(hash, noattr: true, rootname:
|
14
|
+
def pack(hash, root='opt')
|
15
|
+
XmlSimple.xml_out(hash, noattr: true, rootname: root).strip!
|
12
16
|
end
|
13
17
|
end
|
14
18
|
end
|
data/lib/coronet/protocol.rb
CHANGED
@@ -9,21 +9,26 @@ module Coronet
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def read(io)
|
12
|
-
packed =
|
13
|
-
unpacked =
|
14
|
-
|
12
|
+
# packed =
|
13
|
+
# unpacked =
|
14
|
+
@message_format.unpack(@transport_mechanism.read(io))
|
15
|
+
# unpacked
|
15
16
|
end
|
16
17
|
|
17
18
|
def write(data, io)
|
18
|
-
|
19
|
-
@transport_mechanism.write(packed, io)
|
19
|
+
@transport_mechanism.write(@message_format.pack(data), io)
|
20
20
|
end
|
21
21
|
|
22
22
|
def transmit(request, host, port)
|
23
|
+
# puts "=== opening connection to #{host}:#{port}"
|
23
24
|
io = @transport_mechanism.open(host,port)
|
25
|
+
# puts "--- writing #{request} to #{host}:#{port}"
|
24
26
|
write(request, io)
|
27
|
+
# puts "=== reading response from #{host}:#{port}"
|
25
28
|
response = read(io)
|
29
|
+
# puts "--- closing socket to #{host}:#{port}"
|
26
30
|
@transport_mechanism.close(io)
|
31
|
+
# puts "=== returning response #{response} from #{host}:#{port}"
|
27
32
|
response
|
28
33
|
end
|
29
34
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Coronet
|
2
|
+
module Support
|
3
|
+
|
4
|
+
class RequestReplyServer < GServer
|
5
|
+
def initialize(port=12345, format=MessageFormat::YamlMessageFormat.new, *args)
|
6
|
+
super(port, *args)
|
7
|
+
@tcp = TransportMechanism::LengthPrefixedTcpTransport.new
|
8
|
+
@format = format
|
9
|
+
@count = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def serve(io)
|
13
|
+
packed_request = @tcp.read(io)
|
14
|
+
request = @format.unpack(packed_request)
|
15
|
+
response = handle(request)
|
16
|
+
packed_response = @format.pack(response)
|
17
|
+
@tcp.write(packed_response, io)
|
18
|
+
end
|
19
|
+
|
20
|
+
def handle(request)
|
21
|
+
@count += 1
|
22
|
+
# puts "--- mock host handling request #{@count}: #{request}"
|
23
|
+
request['hello'] = 'client' if request.has_key? 'hello'
|
24
|
+
request
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -4,24 +4,14 @@ module Coronet
|
|
4
4
|
include Contractual::Interface
|
5
5
|
|
6
6
|
must :open, :host, :port
|
7
|
-
must :write, :data
|
8
|
-
must :read
|
9
|
-
must :close
|
10
|
-
|
11
|
-
# attr_accessor :host, :port
|
12
|
-
# attr_accessor :io
|
13
|
-
|
14
|
-
# def initialize #(host, port)
|
15
|
-
# @host = host
|
16
|
-
# @port = port
|
17
|
-
# end
|
7
|
+
must :write, :data, :io
|
8
|
+
must :read, :io
|
9
|
+
must :close, :io
|
18
10
|
|
19
11
|
def transmit(data, io)
|
20
|
-
# io = open(host, port)
|
21
12
|
write(data, io)
|
22
13
|
response = read(io)
|
23
14
|
close(io)
|
24
|
-
|
25
15
|
response
|
26
16
|
end
|
27
17
|
end
|
@@ -8,21 +8,25 @@ module Coronet
|
|
8
8
|
class LengthPrefixedTcpTransport < Base
|
9
9
|
attr_accessor :tcp_socket
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
# n.b., for four bytes, can just use 4/'N'
|
12
|
+
LENGTH_HEADER_BYTES = 2
|
13
|
+
LENGTH_HEADER_STORAGE_CLASS = "n"
|
14
|
+
|
15
|
+
def open(host, port); TCPSocket.open(host, port); end
|
14
16
|
|
15
17
|
def read(io)
|
16
|
-
length_header = io.read(
|
17
|
-
p length_header
|
18
|
-
length = length_header.unpack(
|
18
|
+
length_header = io.read(LENGTH_HEADER_BYTES)
|
19
|
+
# p length_header
|
20
|
+
length = length_header.unpack(LENGTH_HEADER_STORAGE_CLASS).first
|
21
|
+
# puts "--- TCP READ #{length}"
|
22
|
+
|
19
23
|
io.read(length)
|
20
24
|
end
|
21
25
|
|
22
26
|
def write(data, io)
|
27
|
+
# puts "--- TCP WRITE #{data}"
|
23
28
|
length = data.size
|
24
|
-
prefix =
|
25
|
-
|
29
|
+
prefix = [length].pack(LENGTH_HEADER_STORAGE_CLASS)
|
26
30
|
io.print(prefix)
|
27
31
|
io.print(data)
|
28
32
|
end
|
@@ -30,17 +34,6 @@ module Coronet
|
|
30
34
|
def close(io)
|
31
35
|
io.close
|
32
36
|
end
|
33
|
-
|
34
|
-
private
|
35
|
-
def to_byte_array(num)
|
36
|
-
result = Array.new
|
37
|
-
begin
|
38
|
-
result << (num & 0xff)
|
39
|
-
num >>= 8
|
40
|
-
end until (num == 0 || num == -1) && (result.last[7] == num[7])
|
41
|
-
result.reverse
|
42
|
-
end
|
43
|
-
|
44
37
|
end
|
45
38
|
end
|
46
39
|
end
|
data/spec/coronet/listener.spec
CHANGED
@@ -17,7 +17,6 @@ module Coronet
|
|
17
17
|
|
18
18
|
module Echo
|
19
19
|
def self.handle(request)
|
20
|
-
# puts "--- echo server handling request: #{request}"
|
21
20
|
request
|
22
21
|
end
|
23
22
|
end
|
@@ -28,7 +27,8 @@ module Coronet
|
|
28
27
|
xml = MessageFormat::XmlMessageFormat.new
|
29
28
|
xml_via_tcp = Protocol.new(xml, tcp)
|
30
29
|
|
31
|
-
echo_listener = Listener.new(12345, xml_via_tcp
|
30
|
+
echo_listener = Listener.new(12345, xml_via_tcp)
|
31
|
+
echo_listener.uses_mediator_class(Echo)
|
32
32
|
echo_listener.start
|
33
33
|
|
34
34
|
msg = { 'hello' => 'world' }
|
data/spec/coronet/mediator.spec
CHANGED
@@ -3,7 +3,7 @@ require 'gserver'
|
|
3
3
|
require 'contractual'
|
4
4
|
require 'xmlsimple'
|
5
5
|
|
6
|
-
require 'coronet/support/
|
6
|
+
require 'coronet/support/request_reply_server'
|
7
7
|
|
8
8
|
require 'coronet/message_format/base'
|
9
9
|
require 'coronet/message_format/xml_message_format'
|
@@ -14,68 +14,130 @@ require 'coronet/transport_mechanism/length_prefixed_tcp_transport'
|
|
14
14
|
|
15
15
|
require 'coronet/protocol'
|
16
16
|
require 'coronet/listener'
|
17
|
-
require 'coronet/transformation_rule'
|
18
17
|
require 'coronet/remote_endpoint'
|
19
18
|
|
20
19
|
require 'coronet/mediator'
|
21
20
|
|
22
21
|
module Coronet
|
23
22
|
|
23
|
+
include TransportMechanism
|
24
|
+
include MessageFormat
|
25
|
+
include Support
|
26
|
+
|
27
|
+
$mediator_port, $host_port = 10000, 10001
|
28
|
+
|
24
29
|
describe Mediator, "mediates between clients and servers" do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
tcp = TransportMechanism::LengthPrefixedTcpTransport.new
|
29
|
-
|
30
|
-
xml = MessageFormat::XmlMessageFormat.new
|
31
|
-
yml = MessageFormat::YamlMessageFormat.new
|
32
|
-
|
33
|
-
xml_via_tcp = Protocol.new(xml, tcp)
|
34
|
-
yml_via_tcp = Protocol.new(yml, tcp)
|
35
|
-
|
36
|
-
xml_to_yml = TransformationRule.new(xml, yml)
|
37
|
-
|
38
|
-
listener = Listener.new(10000, xml_via_tcp)
|
39
|
-
|
40
|
-
echo_server = Support::EchoServer.new(10001)
|
41
|
-
echo_server_endpoint = RemoteEndpoint.new('localhost', 10001, yml_via_tcp)
|
42
|
-
|
43
|
-
mediator = Mediator.new listener: listener, endpoint: echo_server_endpoint # , xml_to_yml)
|
44
|
-
|
45
|
-
echo_server.start
|
46
|
-
mediator.start
|
47
|
-
|
48
|
-
msg = { 'hello' => 'world' }
|
49
|
-
xml_via_tcp.transmit(msg, 'localhost', 10000).should == msg
|
30
|
+
|
31
|
+
before :each do
|
32
|
+
@xml_over_tcp = Protocol.new(XmlMessageFormat.new, LengthPrefixedTcpTransport.new)
|
50
33
|
|
51
|
-
|
52
|
-
|
34
|
+
@request = { 'hello' => 'server' }
|
35
|
+
@expected_response = { 'hello' => 'client' }
|
53
36
|
end
|
54
37
|
|
55
|
-
|
38
|
+
# after :each do
|
39
|
+
# end
|
40
|
+
|
41
|
+
it "adapts protocols" do
|
56
42
|
|
57
|
-
|
58
|
-
|
59
|
-
|
43
|
+
class SimpleMediator < Mediator
|
44
|
+
with_listener Listener.new($mediator_port,
|
45
|
+
Protocol.new(
|
46
|
+
MessageFormat::XmlMessageFormat.new,
|
47
|
+
TransportMechanism::LengthPrefixedTcpTransport.new))
|
48
|
+
|
49
|
+
for_endpoint RemoteEndpoint.new('localhost', $host_port,
|
50
|
+
Protocol.new(
|
51
|
+
MessageFormat::YamlMessageFormat.new,
|
52
|
+
TransportMechanism::LengthPrefixedTcpTransport.new))
|
53
|
+
end
|
60
54
|
|
61
|
-
|
62
|
-
|
63
|
-
|
55
|
+
host = RequestReplyServer.new($host_port, YamlMessageFormat.new)
|
56
|
+
host.start
|
57
|
+
SimpleMediator.listen do
|
58
|
+
|
59
|
+
@xml_over_tcp.transmit(@request, 'localhost', $mediator_port).should == @expected_response
|
64
60
|
end
|
61
|
+
host.stop
|
62
|
+
end
|
63
|
+
|
64
|
+
it "supports a simple DSL" do
|
65
65
|
|
66
|
-
|
66
|
+
class SimpleMediatorUsingDSL < Mediator
|
67
|
+
listener $mediator_port, xml_via_tcp
|
68
|
+
endpoint 'localhost', $host_port, yaml_via_tcp
|
69
|
+
end
|
67
70
|
|
68
|
-
|
69
|
-
|
71
|
+
host = RequestReplyServer.new($host_port, YamlMessageFormat.new)
|
72
|
+
host.start
|
70
73
|
|
71
|
-
|
72
|
-
|
74
|
+
SimpleMediatorUsingDSL.listen do
|
75
|
+
@xml_over_tcp.transmit(@request, 'localhost', $mediator_port).should == @expected_response
|
76
|
+
end
|
77
|
+
host.stop
|
78
|
+
end
|
79
|
+
|
80
|
+
it "handles callbacks" do
|
73
81
|
|
74
|
-
|
82
|
+
|
83
|
+
$preprocess_invoked, $postprocess_invoked = false, false
|
84
|
+
class SimpleMediatorWithCallbacks < SimpleMediatorUsingDSL
|
85
|
+
preprocess do |req|
|
86
|
+
$preprocess_invoked = true
|
87
|
+
end
|
88
|
+
|
89
|
+
postprocess do |req, rsp|
|
90
|
+
$postprocess_invoked = true
|
91
|
+
end
|
92
|
+
end
|
75
93
|
|
76
|
-
|
77
|
-
|
94
|
+
host = RequestReplyServer.new($host_port, YamlMessageFormat.new)
|
95
|
+
host.start
|
96
|
+
SimpleMediatorWithCallbacks.listen do
|
97
|
+
@xml_over_tcp.transmit(@request, 'localhost', $mediator_port).should == @expected_response
|
98
|
+
end
|
99
|
+
host.stop
|
100
|
+
$preprocess_invoked.should == true
|
101
|
+
$postprocess_invoked.should == true
|
102
|
+
end
|
103
|
+
|
104
|
+
it "supports concurrent request handling" do
|
78
105
|
|
106
|
+
class SimpleMediatorWithLogging < SimpleMediatorUsingDSL
|
107
|
+
postprocess do |req, rsp|
|
108
|
+
# puts "--- request #{req} got response #{rsp}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
host = RequestReplyServer.new($host_port, YamlMessageFormat.new)
|
113
|
+
host.start
|
114
|
+
SimpleMediatorWithLogging.listen do
|
115
|
+
|
116
|
+
|
117
|
+
client_count = 2
|
118
|
+
message_count = 3
|
119
|
+
|
120
|
+
clients = []
|
121
|
+
(1..client_count).each do |n|
|
122
|
+
client = Thread.new do
|
123
|
+
message_count.times do |index|
|
124
|
+
msg = { 'hello' => 'server', 'client' => n, 'index' => index }
|
125
|
+
xml_over_tcp = Protocol.new(XmlMessageFormat.new, LengthPrefixedTcpTransport.new)
|
126
|
+
# puts "--- client #{n} about to transmit message #{msg}"
|
127
|
+
response = xml_over_tcp.transmit(msg, 'localhost', $mediator_port)
|
128
|
+
# puts "--- client #{n} got response #{response}"
|
129
|
+
response['hello'].should == 'client'
|
130
|
+
response['client'].to_i.should == n
|
131
|
+
response['index'].to_i.should == index
|
132
|
+
sleep 0.1
|
133
|
+
end
|
134
|
+
end
|
135
|
+
clients << client
|
136
|
+
|
137
|
+
end
|
138
|
+
clients.each { |client| client.join }
|
139
|
+
end
|
140
|
+
host.stop
|
79
141
|
end
|
80
142
|
end
|
81
143
|
end
|
@@ -22,12 +22,12 @@ module Coronet
|
|
22
22
|
|
23
23
|
it "should handle xml" do
|
24
24
|
@xml.unpack(@xml_data).should == { 'hello' => 'world' }
|
25
|
-
@xml.pack(@xml.unpack(@xml_data)).should == @xml_data
|
25
|
+
@xml.pack(@xml.unpack(@xml_data), nil).should == @xml_data
|
26
26
|
end
|
27
27
|
|
28
28
|
it "should handle transforming yml to xml (and vice versa)" do
|
29
29
|
@xml.unpack(@xml_data).should == @yml.unpack(@yml_data)
|
30
|
-
@xml.pack(@yml.unpack(@yml_data)).should == @xml_data
|
30
|
+
@xml.pack(@yml.unpack(@yml_data), nil).should == @xml_data
|
31
31
|
@yml.pack(@xml.unpack(@xml_data)).should == @yml_data
|
32
32
|
end
|
33
33
|
end
|
data/spec/coronet/protocol.spec
CHANGED
@@ -22,7 +22,7 @@ module Coronet
|
|
22
22
|
xml = MessageFormat::XmlMessageFormat.new
|
23
23
|
xml_via_tcp = Protocol.new(xml, tcp)
|
24
24
|
|
25
|
-
msg = { 'hello' => 'world' }
|
25
|
+
msg = { 'hello' => 'world', 'whats' => 'up' }
|
26
26
|
xml_via_tcp.transmit(msg, 'localhost', 12345).should == msg
|
27
27
|
|
28
28
|
echo.stop
|
@@ -12,11 +12,13 @@ module Coronet
|
|
12
12
|
describe Base, "encapsulates transport-layer functionality" do
|
13
13
|
it "supports interaction with remote services" do
|
14
14
|
echo = Support::EchoServer.new(12345)
|
15
|
-
tcp = LengthPrefixedTcpTransport.new
|
15
|
+
tcp = LengthPrefixedTcpTransport.new
|
16
16
|
|
17
17
|
echo.start
|
18
18
|
io = tcp.open('localhost', 12345)
|
19
|
-
|
19
|
+
msg = "data" *1250
|
20
|
+
# p msg
|
21
|
+
tcp.transmit(msg, io).should == msg
|
20
22
|
echo.stop
|
21
23
|
end
|
22
24
|
end
|
data/test/example.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'coronet'
|
2
|
+
|
3
|
+
tcp = Coronet::TransportMechanism::LengthPrefixedTcpTransport.new
|
4
|
+
xml = Coronet::MessageFormat::XmlMessageFormat.new
|
5
|
+
yml = Coronet::MessageFormat::YamlMessageFormat.new
|
6
|
+
|
7
|
+
|
8
|
+
#
|
9
|
+
# mediator = Coronet::Mediator.new do
|
10
|
+
# local xml, tcp, 10000
|
11
|
+
# remote yml, tcp, 'localhost', 10001
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# mediator.start
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coronet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-27 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Coronet is a simple protocol adaption framework
|
15
15
|
email:
|
@@ -24,7 +24,6 @@ files:
|
|
24
24
|
- LICENSE
|
25
25
|
- README.md
|
26
26
|
- Rakefile
|
27
|
-
- lib/Coronet/version.rb
|
28
27
|
- lib/coronet.rb
|
29
28
|
- lib/coronet/listener.rb
|
30
29
|
- lib/coronet/mediator.rb
|
@@ -34,17 +33,18 @@ files:
|
|
34
33
|
- lib/coronet/protocol.rb
|
35
34
|
- lib/coronet/remote_endpoint.rb
|
36
35
|
- lib/coronet/support/echo_server.rb
|
37
|
-
- lib/coronet/
|
36
|
+
- lib/coronet/support/request_reply_server.rb
|
38
37
|
- lib/coronet/transport_mechanism/base.rb
|
39
38
|
- lib/coronet/transport_mechanism/length_prefixed_tcp_transport.rb
|
39
|
+
- lib/coronet/version.rb
|
40
40
|
- spec/coronet/listener.spec
|
41
41
|
- spec/coronet/mediator.spec
|
42
42
|
- spec/coronet/message_format/base.spec
|
43
43
|
- spec/coronet/protocol.spec
|
44
44
|
- spec/coronet/remote_endpoint.spec
|
45
|
-
- spec/coronet/transformation_rule.spec
|
46
45
|
- spec/coronet/transport_mechanism/base.spec
|
47
46
|
- spec/coronet_spec.rb
|
47
|
+
- test/example.rb
|
48
48
|
homepage:
|
49
49
|
licenses: []
|
50
50
|
post_install_message:
|
data/lib/Coronet/version.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
module Coronet
|
2
|
-
class TransformationRule
|
3
|
-
attr_accessor :in, :out
|
4
|
-
|
5
|
-
def initialize(incoming, outgoing)
|
6
|
-
@in = incoming
|
7
|
-
@out = outgoing
|
8
|
-
end
|
9
|
-
|
10
|
-
def apply(message)
|
11
|
-
@in.transform(message, @out)
|
12
|
-
end
|
13
|
-
|
14
|
-
def inverse; TransformationRule.new(@out, @in); end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'contractual'
|
2
|
-
require 'xmlsimple'
|
3
|
-
require 'psych'
|
4
|
-
|
5
|
-
require 'coronet/message_format/base'
|
6
|
-
require 'coronet/message_format/xml_message_format'
|
7
|
-
require 'coronet/message_format/yaml_message_format'
|
8
|
-
|
9
|
-
require 'coronet/transformation_rule'
|
10
|
-
|
11
|
-
module Coronet
|
12
|
-
describe TransformationRule, "transforms messages into other formats" do
|
13
|
-
before :each do
|
14
|
-
@yml, @xml = MessageFormat::YamlMessageFormat.new, MessageFormat::XmlMessageFormat.new
|
15
|
-
@yml_data = "---\nhello: world\n"
|
16
|
-
@xml_data = "<hello>world</hello>"
|
17
|
-
end
|
18
|
-
|
19
|
-
it "transforms xml to yml" do
|
20
|
-
rule = TransformationRule.new(@xml, @yml)
|
21
|
-
rule.apply(@xml_data).should == @yml_data
|
22
|
-
end
|
23
|
-
|
24
|
-
it "transforms yml to xml" do
|
25
|
-
rule = TransformationRule.new(@yml, @xml)
|
26
|
-
rule.apply(@yml_data).should == @xml_data
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|