rxio 0.11.4 → 0.12.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 +4 -4
- data/README.md +102 -30
- data/lib/rxio/client.rb +160 -0
- data/lib/rxio/handler_base.rb +8 -8
- data/lib/rxio/io_base.rb +79 -0
- data/lib/rxio/io_filters/bin_delim.rb +1 -0
- data/lib/rxio/service.rb +28 -71
- data/lib/rxio/version.rb +1 -1
- data/lib/rxio.rb +2 -1
- data/rxio.gemspec +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a192fa9381b7872090a16feb90e28fe3fe6c1994
|
4
|
+
data.tar.gz: 582612082630571b7ef3bd855620bedddd488e17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 934b55278bcd8237d83d79c94374b2cb4e0ecc01eb6321a91388e22fb73fecbb94db2abd122ad2b743cc9986dd85c5a6c25b5af23d1875c6c6a388b93a4294b4
|
7
|
+
data.tar.gz: 16939703ed1cc130e9f5b5be682a951890c67c12f1f3952d7f98ab0f698e80d3a45a75045b4390fe2c4360b5ac4a133d9fc7579ab3cc4ff10d5dc3e41ffa132e
|
data/README.md
CHANGED
@@ -23,26 +23,27 @@ gem install -V rxio
|
|
23
23
|
|
24
24
|
A simple service is created by spawning an instance of the *RxIO::Service* class, passing a *Handler Module* as argument to its constructor and calling its _run_ method.
|
25
25
|
|
26
|
-
|
26
|
+
A simple client is created by spawning an instance of the *RxIO::Client* class, passing a *Handler Module* as argument to its constructor and calling its _run_ method.
|
27
27
|
|
28
|
-
|
28
|
+
This will execute the service / client main loop. The handler module provides the specific protocol implementation through a set of methods.
|
29
29
|
|
30
|
-
|
30
|
+
The _run_ method on both *Service* & *Client* is blocking and will only return after the main loop has terminated.
|
31
|
+
A _stop_ method is also provided to request the main loop to terminate.
|
31
32
|
|
32
33
|
### Running in the background
|
33
34
|
|
34
|
-
While the _run_ / _stop_ methods offer a simple way to implement a single service within the current thread, some situations may require
|
35
|
+
While the _run_ / _stop_ methods offer a simple way to implement a single service/client within the current thread, some situations may require wrapping in a separate thread.
|
35
36
|
|
36
|
-
Thank to [Runify](https://rubygems.org/gems/runify), a dedicated interface is provided for exactly this: _startup_ / _shutdown_ / _restart_
|
37
|
+
Thank to [Runify](https://rubygems.org/gems/runify), a dedicated interface is provided for exactly this purpose: _startup_ / _shutdown_ / _restart_
|
37
38
|
|
38
39
|
#### *startup*
|
39
40
|
|
40
|
-
Calling this method will spawn a new thread around the _run_ method, effectively starting the service in the 'background'.
|
41
|
+
Calling this method will spawn a new thread around the _run_ method, effectively starting the service / client in the 'background'.
|
41
42
|
|
42
43
|
#### *shutdown*
|
43
44
|
|
44
|
-
Calling _shutdown_ will request the service to terminate and wait for the thread to complete (join).
|
45
|
-
Once this method returns, the service has completely terminated (thread dead, all clients disconnected).
|
45
|
+
Calling _shutdown_ will request the service / client to terminate and wait for the wrapper thread to complete (join).
|
46
|
+
Once this method returns, the service / client has completely terminated (thread dead, all sockets closed, all clients disconnected).
|
46
47
|
|
47
48
|
#### *restart*
|
48
49
|
|
@@ -50,52 +51,53 @@ This method is a simple shortcut to _shutdown_ immediately followed by _startup_
|
|
50
51
|
|
51
52
|
### Handler Interface
|
52
53
|
|
53
|
-
The following is a list of methods that should be implemented by the handler module in order to provide a valid interface to the RxIO::Service
|
54
|
+
The following is a list of methods that should be implemented by the handler module in order to provide a valid interface to the RxIO::Service and RxIO::Client classes that will use it.
|
54
55
|
|
55
|
-
#### *filter_input*
|
56
|
+
#### *filter_input* _endpoint_, _chunk_
|
56
57
|
|
57
|
-
This method is called any time a chunk of data is received
|
58
|
+
This method is called any time a chunk of data is received on the wire.
|
58
59
|
Its purpose is usually to filter protocol data and re-assemble messages.
|
59
|
-
Complete messages can be enqueued for processing by pushing them into the *
|
60
|
+
Complete messages can be enqueued for processing by pushing them into the *endpoint[:msgs]* array.
|
60
61
|
|
61
|
-
#### *handle_msg*
|
62
|
+
#### *handle_msg* _endpoint_, _msg_
|
62
63
|
|
63
|
-
Messages in the *
|
64
|
-
This is usually the entry point to most of the
|
64
|
+
Messages in the *endpoint[:msgs]* array are regularly de-queued and passed to the *handle_msg* method for handling.
|
65
|
+
This is usually the entry point to most of the business logic for services.
|
65
66
|
|
66
|
-
#### (OPTIONAL) *on_join*
|
67
|
+
#### (OPTIONAL) *on_join* _endpoint_
|
67
68
|
|
68
|
-
As soon as a
|
69
|
-
This allows the handler module to perform any necessary initialization tasks related to this
|
69
|
+
As soon as a endpoint is 'online' (Client is registered by the Service / Connection to Server is established by the Client), it is passed as argument to the _on_join_ method of the handler module (if available).
|
70
|
+
This allows the handler module to perform any necessary initialization tasks related to this endpoint.
|
70
71
|
|
71
|
-
#### (OPTIONAL) *on_drop*
|
72
|
+
#### (OPTIONAL) *on_drop* _endpoint_
|
72
73
|
|
73
|
-
Called by the service whenever a client
|
74
|
+
Called by the service / client whenever the connection to the server / a client has been lost (if available).
|
74
75
|
This method should release any resources used by the client.
|
75
76
|
|
76
|
-
#### (OPTIONAL) *send_msg*
|
77
|
+
#### (OPTIONAL) *send_msg* _endpoint_, _msg_
|
77
78
|
|
78
|
-
This method should
|
79
|
-
While not
|
79
|
+
This method should encapsulate the message supplied as argument according to the desired protocol, and then add the result to the output buffer.
|
80
|
+
While not absolutely required by the service or client classes, this method should be considered a best-practice for users to encapsulate data according to a protocol.
|
81
|
+
Also, if an implementation for _send_msg_ is provided in the Service Handler, Clients built around it will expose a shortcut 'send_msg' instance method.
|
80
82
|
|
81
83
|
### Handler Base
|
82
84
|
|
83
|
-
A base module is provided to facilitate implementation of new
|
85
|
+
A base module is provided to facilitate implementation of new protocols.
|
84
86
|
The *RxIO::HandlerBase* module should be extended by the service handler module.
|
85
87
|
It provides two simple I/O methods:
|
86
88
|
|
87
|
-
#### *write*
|
89
|
+
#### *write* _endpoint_, _*data_
|
88
90
|
|
89
|
-
Used to send one or more data chunks to
|
90
|
-
This method pushes the chunk(s) to the output buffer, to be later sent
|
91
|
+
Used to send one or more data chunks to an endpoint.
|
92
|
+
This method pushes the chunk(s) to the output buffer, to be later sent over the wire.
|
91
93
|
|
92
|
-
This method is *thread-safe* - while in most cases it will be called from within the main service loop (
|
94
|
+
This method is *thread-safe* - while in most cases it will be called from within the main service / client loop (often as a consequence of service logic in _handle_msg_), it is perfectly safe to call from any other thread. This is how most clients should behave. This can also be useful in situations where a service might generate messages for the client _outside_ of the normal request-response cycle (such as an event-subscription service).
|
93
95
|
|
94
96
|
Note: this method does not perform any encoding or transformation on the data. It is the user's responsibility to provide protocol encoding, usually through the _send_msg_ method.
|
95
97
|
|
96
|
-
#### *buffer_input*,
|
98
|
+
#### *buffer_input*, _endpoint_, _chunk_
|
97
99
|
|
98
|
-
Used to add a data chunk to the
|
100
|
+
Used to add a data chunk to the endpoint's input buffer.
|
99
101
|
|
100
102
|
### Provided Filters
|
101
103
|
|
@@ -217,6 +219,58 @@ es = EchoService.new
|
|
217
219
|
es.run
|
218
220
|
```
|
219
221
|
|
222
|
+
### A simple client for the echo service
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
#!/usr/bin/env ruby
|
226
|
+
|
227
|
+
require 'rxio'
|
228
|
+
|
229
|
+
# Echo Client Class
|
230
|
+
class EchoClient < RxIO::Client
|
231
|
+
|
232
|
+
# Defaults
|
233
|
+
DEFAULT_ADDR = '0.0.0.0'
|
234
|
+
DEFAULT_PORT = 4444
|
235
|
+
|
236
|
+
# Construct
|
237
|
+
def initialize
|
238
|
+
super DEFAULT_ADDR, DEFAULT_PORT, EchoHandler
|
239
|
+
end
|
240
|
+
|
241
|
+
# Echo Service Handler Module
|
242
|
+
module EchoHandler
|
243
|
+
|
244
|
+
# Extend BinDelim I/O Filter
|
245
|
+
extend RxIO::IOFilters::BinDelim
|
246
|
+
|
247
|
+
# Set Message Delimiter
|
248
|
+
msg_delim "\n"
|
249
|
+
|
250
|
+
# On Join
|
251
|
+
def self.on_join server
|
252
|
+
puts "Connected to server: #{server[:peer][:name]}:#{server[:peer][:port]}"
|
253
|
+
send_msg server, "Hello World!"
|
254
|
+
end
|
255
|
+
|
256
|
+
# On Drop
|
257
|
+
def self.on_drop server
|
258
|
+
puts "Connection dropped: #{server[:peer][:name]}:#{server[:peer][:port]}"
|
259
|
+
end
|
260
|
+
|
261
|
+
# Handle Message
|
262
|
+
def self.handle_msg server, msg
|
263
|
+
puts "Got response from server: #{server[:peer][:name]}:#{server[:peer][:port]} -> \"#{msg}\""
|
264
|
+
server[:client].stop # Done - Terminate the Client!
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# Run the Client
|
270
|
+
ec = EchoClient.new
|
271
|
+
ec.run
|
272
|
+
```
|
273
|
+
|
220
274
|
### Running a service in the background
|
221
275
|
|
222
276
|
```ruby
|
@@ -235,6 +289,24 @@ es.shutdown
|
|
235
289
|
puts 'Service has terminated!'
|
236
290
|
```
|
237
291
|
|
292
|
+
### Running a client in the background
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
# ...
|
296
|
+
|
297
|
+
# Run the client in the background
|
298
|
+
puts 'Client is starting up...'
|
299
|
+
es = EchoService.new
|
300
|
+
es.startup
|
301
|
+
puts 'Client is online!'
|
302
|
+
|
303
|
+
# Do something while the client is running...
|
304
|
+
|
305
|
+
# Shutdown the client
|
306
|
+
es.shutdown
|
307
|
+
puts 'Client has terminated!'
|
308
|
+
```
|
309
|
+
|
238
310
|
## License
|
239
311
|
|
240
312
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/lib/rxio/client.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# RxIO
|
2
|
+
# by Eresse <eresse@eresse.net>
|
3
|
+
|
4
|
+
# External Includes
|
5
|
+
require 'thread'
|
6
|
+
require 'socket'
|
7
|
+
require 'runify'
|
8
|
+
|
9
|
+
# Internal Includes
|
10
|
+
require 'rxio/io_base'
|
11
|
+
|
12
|
+
# RxIO Module
|
13
|
+
module RxIO
|
14
|
+
|
15
|
+
# Client Class
|
16
|
+
class Client
|
17
|
+
|
18
|
+
# Runify
|
19
|
+
include Runify
|
20
|
+
|
21
|
+
# I/O Base
|
22
|
+
include IOBase
|
23
|
+
|
24
|
+
# Reconnect Delay (seconds)
|
25
|
+
RECONNECT_DELAY = 1
|
26
|
+
|
27
|
+
# Select Timeout (Seconds)
|
28
|
+
SELECT_TIMEOUT = 0.1
|
29
|
+
|
30
|
+
# Construct
|
31
|
+
# Builds a *Client* around a given _service_handler_ module, set to connect to _addr_ on _port_.
|
32
|
+
# @param [String] addr
|
33
|
+
# @param [Fixnum] port
|
34
|
+
# @param [Module] service_handler
|
35
|
+
def initialize addr, port, service_handler
|
36
|
+
|
37
|
+
# Set Address & Port
|
38
|
+
@addr = addr
|
39
|
+
@port = port
|
40
|
+
|
41
|
+
# Set Service Handler Module
|
42
|
+
@service_handler = service_handler
|
43
|
+
|
44
|
+
# Set Socket
|
45
|
+
@sock = nil
|
46
|
+
|
47
|
+
# Client Hash
|
48
|
+
@client = {
|
49
|
+
client: self,
|
50
|
+
ibuf: '',
|
51
|
+
obuf: '',
|
52
|
+
lock: Mutex.new,
|
53
|
+
msgs: []
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
# Send Message
|
58
|
+
# Enqueues a Message to be sent to the server
|
59
|
+
# @param [String] msg
|
60
|
+
def send_msg msg
|
61
|
+
|
62
|
+
# Verify Implementation
|
63
|
+
raise "Method send_msg is not implemented by Service Handler #{@service_handler.name}" unless @service_handler.respond_to? :send_msg
|
64
|
+
|
65
|
+
# Send Message through Service Handler
|
66
|
+
@service_handler.send_msg @client, msg
|
67
|
+
end
|
68
|
+
|
69
|
+
# Run
|
70
|
+
# Executes the main client loop, taking care of I/O scheduling and message handling.
|
71
|
+
def run
|
72
|
+
|
73
|
+
# Update Loop
|
74
|
+
begin
|
75
|
+
|
76
|
+
# Update Service
|
77
|
+
update until @stop
|
78
|
+
rescue Exception => e
|
79
|
+
puts "[!] ERROR - RxIO Client Update failed - #{e.inspect}"
|
80
|
+
e.backtrace.each { |b| puts " - #{b}" }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Drop Socket
|
84
|
+
@sock.close if @sock
|
85
|
+
@sock = nil
|
86
|
+
end
|
87
|
+
|
88
|
+
# Stop
|
89
|
+
# Requests the client loop to stop executing.
|
90
|
+
# The _run_ method should return shortly after calling _stop_
|
91
|
+
def stop
|
92
|
+
@stop = true
|
93
|
+
end
|
94
|
+
|
95
|
+
# Privates
|
96
|
+
private
|
97
|
+
|
98
|
+
# Update
|
99
|
+
# Serves as the client loop main method, performing I/O scheduling and message handling.
|
100
|
+
def update
|
101
|
+
|
102
|
+
# Ensure Socket is available
|
103
|
+
return unless ensure_sock
|
104
|
+
|
105
|
+
# Select
|
106
|
+
rd, wr, _er = IO.select [@sock], @client[:obuf].empty? ? [] : [@sock], [], SELECT_TIMEOUT
|
107
|
+
|
108
|
+
# Handle I/O
|
109
|
+
rd.each { |s| read_sock s } if rd
|
110
|
+
wr.each { |s| write_sock s } if wr
|
111
|
+
end
|
112
|
+
|
113
|
+
# Ensure Socket is available
|
114
|
+
# Re-creates the socket in the event of failure
|
115
|
+
def ensure_sock
|
116
|
+
|
117
|
+
# Check
|
118
|
+
return @sock if @sock
|
119
|
+
|
120
|
+
# Reconnect Delay (don't be an asshole...)
|
121
|
+
sleep RECONNECT_DELAY unless @sock
|
122
|
+
|
123
|
+
# Attempt reconnect
|
124
|
+
@sock = TCPSocket.new @addr, @port rescue nil
|
125
|
+
|
126
|
+
# Check Socket
|
127
|
+
return nil unless @sock
|
128
|
+
|
129
|
+
# Acquire Peer Address
|
130
|
+
peer = @sock.peeraddr
|
131
|
+
@client[:peer] = {
|
132
|
+
port: peer[1],
|
133
|
+
name: peer[2],
|
134
|
+
addr: peer[3]
|
135
|
+
}
|
136
|
+
|
137
|
+
# Notify Service Handler on success
|
138
|
+
@service_handler.on_join @client if @service_handler.respond_to? :on_join
|
139
|
+
|
140
|
+
# Return Result
|
141
|
+
@sock
|
142
|
+
end
|
143
|
+
|
144
|
+
# Get Endpoint for Socket - Callback for IOBase
|
145
|
+
# Simply returns the Client Hash
|
146
|
+
# @param [TCPSocket] _s
|
147
|
+
# @return [Hash] The Client Hash
|
148
|
+
def get_endpoint_for_sock _s
|
149
|
+
@client
|
150
|
+
end
|
151
|
+
|
152
|
+
# On Drop - Callback for IOBase
|
153
|
+
# Kills the socket
|
154
|
+
# @param [Hash] _e
|
155
|
+
def on_drop _e
|
156
|
+
@sock.close rescue nil
|
157
|
+
@sock = nil
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/lib/rxio/handler_base.rb
CHANGED
@@ -9,23 +9,23 @@ module RxIO
|
|
9
9
|
module HandlerBase
|
10
10
|
|
11
11
|
# Write
|
12
|
-
# Writes one or more chunks of data to the
|
13
|
-
# @param [Hash]
|
12
|
+
# Writes one or more chunks of data to the endpoint's output buffer (:obuf).
|
13
|
+
# @param [Hash] endpoint
|
14
14
|
# @param [String] data One or more chunks of data to be written to the ouput buffer
|
15
|
-
def write
|
15
|
+
def write endpoint, *data
|
16
16
|
|
17
17
|
# Add Data Chunks to Buffer
|
18
|
-
data.each { |c|
|
18
|
+
data.each { |c| endpoint[:lock].synchronize { endpoint[:obuf] << c } }
|
19
19
|
end
|
20
20
|
|
21
21
|
# Buffer Input Chunk
|
22
|
-
# Writes a chunk of data to the
|
23
|
-
# @param [Hash]
|
22
|
+
# Writes a chunk of data to the endpoint's input buffer (:ibuf).
|
23
|
+
# @param [Hash] endpoint
|
24
24
|
# @param [String] chunk
|
25
|
-
def buffer_input
|
25
|
+
def buffer_input endpoint, chunk
|
26
26
|
|
27
27
|
# Buffer Chunk
|
28
|
-
|
28
|
+
endpoint[:ibuf] << chunk
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
data/lib/rxio/io_base.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# RxIO
|
2
|
+
# by Eresse <eresse@eresse.net>
|
3
|
+
|
4
|
+
# RxIO Module
|
5
|
+
module RxIO
|
6
|
+
|
7
|
+
# I/O Base Module
|
8
|
+
module IOBase
|
9
|
+
|
10
|
+
# Chunk Size
|
11
|
+
CHUNK_SIZE = 1024
|
12
|
+
|
13
|
+
# Process Input
|
14
|
+
# Processes Input for an Endpoint, in the form of a data chunk
|
15
|
+
# @param [Hash] endpoint
|
16
|
+
# @param [String] chunk A chunk of data, as received by the socket
|
17
|
+
def process_input endpoint, chunk
|
18
|
+
|
19
|
+
# Pass through Service Handler Module
|
20
|
+
@service_handler.filter_input endpoint, chunk
|
21
|
+
|
22
|
+
# Process Messages
|
23
|
+
@service_handler.handle_msg endpoint, endpoint[:msgs].shift until endpoint[:msgs].empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Read Socket
|
27
|
+
# Attempts to read as many bytes as possible (up to CHUNK_SIZE) from a given socket _s_, passing the data chunks to _process_input_.
|
28
|
+
# @param [TCPSocket] s
|
29
|
+
def read_sock s
|
30
|
+
|
31
|
+
# Acquire Endpoint for Socket
|
32
|
+
e = get_endpoint_for_sock s
|
33
|
+
|
34
|
+
# Check Endpoint
|
35
|
+
return unless e
|
36
|
+
|
37
|
+
# Read Chunk from Socket
|
38
|
+
chunk = s.read_nonblock CHUNK_SIZE rescue nil
|
39
|
+
|
40
|
+
# Drop Endpoint & Abort on Error
|
41
|
+
return drop_endpoint e unless chunk
|
42
|
+
|
43
|
+
# Process Input
|
44
|
+
process_input e, chunk
|
45
|
+
end
|
46
|
+
|
47
|
+
# Write Socket
|
48
|
+
# Attempts to write as many bytes as possible to a given socket _s_ from the associated client's output buffer.
|
49
|
+
# @param [TCPSocket] s
|
50
|
+
def write_sock s
|
51
|
+
|
52
|
+
# Acquire Endpoint
|
53
|
+
e = get_endpoint_for_sock s
|
54
|
+
|
55
|
+
# Check Endpoint
|
56
|
+
return unless e
|
57
|
+
|
58
|
+
# Synchronize Endpoint
|
59
|
+
e[:lock].synchronize do
|
60
|
+
|
61
|
+
# Write as much as possible
|
62
|
+
size = (s.write_nonblock e[:obuf] rescue nil) || 0
|
63
|
+
e[:obuf].slice! 0, size if size > 0
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Drop Endpoint
|
68
|
+
# Notifies the Service Handler and Parent Implementation (in that order) of a dropped endpoint
|
69
|
+
# @param [Hash] endpoint
|
70
|
+
def drop_endpoint endpoint
|
71
|
+
|
72
|
+
# Notify Service Handler
|
73
|
+
@service_handler.on_drop endpoint if @service_handler.respond_to? :on_drop
|
74
|
+
|
75
|
+
# Drop Endpoint
|
76
|
+
on_drop endpoint
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/rxio/service.rb
CHANGED
@@ -4,6 +4,10 @@
|
|
4
4
|
# External Includes
|
5
5
|
require 'thread'
|
6
6
|
require 'socket'
|
7
|
+
require 'runify'
|
8
|
+
|
9
|
+
# Internal Includes
|
10
|
+
require 'rxio/io_base'
|
7
11
|
|
8
12
|
# RxIO Module
|
9
13
|
module RxIO
|
@@ -14,8 +18,11 @@ module RxIO
|
|
14
18
|
# Runify
|
15
19
|
include Runify
|
16
20
|
|
17
|
-
#
|
18
|
-
|
21
|
+
# I/O Base
|
22
|
+
include IOBase
|
23
|
+
|
24
|
+
# Select Timeout (Seconds)
|
25
|
+
SELECT_TIMEOUT = 0.1
|
19
26
|
|
20
27
|
# Construct
|
21
28
|
# Builds a *Service* around a given _service_handler_ module, set to listen for incoming connections @ _addr_ on _port_.
|
@@ -61,7 +68,7 @@ module RxIO
|
|
61
68
|
end
|
62
69
|
|
63
70
|
# Drop all Clients
|
64
|
-
@service_handler.on_drop @clients.
|
71
|
+
@service_handler.on_drop @clients.shift until @clients.empty? if @service_handler.respond_to? :on_drop
|
65
72
|
@cmap = {}
|
66
73
|
|
67
74
|
# Close all Sockets
|
@@ -90,24 +97,11 @@ module RxIO
|
|
90
97
|
ws = @clients.reject { |c| c[:lock].synchronize { c[:obuf].empty? } }.collect { |c| c[:sock] }
|
91
98
|
|
92
99
|
# Select Sockets
|
93
|
-
rd, wr = IO.select @socks, ws
|
100
|
+
rd, wr, _er = IO.select @socks, ws, [], SELECT_TIMEOUT
|
94
101
|
|
95
102
|
# Handle I/O
|
96
|
-
rd.each { |s| s == @serv ? acpt_sock(s) : read_sock(s) }
|
97
|
-
wr.each { |s| write_sock s }
|
98
|
-
end
|
99
|
-
|
100
|
-
# Process Input
|
101
|
-
# Processes Input from a client, in the form of a data chunk
|
102
|
-
# @param [Hash] client
|
103
|
-
# @param [String] chunk A chunk of data, as received by the socket
|
104
|
-
def process_input client, chunk
|
105
|
-
|
106
|
-
# Pass through Service Handler Module
|
107
|
-
@service_handler.filter_input client, chunk
|
108
|
-
|
109
|
-
# Process Messages
|
110
|
-
@service_handler.handle_msg client, client[:msgs].shift until client[:msgs].empty?
|
103
|
+
rd.each { |s| s == @serv ? acpt_sock(s) : read_sock(s) } if rd
|
104
|
+
wr.each { |s| write_sock s } if wr
|
111
105
|
end
|
112
106
|
|
113
107
|
# Register Client
|
@@ -146,24 +140,6 @@ module RxIO
|
|
146
140
|
@service_handler.on_join c if @service_handler.respond_to? :on_join
|
147
141
|
end
|
148
142
|
|
149
|
-
# Drop Client
|
150
|
-
# Unregisters a Client and closes the associated socket.
|
151
|
-
# Also, notifies the Handler Module if the _on_drop_ method is available.
|
152
|
-
# @param [Hash] c
|
153
|
-
def drop_client c
|
154
|
-
|
155
|
-
# Notify Service Handler
|
156
|
-
@service_handler.on_drop c if @service_handler.respond_to? :on_drop
|
157
|
-
|
158
|
-
# Drop Client
|
159
|
-
@cmap.delete c[:sock]
|
160
|
-
@socks.delete c[:sock]
|
161
|
-
@clients.delete c
|
162
|
-
|
163
|
-
# Kill Socket
|
164
|
-
c[:sock].close rescue nil
|
165
|
-
end
|
166
|
-
|
167
143
|
# Accept Socket
|
168
144
|
# Tries to accept any queued connection request in a non-blocking manner.
|
169
145
|
# Registers a new Client through _add_client_ around the newly-accepted socket if present.
|
@@ -177,45 +153,26 @@ module RxIO
|
|
177
153
|
add_client ns if ns
|
178
154
|
end
|
179
155
|
|
180
|
-
#
|
181
|
-
#
|
156
|
+
# Get Endpoint for Socket - Callback for IOBase
|
157
|
+
# Finds the Client associated with a given Socket
|
182
158
|
# @param [TCPSocket] s
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
c = @cmap[s]
|
187
|
-
|
188
|
-
# Check Client
|
189
|
-
return unless c
|
190
|
-
|
191
|
-
# Read Chunk from Socket
|
192
|
-
chunk = s.read_nonblock CHUNK_SIZE rescue nil
|
193
|
-
|
194
|
-
# Drop Client & Abort on Error
|
195
|
-
return drop_client c unless chunk
|
196
|
-
|
197
|
-
# Process Input
|
198
|
-
process_input c, chunk
|
159
|
+
# @return [Hash] The Endpoint associated with Socket _s_, or nil
|
160
|
+
def get_endpoint_for_sock s
|
161
|
+
@cmap[s]
|
199
162
|
end
|
200
163
|
|
201
|
-
#
|
202
|
-
#
|
203
|
-
# @param [
|
204
|
-
def
|
205
|
-
|
206
|
-
# Acquire Client
|
207
|
-
c = @cmap[s]
|
208
|
-
|
209
|
-
# Check Client
|
210
|
-
return unless c
|
164
|
+
# On Drop - Callback for IOBase
|
165
|
+
# Unregisters a Client and closes the associated socket.
|
166
|
+
# @param [Hash] c
|
167
|
+
def on_drop c
|
211
168
|
|
212
|
-
#
|
213
|
-
c[:
|
169
|
+
# Drop Client
|
170
|
+
@cmap.delete c[:sock]
|
171
|
+
@socks.delete c[:sock]
|
172
|
+
@clients.delete c
|
214
173
|
|
215
|
-
|
216
|
-
|
217
|
-
c[:obuf].slice! 0, size if size > 0
|
218
|
-
end
|
174
|
+
# Kill Socket
|
175
|
+
c[:sock].close rescue nil
|
219
176
|
end
|
220
177
|
end
|
221
178
|
end
|
data/lib/rxio/version.rb
CHANGED
data/lib/rxio.rb
CHANGED
data/rxio.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rxio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eresse
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: runify
|
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'
|
55
69
|
description: Provides an implementation of the Reactor Pattern for Ruby Sockets.
|
56
70
|
email:
|
57
71
|
- eresse@eresse.net
|
@@ -65,7 +79,9 @@ files:
|
|
65
79
|
- README.md
|
66
80
|
- Rakefile
|
67
81
|
- lib/rxio.rb
|
82
|
+
- lib/rxio/client.rb
|
68
83
|
- lib/rxio/handler_base.rb
|
84
|
+
- lib/rxio/io_base.rb
|
69
85
|
- lib/rxio/io_filters.rb
|
70
86
|
- lib/rxio/io_filters/bin_delim.rb
|
71
87
|
- lib/rxio/io_filters/msg_size.rb
|