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 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