xkoon 1.0.0
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 +3 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +21 -0
- data/README.md +217 -0
- data/Rakefile +9 -0
- data/lib/xkoon.rb +15 -0
- data/lib/xkoon/client.rb +40 -0
- data/lib/xkoon/handler.rb +92 -0
- data/lib/xkoon/processor.rb +85 -0
- data/lib/xkoon/proxy.rb +69 -0
- data/lib/xkoon/service.rb +40 -0
- data/lib/xkoon/version.rb +9 -0
- data/xkoon.gemspec +25 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ee2734e060d87cfe173b074e2149710a13d3317c
|
4
|
+
data.tar.gz: 742b227a140dbb54c9cdbb934c36032b0e01f8c3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a10dbd184d2cad958795d3451274fc7741ed5d4f13b2168d318ab8692adbdcafc0ae468033ec75d638f947a3b788b13670fc2592180ac0ab9a617095e4c5ca9c
|
7
|
+
data.tar.gz: 8ab2806562fdf8b3a4a3fcaf2bac368693372c0fded34a08de17860f4be3b307e3a4c5ee3d3203bd097405278f96cbee87a688816d36bc1c5c27a229d8524e93
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Paul Duncan
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
# xKoon
|
2
|
+
|
3
|
+
JSON-based Reactive Service Framework
|
4
|
+
|
5
|
+
## Presentation
|
6
|
+
|
7
|
+
This library provides a simple framework to build network services (servers & clients) around a very simple JSON message format, using [RxIO](https://rubygems.org/gems/rxio).
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
### Gemfile
|
12
|
+
```ruby
|
13
|
+
gem 'xkoon'
|
14
|
+
```
|
15
|
+
|
16
|
+
### Terminal
|
17
|
+
```bash
|
18
|
+
gem install -V xkoon
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Building a service endpoint (whether client or server) with xKoon requires the following:
|
24
|
+
1. define a *Processor* module (for your business logic) providing a bunch of _process_XXX_ methods'
|
25
|
+
2. instantiate an *XKoon::Service* or *XKoon::Client* object around your processor
|
26
|
+
3. run it
|
27
|
+
|
28
|
+
### The Processor
|
29
|
+
|
30
|
+
The _processor_ is at the heart of xKoon - it provides all the necessary abstractions for building simple services.
|
31
|
+
|
32
|
+
#### How to use
|
33
|
+
|
34
|
+
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.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
module ExampleProcessor
|
38
|
+
include XKoon::Processor
|
39
|
+
|
40
|
+
def process_foobar p, h, m
|
41
|
+
puts "Got a 'foobar' request: peer=#{p} handler=#{h} message=#{m}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
#### Sending requests
|
47
|
+
|
48
|
+
The *send_request* method in *XKoon::Processor* allows sending requests to remote peers.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Processor.send_request p, h, m, :some_request_method, data: { foo: :bar }
|
52
|
+
```
|
53
|
+
|
54
|
+
#### Sending responses
|
55
|
+
|
56
|
+
While processing a request, a response can be sent back using the *send_response* method in *XKoon::Processor*.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
# Success
|
60
|
+
send_response p, h, m, 'Everything was processed correctly!'
|
61
|
+
```
|
62
|
+
|
63
|
+
Errors should be sent using the *send_error* method.
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
# Failure
|
67
|
+
send_error p, h, m, 'Something went wrong :('
|
68
|
+
```
|
69
|
+
|
70
|
+
#### Error Wrapper
|
71
|
+
|
72
|
+
An error wrapper is provided within *XKoon::Processor*, allowing for a more transparent implementation of business logic.
|
73
|
+
|
74
|
+
The *error_wrapper* method will yield any block passed to it, rescuing any exception and immediately throwing it back to the remote peer.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
error_wrapper p, h, m do
|
78
|
+
raise "This will get thrown back to remote peer"
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
#### Dealing with responses
|
83
|
+
|
84
|
+
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.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
module ExampleProcessor
|
88
|
+
include XKoon::Processor
|
89
|
+
|
90
|
+
def handle_response p, h, m
|
91
|
+
puts "Got a response from peer [#{p}]: #{m}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
#### Client / Server Processors
|
97
|
+
|
98
|
+
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.
|
99
|
+
|
100
|
+
### Request Format
|
101
|
+
|
102
|
+
xKoon Requests contain the following information:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
{
|
106
|
+
# Requested Method
|
107
|
+
req: :some_request_method,
|
108
|
+
|
109
|
+
# Timestamp marking the time at which the remote peer sent the request
|
110
|
+
sent: 1495623525
|
111
|
+
}
|
112
|
+
```
|
113
|
+
|
114
|
+
### Method Proxying (Make everything transparent)
|
115
|
+
|
116
|
+
xKoon injects a _to_proxy_ method into every Peer Hash.
|
117
|
+
This method simply creates a *Proxy* around the peer and returns it.
|
118
|
+
|
119
|
+
The proxy object serves as a remote method interface: any method called on it will be forwarded to the remote peer.
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
# Create Proxy around Peer
|
123
|
+
pxy = peer_hash.to_proxy
|
124
|
+
|
125
|
+
# Send a 'foobar' request to the remote peer
|
126
|
+
pxy.foobar hello: :world
|
127
|
+
```
|
128
|
+
|
129
|
+
### Response Format
|
130
|
+
|
131
|
+
xKoon Responses contain the following information:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
{
|
135
|
+
# Success (true / false)
|
136
|
+
success: true,
|
137
|
+
|
138
|
+
# Original Request
|
139
|
+
req: { req: :some_request_method, sent: 1495623525 },
|
140
|
+
|
141
|
+
# Whatever the remote peer responded (can be any object - will be converted to JSON)
|
142
|
+
res: 'Got your message!',
|
143
|
+
|
144
|
+
# Timestamp marking the time at which the remote peer sent the response
|
145
|
+
sent: 1495623525
|
146
|
+
}
|
147
|
+
```
|
148
|
+
|
149
|
+
### Example
|
150
|
+
|
151
|
+
Below is a simple but complete example presenting an 'echo' service, replying back anything that was answered.
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
require 'xkoon'
|
155
|
+
|
156
|
+
# Proxy objects
|
157
|
+
PXY = {}
|
158
|
+
|
159
|
+
# Response Objects
|
160
|
+
RES = {}
|
161
|
+
|
162
|
+
# Two-Way Processor (used by both the client & server)
|
163
|
+
module EchoProcessor
|
164
|
+
include XKoon::Processor
|
165
|
+
|
166
|
+
# On Join (Attach the Proxy Objects as soon as we're online)
|
167
|
+
def self.on_join peer, handler
|
168
|
+
PXY[:server] = peer.to_proxy if peer.has_key? :serv
|
169
|
+
PXY[:client] = peer.to_proxy if peer.has_key? :client
|
170
|
+
end
|
171
|
+
|
172
|
+
# On Drop (Release the Proxy Objects whenever we lose the connection)
|
173
|
+
def self.on_drop peer, handler
|
174
|
+
PXY[:server] = nil if peer.has_key? :serv
|
175
|
+
PXY[:client] = nil if peer.has_key? :client
|
176
|
+
end
|
177
|
+
|
178
|
+
# Process 'echo' Request
|
179
|
+
def self.process_echo p, h, m
|
180
|
+
puts "Got echo request: #{m[:data]}"
|
181
|
+
send_response p, h, m, m[:data]
|
182
|
+
end
|
183
|
+
|
184
|
+
# Handle Response
|
185
|
+
def self.handle_response p, h, m
|
186
|
+
RES[:server] = m if p.has_key? :serv
|
187
|
+
RES[:client] = m if p.has_key? :client
|
188
|
+
puts "Got response from peer #{p[:peer][:name]}:#{p[:peer][:port]}: #{m[:res]}"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Create Endpoints
|
193
|
+
srv = XKoon::Service.new EchoProcessor
|
194
|
+
cli = XKoon::Client.new EchoProcessor
|
195
|
+
|
196
|
+
# Start Server & Client
|
197
|
+
srv.startup
|
198
|
+
cli.startup
|
199
|
+
|
200
|
+
# Wait for client and echo something
|
201
|
+
sleep 0.1 until PXY[:client]
|
202
|
+
PXY[:client].echo data: { str: 'hello world!' }
|
203
|
+
|
204
|
+
# Wait for Response to come back
|
205
|
+
sleep 0.1 until RES[:client]
|
206
|
+
|
207
|
+
# Drop Client and wait for drop
|
208
|
+
cli.shutdown
|
209
|
+
sleep 0.1 while PXY[:server]
|
210
|
+
|
211
|
+
# Drop Server
|
212
|
+
srv.shutdown
|
213
|
+
```
|
214
|
+
|
215
|
+
## License
|
216
|
+
|
217
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/lib/xkoon.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# xKoon
|
2
|
+
# by Eresse <eresse@eresse.net>
|
3
|
+
|
4
|
+
# Internal Includes
|
5
|
+
require 'xkoon/version'
|
6
|
+
require 'xkoon/service'
|
7
|
+
require 'xkoon/client'
|
8
|
+
require 'xkoon/handler'
|
9
|
+
require 'xkoon/processor'
|
10
|
+
require 'xkoon/proxy'
|
11
|
+
|
12
|
+
# xKoon Module:
|
13
|
+
# Root Module for xKoon.
|
14
|
+
module XKoon
|
15
|
+
end
|
data/lib/xkoon/client.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# xKoon
|
2
|
+
# by Eresse <eresse@eresse.net>
|
3
|
+
|
4
|
+
# External Includes
|
5
|
+
require 'json'
|
6
|
+
require 'aromat'
|
7
|
+
require 'rxio'
|
8
|
+
|
9
|
+
# Internal Includes
|
10
|
+
require 'xkoon/handler'
|
11
|
+
|
12
|
+
# xKoon Module
|
13
|
+
module XKoon
|
14
|
+
|
15
|
+
# Client Class
|
16
|
+
class Client < RxIO::Client
|
17
|
+
|
18
|
+
# Attribute Accessors
|
19
|
+
attr_reader :processor
|
20
|
+
|
21
|
+
# Defaults
|
22
|
+
DEFAULT_ADDR = 'localhost'
|
23
|
+
DEFAULT_PORT = 23255
|
24
|
+
|
25
|
+
# Construct:
|
26
|
+
# Builds a *Client* around a given _processor_ implementation, set to connect to _addr_ on _port_.
|
27
|
+
# @param [Module] processor
|
28
|
+
# @param [String] addr
|
29
|
+
# @param [Fixnum] port
|
30
|
+
# @param [Hash] ssl_params
|
31
|
+
def initialize processor, addr = DEFAULT_ADDR, port = DEFAULT_PORT, ssl_params = nil
|
32
|
+
|
33
|
+
# Super
|
34
|
+
super addr, port, Handler, ssl_params
|
35
|
+
|
36
|
+
# Set Processor
|
37
|
+
@processor = processor
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# xKoon
|
2
|
+
# by Eresse <eresse@eresse.net>
|
3
|
+
|
4
|
+
# External Includes
|
5
|
+
require 'json'
|
6
|
+
require 'aromat'
|
7
|
+
require 'rxio'
|
8
|
+
|
9
|
+
# Internal Includes
|
10
|
+
require 'xkoon/processor'
|
11
|
+
require 'xkoon/proxy'
|
12
|
+
|
13
|
+
# xKoon Module
|
14
|
+
module XKoon
|
15
|
+
|
16
|
+
# Handler Module:
|
17
|
+
# Provides a generic two-way implementation of the xKoon Protocol.
|
18
|
+
module Handler
|
19
|
+
|
20
|
+
# Split messages on New Lines (Extend BinDelim I/O Filter & Set message delimiter to "\n")
|
21
|
+
extend RxIO::IOFilters::BinDelim
|
22
|
+
msg_delim "\n"
|
23
|
+
|
24
|
+
# Send Request:
|
25
|
+
# Sends a request to the Peer.
|
26
|
+
# @param [Hash] peer RxIO Peer (Client / Server) Hash
|
27
|
+
# @param [Symbol] req Request method
|
28
|
+
# @param [Hash] msg Message Hash
|
29
|
+
def self.send_request peer, req, msg
|
30
|
+
send_msg peer, msg.merge(req: req, sent: Time.now.to_i).to_json
|
31
|
+
end
|
32
|
+
|
33
|
+
# On Join:
|
34
|
+
# RxIO Service Interface Callback - Triggered each time a peer is connected. Forwards notifications to Processor.
|
35
|
+
# @param [Hash] peer An RxIO Peer (Client / Server) Hash
|
36
|
+
def self.on_join peer
|
37
|
+
|
38
|
+
# Acquire Local Endpoint's Processor
|
39
|
+
proc = peer[:local].processor
|
40
|
+
|
41
|
+
# Inject Proxy Generator Method into Peer
|
42
|
+
peer.define_singleton_method(:to_proxy) { Proxy.for_peer peer }
|
43
|
+
|
44
|
+
# Forward Join Notification to Processor
|
45
|
+
proc.on_join peer, self if proc.respond_to? :on_join
|
46
|
+
end
|
47
|
+
|
48
|
+
# On Drop:
|
49
|
+
# RxIO Service Interface Callback - Triggered each time a peer is dropped. Forwards notifications to Processor.
|
50
|
+
# @param [Hash] peer An RxIO Peer (Client / Server) Hash
|
51
|
+
def self.on_drop peer
|
52
|
+
|
53
|
+
# Acquire Local Endpoint's Processor
|
54
|
+
proc = peer[:local].processor
|
55
|
+
|
56
|
+
# Forward Drop Notification to Processor
|
57
|
+
proc.on_drop peer, self if proc.respond_to? :on_drop
|
58
|
+
end
|
59
|
+
|
60
|
+
# Handle Message:
|
61
|
+
# Parses incomning messages and forwards them to the processor.
|
62
|
+
# @param [Hash] peer An RxIO Peer (Client / Server) Hash
|
63
|
+
# @param [String] msg A message
|
64
|
+
def self.handle_msg peer, msg
|
65
|
+
|
66
|
+
# Process Chomped Message as JSON and Deep-Symbolize Keys
|
67
|
+
process_msg peer, JSON.parse(msg.chomp).try(:sym_keys)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Process Message:
|
71
|
+
# Verifies message structure and forwards to processor.
|
72
|
+
# @param [Hash] peer An RxIO Peer (Client / Server) Hash
|
73
|
+
# @param [Hash] msg A message
|
74
|
+
def self.process_msg peer, m
|
75
|
+
|
76
|
+
# Acquire Local Endpoint's Processor
|
77
|
+
proc = peer[:local].processor
|
78
|
+
|
79
|
+
# Check Request Present in Message
|
80
|
+
raise "Missing method in request" unless m[:req].try(:to_s).try :nstr
|
81
|
+
|
82
|
+
# Handle Responses
|
83
|
+
return proc.handle_response peer, self, m if m[:req].is_a? Hash
|
84
|
+
|
85
|
+
# Check Request Valid in Message
|
86
|
+
raise "Invalid method [#{m[:req]}] in request" unless proc.respond_to? "process_#{m[:req]}".to_sym
|
87
|
+
|
88
|
+
# Forward Message to Local Endpoint's Processor
|
89
|
+
proc.send "process_#{m[:req]}".to_sym, peer, self, m
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# xKoon
|
2
|
+
# by Eresse <eresse@eresse.net>
|
3
|
+
|
4
|
+
# External Includes
|
5
|
+
require 'json'
|
6
|
+
require 'aromat'
|
7
|
+
|
8
|
+
# xKoon Module
|
9
|
+
module XKoon
|
10
|
+
|
11
|
+
# Generic Processor Module:
|
12
|
+
# Provides base methods for implementing xKoon Service Processors.
|
13
|
+
module Processor
|
14
|
+
|
15
|
+
# Included:
|
16
|
+
# Inject stuff when included.
|
17
|
+
def self.included base
|
18
|
+
base.extend ClassMethods
|
19
|
+
end
|
20
|
+
|
21
|
+
# Class Methods:
|
22
|
+
# These are injected into the user's processor implementation when this module is included.
|
23
|
+
module ClassMethods
|
24
|
+
|
25
|
+
# Send Request:
|
26
|
+
# Sends a request to the Peer.
|
27
|
+
# @param [Hash] p RxIO Peer (Client / Server) Hash
|
28
|
+
# @param [Module] h Handler Module
|
29
|
+
# @param [Symbol] r Request method
|
30
|
+
# @param [Hash] m Message Hash
|
31
|
+
def send_request p, h, r, m
|
32
|
+
h.send_request p, r, m
|
33
|
+
end
|
34
|
+
|
35
|
+
# Handle Response:
|
36
|
+
# Called whenever a response is sent back from the remote peer.
|
37
|
+
# @param [Hash] p RxIO Peer (Client / Server) Hash
|
38
|
+
# @param [Module] h Handler Module
|
39
|
+
# @param [Hash] m Message Hash
|
40
|
+
def handle_response p, h, m
|
41
|
+
# NoOp - Provide your implementation
|
42
|
+
end
|
43
|
+
|
44
|
+
# Wrap in Error:
|
45
|
+
# Yields the given block, rescuing exceptions and throwing them back to the peer.
|
46
|
+
# @param [Hash] p RxIO Peer (Client / Server) Hash
|
47
|
+
# @param [Module] h Handler Module
|
48
|
+
# @param [Hash] m Message Hash
|
49
|
+
# @return [Array] An two-element Array containing a boolean representing success and the block's result [failed, output]
|
50
|
+
def error_wrapper p, h, m
|
51
|
+
failed = false
|
52
|
+
out = nil
|
53
|
+
begin
|
54
|
+
out = yield
|
55
|
+
rescue Exception => e
|
56
|
+
send_error p, h, m, e
|
57
|
+
failed = true
|
58
|
+
end
|
59
|
+
|
60
|
+
[failed, out]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Respond with Error:
|
64
|
+
# Sends an error message to the Peer.
|
65
|
+
# @param [Hash] p RxIO Peer (Client / Server) Hash
|
66
|
+
# @param [Module] h Handler Module
|
67
|
+
# @param [Hash] req Original request from Peer
|
68
|
+
# @param [Object] error Anything representing an error
|
69
|
+
def send_error p, h, req, error
|
70
|
+
send_response p, h, req, { error: error }, false
|
71
|
+
end
|
72
|
+
|
73
|
+
# Send Generic Response Message:
|
74
|
+
# Sends a response message to the Peer.
|
75
|
+
# @param [Hash] p RxIO Peer (Client / Server) Hash
|
76
|
+
# @param [Module] h Handler Module
|
77
|
+
# @param [Hash] req Original request from Peer
|
78
|
+
# @param [Object] res Anything representing the result of the Peer's request
|
79
|
+
# @param [Object] success Boolean indicating success for the Peer's request
|
80
|
+
def send_response p, h, req, res = {}, success = true
|
81
|
+
h.send_msg p, { success: success, req: req, res: res, sent: Time.now.to_i }.to_json
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/xkoon/proxy.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# xKoon
|
2
|
+
# by Eresse <eresse@eresse.net>
|
3
|
+
|
4
|
+
# External Includes
|
5
|
+
require 'aromat'
|
6
|
+
|
7
|
+
# Internal Includes
|
8
|
+
require 'xkoon/handler'
|
9
|
+
require 'xkoon/processor'
|
10
|
+
|
11
|
+
# xKoon Module
|
12
|
+
module XKoon
|
13
|
+
|
14
|
+
# Proxy Module:
|
15
|
+
# Provides transparent proxying of methods to a Peer.
|
16
|
+
module Proxy
|
17
|
+
|
18
|
+
# Create Proxy for Peer:
|
19
|
+
# Creates a new *Base* proxy object around a given _peer_ and optional _handler_.
|
20
|
+
# @param [Hash] peer RxIO Peer (Client / Server) Hash
|
21
|
+
# @param [Module] handler Handler module
|
22
|
+
def self.for_peer peer, handler = XKoon::Handler
|
23
|
+
Base.new peer, handler
|
24
|
+
end
|
25
|
+
|
26
|
+
# Method Missing:
|
27
|
+
# Proxy all method calls into requests to the Service Peer.
|
28
|
+
def self.method_missing name, *args
|
29
|
+
|
30
|
+
# Ensure we have at least a peer, handler and message
|
31
|
+
raise "Missing arguments in call to [#{name}] (peer, handler, msg)" unless args.size >= 3
|
32
|
+
|
33
|
+
# Get Peer & Handler from Args
|
34
|
+
peer = args.slice! 0
|
35
|
+
handler = args.slice! 0
|
36
|
+
|
37
|
+
# Acquire Payload
|
38
|
+
msg = args.slice! 0
|
39
|
+
|
40
|
+
# Send Request
|
41
|
+
handler.send_request peer, name, msg
|
42
|
+
end
|
43
|
+
|
44
|
+
# Object Proxy Base Class:
|
45
|
+
# Inherit this class to build proxy objects, routing all method calls to the remote peer.
|
46
|
+
class Base
|
47
|
+
|
48
|
+
# Construct:
|
49
|
+
# Creates a new *Base* proxy object around a given _peer_ and optional _handler_.
|
50
|
+
# @param [Hash] peer RxIO Peer (Client / Server) Hash
|
51
|
+
# @param [Module] handler Handler module
|
52
|
+
def initialize peer, handler = XKoon::Handler
|
53
|
+
@proxy_peer = peer
|
54
|
+
@proxy_handler = handler
|
55
|
+
end
|
56
|
+
|
57
|
+
# Method Missing:
|
58
|
+
# Proxy all method calls into requests to the remote peer.
|
59
|
+
def method_missing name, *args
|
60
|
+
|
61
|
+
# Ensure we have at least a message
|
62
|
+
raise "Missing argument in call to [#{name}] (msg)" unless args.size >= 1
|
63
|
+
|
64
|
+
# Forward request through Proxy Module
|
65
|
+
Proxy.send name, @proxy_peer, @proxy_handler, *args
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# xKoon
|
2
|
+
# by Eresse <eresse@eresse.net>
|
3
|
+
|
4
|
+
# External Includes
|
5
|
+
require 'json'
|
6
|
+
require 'aromat'
|
7
|
+
require 'rxio'
|
8
|
+
|
9
|
+
# Internal Includes
|
10
|
+
require 'xkoon/handler'
|
11
|
+
|
12
|
+
# xKoon Module
|
13
|
+
module XKoon
|
14
|
+
|
15
|
+
# Service Class
|
16
|
+
class Service < RxIO::Service
|
17
|
+
|
18
|
+
# Attribute Accessors
|
19
|
+
attr_reader :processor
|
20
|
+
|
21
|
+
# Defaults
|
22
|
+
DEFAULT_ADDR = 'localhost'
|
23
|
+
DEFAULT_PORT = 23255
|
24
|
+
|
25
|
+
# Construct:
|
26
|
+
# Builds a *Service* around a given _processor_ implementation, set to listen for incoming connections @ _addr_ on _port_.
|
27
|
+
# @param [Module] processor
|
28
|
+
# @param [String] addr
|
29
|
+
# @param [Fixnum] port
|
30
|
+
# @param [Hash] ssl_params
|
31
|
+
def initialize processor, addr = DEFAULT_ADDR, port = DEFAULT_PORT, ssl_params = nil
|
32
|
+
|
33
|
+
# Super
|
34
|
+
super addr, port, Handler, ssl_params
|
35
|
+
|
36
|
+
# Set Processor
|
37
|
+
@processor = processor
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/xkoon.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'xkoon/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'xkoon'
|
8
|
+
spec.version = XKoon::VERSION
|
9
|
+
spec.authors = ['Eresse']
|
10
|
+
spec.email = ['eresse@eresse.net']
|
11
|
+
|
12
|
+
spec.summary = 'JSON-based Reactive Service Framework'
|
13
|
+
spec.description = 'Provides a simple framework to build network services.'
|
14
|
+
spec.homepage = 'http://redmine.eresse.net/projects/xkoon'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
spec.add_runtime_dependency 'minitest'
|
23
|
+
spec.add_runtime_dependency 'aromat'
|
24
|
+
spec.add_runtime_dependency 'rxio'
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xkoon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eresse
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: aromat
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rxio
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Provides a simple framework to build network services.
|
84
|
+
email:
|
85
|
+
- eresse@eresse.net
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- Gemfile
|
92
|
+
- LICENSE.txt
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- lib/xkoon.rb
|
96
|
+
- lib/xkoon/client.rb
|
97
|
+
- lib/xkoon/handler.rb
|
98
|
+
- lib/xkoon/processor.rb
|
99
|
+
- lib/xkoon/proxy.rb
|
100
|
+
- lib/xkoon/service.rb
|
101
|
+
- lib/xkoon/version.rb
|
102
|
+
- xkoon.gemspec
|
103
|
+
homepage: http://redmine.eresse.net/projects/xkoon
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.5.1
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: JSON-based Reactive Service Framework
|
127
|
+
test_files: []
|