rxio 0.11.4 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58ba254c8b92e99fce1f72e3e98f490f112ffbba
4
- data.tar.gz: 64794413e4927e4b7380d5f87d20b7e3dbfe72fa
3
+ metadata.gz: a192fa9381b7872090a16feb90e28fe3fe6c1994
4
+ data.tar.gz: 582612082630571b7ef3bd855620bedddd488e17
5
5
  SHA512:
6
- metadata.gz: 3539209f39086919b411bf01ef6c5cb5acb8cf07afacdcc4e771509a996bd5421fafaf941ea3a07557f735a32d498132b4f05113d06338304963612ebc4b4703
7
- data.tar.gz: 5906ac469b314c200ff95810c75073bf74be8c194e9acbd49ebd3270d62283301ddcc4d4ba612191a9c29ea90ab8e16ca749c20478a63779feb82733e1d2d1a4
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
- This will execute the service's main loop. The handler module provides the specific protocol implementation through a set of methods.
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
- The _run_ method is blocking and will only return after the service has terminated.
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
- A _stop_ method is also provided to request the service to terminate.
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 the wrapping of the service in a separate thread.
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 class that will use it.
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* _client_, _chunk_
56
+ #### *filter_input* _endpoint_, _chunk_
56
57
 
57
- This method is called any time a chunk of data is received from a client.
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 *client[:msgs]* array.
60
+ Complete messages can be enqueued for processing by pushing them into the *endpoint[:msgs]* array.
60
61
 
61
- #### *handle_msg* _client_, _msg_
62
+ #### *handle_msg* _endpoint_, _msg_
62
63
 
63
- Messages in the *client[:msgs]* array are regularly de-queued and passed to the *handle_msg* method for handling.
64
- This is usually the entry point to most of the service logic.
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* _client_
67
+ #### (OPTIONAL) *on_join* _endpoint_
67
68
 
68
- As soon as a client is registered by the service, it is passed as argument to the _on_join_ method of the handler module (if available).
69
- This allows the handler module to perform any necessary initialization tasks related to this client.
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* _client_
72
+ #### (OPTIONAL) *on_drop* _endpoint_
72
73
 
73
- Called by the service whenever a client is about to be disconnected (if available).
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* _client_, _msg_
77
+ #### (OPTIONAL) *send_msg* _endpoint_, _msg_
77
78
 
78
- This method should wrap the message supplied as argument according to the desired protocol, and then add the result to the output buffer.
79
- While not actually required by the service class, this method should be considered a best-practice for users to encapsulate data according to a protocol.
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 services and protocols.
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* _client_, _*data_
89
+ #### *write* _endpoint_, _*data_
88
90
 
89
- Used to send one or more data chunks to a client.
90
- This method pushes the chunk(s) to the output buffer, to be later sent to the client.
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 (generally as a consequence of service logic in _handle_msg_), it is perfectly safe to call from any other thread. This can 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).
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*, _client_, _chunk_
98
+ #### *buffer_input*, _endpoint_, _chunk_
97
99
 
98
- Used to add a data chunk to the client's input buffer.
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).
@@ -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
@@ -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 client's output buffer (:obuf).
13
- # @param [Hash] client
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 client, *data
15
+ def write endpoint, *data
16
16
 
17
17
  # Add Data Chunks to Buffer
18
- data.each { |c| client[:lock].synchronize { client[:obuf] << 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 client's input buffer (:ibuf).
23
- # @param [Hash] client
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 client, chunk
25
+ def buffer_input endpoint, chunk
26
26
 
27
27
  # Buffer Chunk
28
- client[:ibuf] << chunk
28
+ endpoint[:ibuf] << chunk
29
29
  end
30
30
  end
31
31
  end
@@ -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
@@ -37,6 +37,7 @@ module RxIO
37
37
  buffer_input client, chunk
38
38
 
39
39
  # Ensure Last Position is available
40
+ client[:bin_delim] ||= {}
40
41
  client[:bin_delim][:last_pos] ||= 0
41
42
 
42
43
  # Loop over Messages
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
- # Chunk Size
18
- CHUNK_SIZE = 1024
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.pop until @clients.empty?
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
- # Read Socket
181
- # Attempts to read as many bytes as possible (up to CHUNK_SIZE) from a given socket _s_, passing the data chunks to _process_input_.
156
+ # Get Endpoint for Socket - Callback for IOBase
157
+ # Finds the Client associated with a given Socket
182
158
  # @param [TCPSocket] s
183
- def read_sock s
184
-
185
- # Acquire Client
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
- # Write Socket
202
- # Attempts to write as many bytes as possible to a given socket _s_ from the associated client's output buffer.
203
- # @param [TCPSocket] s
204
- def write_sock s
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
- # Synchronize Client
213
- c[:lock].synchronize do
169
+ # Drop Client
170
+ @cmap.delete c[:sock]
171
+ @socks.delete c[:sock]
172
+ @clients.delete c
214
173
 
215
- # Write as much as possible
216
- size = s.write_nonblock c[:obuf]
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
@@ -5,5 +5,5 @@
5
5
  module RxIO
6
6
 
7
7
  # Version
8
- VERSION = '0.11.4'
8
+ VERSION = '0.12.0'
9
9
  end
data/lib/rxio.rb CHANGED
@@ -3,9 +3,10 @@
3
3
 
4
4
  # Internal Includes
5
5
  require 'rxio/version'
6
- require 'rxio/service'
7
6
  require 'rxio/handler_base'
8
7
  require 'rxio/io_filters'
8
+ require 'rxio/service'
9
+ require 'rxio/client'
9
10
 
10
11
  # RxIO Module
11
12
  # Root Module for RxIO
data/rxio.gemspec CHANGED
@@ -20,4 +20,5 @@ Gem::Specification.new do |spec|
20
20
  spec.add_development_dependency 'bundler'
21
21
  spec.add_development_dependency 'rake'
22
22
  spec.add_runtime_dependency 'minitest'
23
+ spec.add_runtime_dependency 'runify'
23
24
  end
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.11.4
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-01-28 00:00:00.000000000 Z
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