coronet 0.0.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.
- data/.gitignore +17 -0
- data/Coronet.gemspec +17 -0
- data/Gemfile +13 -0
- data/LICENSE +22 -0
- data/README.md +106 -0
- data/Rakefile +2 -0
- data/lib/Coronet/version.rb +3 -0
- data/lib/coronet/listener.rb +25 -0
- data/lib/coronet/mediator.rb +44 -0
- data/lib/coronet/message_format/base.rb +17 -0
- data/lib/coronet/message_format/xml_message_format.rb +15 -0
- data/lib/coronet/message_format/yaml_message_format.rb +18 -0
- data/lib/coronet/protocol.rb +30 -0
- data/lib/coronet/remote_endpoint.rb +16 -0
- data/lib/coronet/support/echo_server.rb +15 -0
- data/lib/coronet/transformation_rule.rb +16 -0
- data/lib/coronet/transport_mechanism/base.rb +29 -0
- data/lib/coronet/transport_mechanism/length_prefixed_tcp_transport.rb +46 -0
- data/lib/coronet.rb +5 -0
- data/spec/coronet/listener.spec +40 -0
- data/spec/coronet/mediator.spec +81 -0
- data/spec/coronet/message_format/base.spec +35 -0
- data/spec/coronet/protocol.spec +31 -0
- data/spec/coronet/remote_endpoint.spec +36 -0
- data/spec/coronet/transformation_rule.spec +29 -0
- data/spec/coronet/transport_mechanism/base.spec +24 -0
- data/spec/coronet_spec.rb +1 -0
- metadata +72 -0
data/.gitignore
ADDED
data/Coronet.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/Coronet/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Joseph Weissman"]
|
6
|
+
gem.email = ["jweissman1986@gmail.com"]
|
7
|
+
gem.description = %q{Coronet is a simple protocol adaption framework}
|
8
|
+
gem.summary = %q{Coronet is an extensible message-mediation server appliance.}
|
9
|
+
# gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
# gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "coronet"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Coronet::VERSION
|
17
|
+
end
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 TODO: Write your name
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# Coronet
|
2
|
+
|
3
|
+
Coronet is a dynamically-reconfigurable message-mediation (transformation) server appliance.
|
4
|
+
|
5
|
+
(A 'coronet' is a small, simple crown -- possibly made with grass or leaves.)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'coronet'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install coronet
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Coronet requires the definition of message formats, transports, service entry/end-points and mediation rules. Once these are defined, you can construct 'service layers' which automatically mediate messages.
|
24
|
+
|
25
|
+
### Message Formats
|
26
|
+
|
27
|
+
*Message formats* currently just have to implement 'pack' and 'unpack' functions.
|
28
|
+
|
29
|
+
Currently provided are a simple Yaml and XML message format specification.
|
30
|
+
|
31
|
+
Eventually there should be mappers which can transform hash keys.
|
32
|
+
|
33
|
+
class MyCustomMessageFormat < Coronet::MessageFormat
|
34
|
+
def pack(hash)
|
35
|
+
# pack logic goes here
|
36
|
+
# return binary data/string/whatever
|
37
|
+
end
|
38
|
+
|
39
|
+
def unpack(data)
|
40
|
+
# unpack business logic
|
41
|
+
# return hash of element names => values
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
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
|
+
### Transport Mechanisms
|
52
|
+
|
53
|
+
*Transport mechanisms* encapsulate functional requirements for message transport to
|
54
|
+
remote services.
|
55
|
+
|
56
|
+
Currently, transport mechanisms have to implement 'open', 'read', 'write(data)'
|
57
|
+
and 'close' methods. There is a simple length-prefixed TCP implementation provided.
|
58
|
+
I'd like to eventually support SSL (over TCP) and HTTP(S).
|
59
|
+
|
60
|
+
### Protocols
|
61
|
+
|
62
|
+
A *protocol* combines a particular transport mechanism and a message format.
|
63
|
+
|
64
|
+
### Listeners, Remote Endpoints and Mediators
|
65
|
+
|
66
|
+
*Listeners* are entrypoints into the mediating framework, and need to specify
|
67
|
+
their message format, transport mechanism, and local listening port.
|
68
|
+
|
69
|
+
*Remote endpoints* are foreign service interfaces, which need to specify
|
70
|
+
the format and transport like a listener, but also need to specify the remote
|
71
|
+
address and port of the target host.
|
72
|
+
|
73
|
+
*Mediators* link these together into a concrete process resulting in requests
|
74
|
+
being transformed, transported to remote endpoints, the responses gathered,
|
75
|
+
transformation rules applied, and the initiating actor (client) being sent
|
76
|
+
the transformed response.
|
77
|
+
|
78
|
+
## Example
|
79
|
+
|
80
|
+
The following simple example should start the Coronet engine on localhost:10000,
|
81
|
+
listening for XML requests via TCP, and mediate the requests to localhost:10001
|
82
|
+
in YML over TCP.
|
83
|
+
|
84
|
+
require 'coronet'
|
85
|
+
|
86
|
+
tcp = Coronet::TransportMechanism::LengthPrefixedTcpTransport.new
|
87
|
+
xml = Coronet::MessageFormat::XmlMessageFormat.new
|
88
|
+
yml = Coronet::MessageFormat::YamlMessageFormat.new
|
89
|
+
|
90
|
+
mediator = Coronet::Mediator.new do
|
91
|
+
local xml, tcp, 10000
|
92
|
+
remote yml, tcp, 'localhost', 10001
|
93
|
+
end
|
94
|
+
|
95
|
+
mediator.start
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
## Contributing
|
101
|
+
|
102
|
+
1. Fork it
|
103
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
104
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
105
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
106
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Coronet
|
2
|
+
class Listener < GServer
|
3
|
+
attr_accessor :port
|
4
|
+
attr_accessor :protocol
|
5
|
+
attr_accessor :callback
|
6
|
+
|
7
|
+
def initialize(port, protocol, callback=nil)
|
8
|
+
@port = port
|
9
|
+
@protocol = protocol
|
10
|
+
@callback = callback
|
11
|
+
|
12
|
+
# start listening on port
|
13
|
+
super(port)
|
14
|
+
end
|
15
|
+
|
16
|
+
def serve(io)
|
17
|
+
request = @protocol.read(io)
|
18
|
+
puts "--- listener invoking callback with request: #{request}"
|
19
|
+
response = callback.call(request)
|
20
|
+
puts "--- listener got response: #{response}"
|
21
|
+
@protocol.write(response, io)
|
22
|
+
# io.close
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Coronet
|
2
|
+
class Mediator
|
3
|
+
attr_accessor :listener, :remote_endpoint
|
4
|
+
|
5
|
+
def initialize(opts={}, &block)
|
6
|
+
with_listener(opts[:listener]) if opts.has_key? :listener
|
7
|
+
using_endpoint(opts[:endpoint]) if opts.has_key? :endpoint
|
8
|
+
|
9
|
+
instance_eval &block if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_listener(listener)
|
13
|
+
@listener = listener
|
14
|
+
@listener.callback = method(:handle)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def using_endpoint(remote_endpoint)
|
19
|
+
@remote_endpoint = remote_endpoint
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def local(message_format, transport_mechanism, port)
|
24
|
+
protocol = Protocol.new(message_format, transport_mechanism)
|
25
|
+
listener = Listener.new(port, protocol)
|
26
|
+
with_listener(listener)
|
27
|
+
end
|
28
|
+
|
29
|
+
def remote(message_format, transport_mechanism, remote_host, remote_port)
|
30
|
+
protocol = Protocol.new(message_format, transport_mechanism)
|
31
|
+
endpoint = RemoteEndpoint.new(remote_host, remote_port, protocol)
|
32
|
+
using_endpoint(endpoint)
|
33
|
+
end
|
34
|
+
|
35
|
+
# proxy start/stop to listener
|
36
|
+
def start; @listener.start; end
|
37
|
+
def stop; @listener.stop; end
|
38
|
+
|
39
|
+
def handle(request)
|
40
|
+
@remote_endpoint.transmit(request)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Coronet
|
2
|
+
module MessageFormat
|
3
|
+
class Base
|
4
|
+
|
5
|
+
include Contractual::Interface
|
6
|
+
|
7
|
+
must :pack, :message
|
8
|
+
must :unpack, :message
|
9
|
+
|
10
|
+
def transform(message, outgoing_format)
|
11
|
+
unpacked = unpack(message)
|
12
|
+
outgoing_format.pack(unpacked)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Coronet
|
2
|
+
module MessageFormat
|
3
|
+
class XmlMessageFormat < Base
|
4
|
+
# transform xml string to hash
|
5
|
+
def unpack(xml_str)
|
6
|
+
XmlSimple.xml_in(xml_str, forcearray: false, keeproot: true)
|
7
|
+
end
|
8
|
+
|
9
|
+
# transform hash to xml string
|
10
|
+
def pack(hash)
|
11
|
+
XmlSimple.xml_out(hash, noattr: true, rootname: nil).strip!
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Coronet
|
2
|
+
module MessageFormat
|
3
|
+
class YamlMessageFormat < Base
|
4
|
+
|
5
|
+
# transform yml string to hash
|
6
|
+
def unpack(yml_str)
|
7
|
+
Psych.load(yml_str)
|
8
|
+
# YAML.load(yml_str)
|
9
|
+
end
|
10
|
+
|
11
|
+
# transform hash to yml string
|
12
|
+
def pack(hash)
|
13
|
+
yml_out = Psych.dump(hash) #.strip!
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Coronet
|
2
|
+
class Protocol
|
3
|
+
attr_accessor :message_format
|
4
|
+
attr_accessor :transport_mechanism
|
5
|
+
|
6
|
+
def initialize(message_format, transport_mechanism)
|
7
|
+
@message_format = message_format
|
8
|
+
@transport_mechanism = transport_mechanism
|
9
|
+
end
|
10
|
+
|
11
|
+
def read(io)
|
12
|
+
packed = @transport_mechanism.read(io)
|
13
|
+
unpacked = @message_format.unpack(packed)
|
14
|
+
unpacked
|
15
|
+
end
|
16
|
+
|
17
|
+
def write(data, io)
|
18
|
+
packed = @message_format.pack(data)
|
19
|
+
@transport_mechanism.write(packed, io)
|
20
|
+
end
|
21
|
+
|
22
|
+
def transmit(request, host, port)
|
23
|
+
io = @transport_mechanism.open(host,port)
|
24
|
+
write(request, io)
|
25
|
+
response = read(io)
|
26
|
+
@transport_mechanism.close(io)
|
27
|
+
response
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Coronet
|
2
|
+
class RemoteEndpoint
|
3
|
+
attr_accessor :host, :port
|
4
|
+
attr_accessor :protocol
|
5
|
+
|
6
|
+
def initialize(host, port, protocol)
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
@protocol = protocol
|
10
|
+
end
|
11
|
+
|
12
|
+
def transmit(request)
|
13
|
+
@protocol.transmit(request, @host, @port)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Coronet
|
2
|
+
module Support
|
3
|
+
|
4
|
+
class EchoServer < GServer
|
5
|
+
def initialize(port=12345, *args)
|
6
|
+
super(port, *args)
|
7
|
+
@tcp = TransportMechanism::LengthPrefixedTcpTransport.new
|
8
|
+
end
|
9
|
+
def serve(io)
|
10
|
+
@tcp.write(@tcp.read(io), io)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Coronet
|
2
|
+
module TransportMechanism
|
3
|
+
class Base
|
4
|
+
include Contractual::Interface
|
5
|
+
|
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
|
18
|
+
|
19
|
+
def transmit(data, io)
|
20
|
+
# io = open(host, port)
|
21
|
+
write(data, io)
|
22
|
+
response = read(io)
|
23
|
+
close(io)
|
24
|
+
|
25
|
+
response
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Coronet
|
2
|
+
module TransportMechanism
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# Supports length-prefixed TCP transport.
|
6
|
+
#
|
7
|
+
#
|
8
|
+
class LengthPrefixedTcpTransport < Base
|
9
|
+
attr_accessor :tcp_socket
|
10
|
+
|
11
|
+
def open(host, port)
|
12
|
+
TCPSocket.open(host, port)
|
13
|
+
end
|
14
|
+
|
15
|
+
def read(io)
|
16
|
+
length_header = io.read(2)
|
17
|
+
p length_header
|
18
|
+
length = length_header.unpack("S").first
|
19
|
+
io.read(length)
|
20
|
+
end
|
21
|
+
|
22
|
+
def write(data, io)
|
23
|
+
length = data.size
|
24
|
+
prefix = to_byte_array(length).pack("S")
|
25
|
+
|
26
|
+
io.print(prefix)
|
27
|
+
io.print(data)
|
28
|
+
end
|
29
|
+
|
30
|
+
def close(io)
|
31
|
+
io.close
|
32
|
+
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
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/coronet.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'gserver'
|
2
|
+
|
3
|
+
require 'contractual'
|
4
|
+
require 'xmlsimple'
|
5
|
+
|
6
|
+
require 'coronet/message_format/base'
|
7
|
+
require 'coronet/message_format/xml_message_format'
|
8
|
+
|
9
|
+
require 'coronet/transport_mechanism/base'
|
10
|
+
require 'coronet/transport_mechanism/length_prefixed_tcp_transport'
|
11
|
+
|
12
|
+
require 'coronet/protocol'
|
13
|
+
require 'coronet/listener'
|
14
|
+
|
15
|
+
module Coronet
|
16
|
+
describe Listener, "encapsulates an entrypoint into the mediating framework" do
|
17
|
+
|
18
|
+
module Echo
|
19
|
+
def self.handle(request)
|
20
|
+
# puts "--- echo server handling request: #{request}"
|
21
|
+
request
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "serves external requests and provides a callback for processing" do
|
26
|
+
|
27
|
+
tcp = TransportMechanism::LengthPrefixedTcpTransport.new
|
28
|
+
xml = MessageFormat::XmlMessageFormat.new
|
29
|
+
xml_via_tcp = Protocol.new(xml, tcp)
|
30
|
+
|
31
|
+
echo_listener = Listener.new(12345, xml_via_tcp, Echo.method(:handle))
|
32
|
+
echo_listener.start
|
33
|
+
|
34
|
+
msg = { 'hello' => 'world' }
|
35
|
+
xml_via_tcp.transmit(msg, 'localhost', 12345).should == msg
|
36
|
+
|
37
|
+
echo_listener.stop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'gserver'
|
2
|
+
|
3
|
+
require 'contractual'
|
4
|
+
require 'xmlsimple'
|
5
|
+
|
6
|
+
require 'coronet/support/echo_server'
|
7
|
+
|
8
|
+
require 'coronet/message_format/base'
|
9
|
+
require 'coronet/message_format/xml_message_format'
|
10
|
+
require 'coronet/message_format/yaml_message_format'
|
11
|
+
|
12
|
+
require 'coronet/transport_mechanism/base'
|
13
|
+
require 'coronet/transport_mechanism/length_prefixed_tcp_transport'
|
14
|
+
|
15
|
+
require 'coronet/protocol'
|
16
|
+
require 'coronet/listener'
|
17
|
+
require 'coronet/transformation_rule'
|
18
|
+
require 'coronet/remote_endpoint'
|
19
|
+
|
20
|
+
require 'coronet/mediator'
|
21
|
+
|
22
|
+
module Coronet
|
23
|
+
|
24
|
+
describe Mediator, "mediates between clients and servers" do
|
25
|
+
# it "mediates between client and server"
|
26
|
+
# it "transforms message formats"
|
27
|
+
it "adapts transport mechanisms and protocols" do
|
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
|
50
|
+
|
51
|
+
mediator.stop
|
52
|
+
echo_server.stop
|
53
|
+
end
|
54
|
+
|
55
|
+
it "supports a basic DSL" do
|
56
|
+
|
57
|
+
tcp = TransportMechanism::LengthPrefixedTcpTransport.new
|
58
|
+
xml = MessageFormat::XmlMessageFormat.new
|
59
|
+
yml = MessageFormat::YamlMessageFormat.new
|
60
|
+
|
61
|
+
mediator = Mediator.new do
|
62
|
+
local xml, tcp, 10000
|
63
|
+
remote yml, tcp, 'localhost', 10001
|
64
|
+
end
|
65
|
+
|
66
|
+
echo_server = Support::EchoServer.new(10001)
|
67
|
+
|
68
|
+
msg = { 'hello' => 'world' }
|
69
|
+
xml_via_tcp = Protocol.new(xml, tcp)
|
70
|
+
|
71
|
+
mediator.start
|
72
|
+
echo_server.start
|
73
|
+
|
74
|
+
xml_via_tcp.transmit(msg, 'localhost', 10000).should == msg
|
75
|
+
|
76
|
+
echo_server.stop
|
77
|
+
mediator.stop
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'contractual'
|
2
|
+
require 'xmlsimple'
|
3
|
+
|
4
|
+
require 'coronet/message_format/base'
|
5
|
+
require 'coronet/message_format/xml_message_format'
|
6
|
+
require 'coronet/message_format/yaml_message_format'
|
7
|
+
|
8
|
+
module Coronet
|
9
|
+
module MessageFormat
|
10
|
+
describe Base, "should describe structured message formats" do
|
11
|
+
|
12
|
+
before :each do
|
13
|
+
@yml, @xml = YamlMessageFormat.new, XmlMessageFormat.new
|
14
|
+
@yml_data = "---\nhello: world\n"
|
15
|
+
@xml_data = "<hello>world</hello>"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should handle yml" do
|
19
|
+
@yml.unpack(@yml_data).should == { 'hello' => 'world' }
|
20
|
+
@yml.pack(@yml.unpack(@yml_data)).should == @yml_data
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should handle xml" do
|
24
|
+
@xml.unpack(@xml_data).should == { 'hello' => 'world' }
|
25
|
+
@xml.pack(@xml.unpack(@xml_data)).should == @xml_data
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should handle transforming yml to xml (and vice versa)" do
|
29
|
+
@xml.unpack(@xml_data).should == @yml.unpack(@yml_data)
|
30
|
+
@xml.pack(@yml.unpack(@yml_data)).should == @xml_data
|
31
|
+
@yml.pack(@xml.unpack(@xml_data)).should == @yml_data
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'gserver'
|
2
|
+
|
3
|
+
require 'contractual'
|
4
|
+
require 'xmlsimple'
|
5
|
+
|
6
|
+
require 'coronet/message_format/base'
|
7
|
+
require 'coronet/message_format/xml_message_format'
|
8
|
+
|
9
|
+
require 'coronet/transport_mechanism/base'
|
10
|
+
require 'coronet/transport_mechanism/length_prefixed_tcp_transport'
|
11
|
+
require 'coronet/support/echo_server'
|
12
|
+
|
13
|
+
require 'coronet/protocol'
|
14
|
+
|
15
|
+
module Coronet
|
16
|
+
describe Protocol, "conjoins a message format and transport-layer functionality" do
|
17
|
+
it "supports xml-via-tcp interaction with remote interfaces" do
|
18
|
+
echo = Support::EchoServer.new
|
19
|
+
echo.start
|
20
|
+
|
21
|
+
tcp = TransportMechanism::LengthPrefixedTcpTransport.new
|
22
|
+
xml = MessageFormat::XmlMessageFormat.new
|
23
|
+
xml_via_tcp = Protocol.new(xml, tcp)
|
24
|
+
|
25
|
+
msg = { 'hello' => 'world' }
|
26
|
+
xml_via_tcp.transmit(msg, 'localhost', 12345).should == msg
|
27
|
+
|
28
|
+
echo.stop
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'gserver'
|
2
|
+
|
3
|
+
require 'contractual'
|
4
|
+
require 'xmlsimple'
|
5
|
+
|
6
|
+
require 'coronet/message_format/base'
|
7
|
+
require 'coronet/message_format/xml_message_format'
|
8
|
+
|
9
|
+
require 'coronet/transport_mechanism/base'
|
10
|
+
require 'coronet/transport_mechanism/length_prefixed_tcp_transport'
|
11
|
+
|
12
|
+
require 'coronet/protocol'
|
13
|
+
require 'coronet/remote_endpoint'
|
14
|
+
|
15
|
+
require 'coronet/support/echo_server'
|
16
|
+
|
17
|
+
module Coronet
|
18
|
+
|
19
|
+
describe RemoteEndpoint, "conjoins a concrete endpoint, message format and transport-layer functionality" do
|
20
|
+
it "supports xml-via-tcp interaction with remote interfaces" do
|
21
|
+
|
22
|
+
tcp = TransportMechanism::LengthPrefixedTcpTransport.new
|
23
|
+
xml = MessageFormat::XmlMessageFormat.new
|
24
|
+
xml_via_tcp = Protocol.new(xml, tcp)
|
25
|
+
echo_server_endpoint = RemoteEndpoint.new('localhost', 12345, xml_via_tcp)
|
26
|
+
|
27
|
+
msg = { 'hello' => 'world' }
|
28
|
+
|
29
|
+
echo = Support::EchoServer.new
|
30
|
+
echo.start
|
31
|
+
echo_server_endpoint.transmit(msg).should == msg
|
32
|
+
echo.stop
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'gserver'
|
2
|
+
|
3
|
+
require 'contractual'
|
4
|
+
|
5
|
+
require 'coronet/transport_mechanism/base'
|
6
|
+
require 'coronet/transport_mechanism/length_prefixed_tcp_transport'
|
7
|
+
|
8
|
+
require 'coronet/support/echo_server'
|
9
|
+
|
10
|
+
module Coronet
|
11
|
+
module TransportMechanism
|
12
|
+
describe Base, "encapsulates transport-layer functionality" do
|
13
|
+
it "supports interaction with remote services" do
|
14
|
+
echo = Support::EchoServer.new(12345)
|
15
|
+
tcp = LengthPrefixedTcpTransport.new# ('localhost', 12345)
|
16
|
+
|
17
|
+
echo.start
|
18
|
+
io = tcp.open('localhost', 12345)
|
19
|
+
tcp.transmit("hello", io).should == 'hello'
|
20
|
+
echo.stop
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'coronet'
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: coronet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joseph Weissman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-26 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Coronet is a simple protocol adaption framework
|
15
|
+
email:
|
16
|
+
- jweissman1986@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Coronet.gemspec
|
23
|
+
- Gemfile
|
24
|
+
- LICENSE
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- lib/Coronet/version.rb
|
28
|
+
- lib/coronet.rb
|
29
|
+
- lib/coronet/listener.rb
|
30
|
+
- lib/coronet/mediator.rb
|
31
|
+
- lib/coronet/message_format/base.rb
|
32
|
+
- lib/coronet/message_format/xml_message_format.rb
|
33
|
+
- lib/coronet/message_format/yaml_message_format.rb
|
34
|
+
- lib/coronet/protocol.rb
|
35
|
+
- lib/coronet/remote_endpoint.rb
|
36
|
+
- lib/coronet/support/echo_server.rb
|
37
|
+
- lib/coronet/transformation_rule.rb
|
38
|
+
- lib/coronet/transport_mechanism/base.rb
|
39
|
+
- lib/coronet/transport_mechanism/length_prefixed_tcp_transport.rb
|
40
|
+
- spec/coronet/listener.spec
|
41
|
+
- spec/coronet/mediator.spec
|
42
|
+
- spec/coronet/message_format/base.spec
|
43
|
+
- spec/coronet/protocol.spec
|
44
|
+
- spec/coronet/remote_endpoint.spec
|
45
|
+
- spec/coronet/transformation_rule.spec
|
46
|
+
- spec/coronet/transport_mechanism/base.spec
|
47
|
+
- spec/coronet_spec.rb
|
48
|
+
homepage:
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.22
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Coronet is an extensible message-mediation server appliance.
|
72
|
+
test_files: []
|