xKoon
JSON-based Reactive Service Framework
Presentation
This library provides a simple framework to build network services (servers & clients) around a very simple JSON message format, using RxIO.
Installation
Gemfile
gem 'xkoon'
Terminal
gem install -V xkoon
Usage
Building a service endpoint (whether client or server) with xKoon requires the following:
- define a Processor module (for your business logic) providing a bunch of process_XXX methods'
- instantiate an XKoon::Service or XKoon::Client object around your processor
- run it
The Processor
The processor is at the heart of xKoon - it provides all the necessary abstractions for building simple services.
How to use
To build a processor, simply include XKoon::Processor into any module. Then, any method in your module that starts with process_ will be made available to remote peers.
module ExampleProcessor
include XKoon::Processor
def p, h, m
puts "Got a 'foobar' request: peer=#{p} handler=#{h} message=#{m}"
end
end
Sending requests
The send_request method in XKoon::Processor allows sending requests to remote peers.
Processor.send_request p, h, m, :some_request_method, data: { foo: :bar }
Sending responses
While processing a request, a response can be sent back using the send_response method in XKoon::Processor.
# Success
send_response p, h, m, 'Everything was processed correctly!'
Errors should be sent using the send_error method.
# Failure
send_error p, h, m, 'Something went wrong :('
Error Wrapper
An error wrapper is provided within XKoon::Processor, allowing for a more transparent implementation of business logic.
The error_wrapper method will yield any block passed to it, rescuing any exception and immediately throwing it back to the remote peer.
error_wrapper p, h, m do
raise "This will get thrown back to remote peer"
end
Dealing with responses
Any response to a request will be handed to the handle_response method of the processor. By default the method is empty. You may override it to implement any custom behavior.
module ExampleProcessor
include XKoon::Processor
def handle_response p, h, m
puts "Got a response from peer [#{p}]: #{m}"
end
end
Client / Server Processors
The processor does not care about being the client or server. This means you can implement a single processor serving as a two-way module for both client & server.
Request Format
xKoon Requests contain the following information:
{
# Requested Method
req: :some_request_method,
# Timestamp marking the time at which the remote peer sent the request
sent: 1495623525
}
Method Proxying (Make everything transparent)
xKoon injects a to_proxy method into every Peer Hash. This method simply creates a Proxy around the peer and returns it.
The proxy object serves as a remote method interface: any method called on it will be forwarded to the remote peer.
# Create Proxy around Peer
pxy = peer_hash.to_proxy
# Send a 'foobar' request to the remote peer
pxy. hello: :world
Response Format
xKoon Responses contain the following information:
{
# Success (true / false)
success: true,
# Original Request
req: { req: :some_request_method, sent: 1495623525 },
# Whatever the remote peer responded (can be any object - will be converted to JSON)
res: 'Got your message!',
# Timestamp marking the time at which the remote peer sent the response
sent: 1495623525
}
Example
Below is a simple but complete example presenting an 'echo' service, replying back anything that was answered.
require 'xkoon'
# Proxy objects
PXY = {}
# Response Objects
RES = {}
# Two-Way Processor (used by both the client & server)
module EchoProcessor
include XKoon::Processor
# On Join (Attach the Proxy Objects as soon as we're online)
def self.on_join peer, handler
PXY[:server] = peer.to_proxy if peer.has_key? :serv
PXY[:client] = peer.to_proxy if peer.has_key? :client
end
# On Drop (Release the Proxy Objects whenever we lose the connection)
def self.on_drop peer, handler
PXY[:server] = nil if peer.has_key? :serv
PXY[:client] = nil if peer.has_key? :client
end
# Process 'echo' Request
def self.process_echo p, h, m
puts "Got echo request: #{m[:data]}"
send_response p, h, m, m[:data]
end
# Handle Response
def self.handle_response p, h, m
RES[:server] = m if p.has_key? :serv
RES[:client] = m if p.has_key? :client
puts "Got response from peer #{p[:peer][:name]}:#{p[:peer][:port]}: #{m[:res]}"
end
end
# Create Endpoints
srv = XKoon::Service.new EchoProcessor
cli = XKoon::Client.new EchoProcessor
# Start Server & Client
srv.startup
cli.startup
# Wait for client and echo something
sleep 0.1 until PXY[:client]
PXY[:client].echo data: { str: 'hello world!' }
# Wait for Response to come back
sleep 0.1 until RES[:client]
# Drop Client and wait for drop
cli.shutdown
sleep 0.1 while PXY[:server]
# Drop Server
srv.shutdown
License
The gem is available as open source under the terms of the MIT License.