Class: TinyTCPService
- Inherits:
-
Object
- Object
- TinyTCPService
- Defined in:
- lib/tiny_tcp_service.rb
Overview
usage:
s = TinyTCPService.new(
1234,
->(m) { puts m }
)
s.stop! # gracefully shutdown the server
TinyTCPService implements a line-based, call and response protocol, where every incoming message must be a newline-terminated (“n”) String, and for every received message the service responds with a newline-terminated String. been set).
If you need more complex objects to be sent over the wire, consider something like JSON.
NOTE: if you’re running a TinyTCPService and a client of your system violates your communication protocol, you should raise an instance of TinyTCPService::BadClient, and the TinyTCPService instance will take care of safely removing the client.
Defined Under Namespace
Classes: BadClient
Instance Method Summary collapse
- #_remove_client!(c) ⇒ Object
-
#add_error_handler(klass, block) ⇒ Object
add the error handler and block for the specified class.
-
#initialize(port) ⇒ TinyTCPService
constructor
A new instance of TinyTCPService.
-
#join ⇒ Object
join the service Thread if you want to wait until it’s closed.
-
#msg_handler=(h) ⇒ Object
h - some object that responds to #call.
-
#num_clients ⇒ Object
returns the number of connected clients.
-
#remove_error_handler(klass) ⇒ Object
remove the error handler associated with klass.
-
#running? ⇒ Boolean
returns true if the server is running false otherwise.
-
#stop! ⇒ Object
stops the server gracefully.
Constructor Details
#initialize(port) ⇒ TinyTCPService
Returns a new instance of TinyTCPService.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/tiny_tcp_service.rb', line 24 def initialize(port) @port = port @server = TCPServer.new(port) @clients = [] @running = true @msg_handler = nil @error_handlers = {} # client accept thread @thread = Thread.new do |t| loop do break unless running? @clients << @server.accept end @clients.each{|c| _remove_client!(c) if c && !c.closed? } @server.close end # service thread Thread.new do |t| loop do break unless running? readable, _, errored = IO.select(@clients, nil, @clients, 1) readable&.each do |c| begin m = c.gets&.chomp if m.is_a?(String) c.puts(@msg_handler&.call(m)) else _remove_client!(c) end rescue TinyTCPService::BadClient, Errno::ECONNRESET => e _remove_client!(c) rescue => e handler = @error_handlers[e.class] if handler handler.call(e) else stop! raise e end end end errored&.each do |c| _remove_client!(c) end end end end |
Instance Method Details
#_remove_client!(c) ⇒ Object
114 115 116 117 |
# File 'lib/tiny_tcp_service.rb', line 114 def _remove_client!(c) @clients.delete(c) c.close if c && !c.closed? end |
#add_error_handler(klass, block) ⇒ Object
add the error handler and block for the specified class
you can assume that the local variable name of the error will be ‘e’
100 101 102 |
# File 'lib/tiny_tcp_service.rb', line 100 def add_error_handler(klass, block) @error_handlers[klass] = block end |
#join ⇒ Object
join the service Thread if you want to wait until it’s closed
82 83 84 |
# File 'lib/tiny_tcp_service.rb', line 82 def join @thread.join end |
#msg_handler=(h) ⇒ Object
h - some object that responds to #call
87 88 89 |
# File 'lib/tiny_tcp_service.rb', line 87 def msg_handler=(h) @msg_handler = h end |
#num_clients ⇒ Object
returns the number of connected clients
110 111 112 |
# File 'lib/tiny_tcp_service.rb', line 110 def num_clients @clients.length end |
#remove_error_handler(klass) ⇒ Object
remove the error handler associated with klass
105 106 107 |
# File 'lib/tiny_tcp_service.rb', line 105 def remove_error_handler(klass) @error_handlers.delete(klass) end |
#running? ⇒ Boolean
returns true if the server is running false otherwise
93 94 95 |
# File 'lib/tiny_tcp_service.rb', line 93 def running? @running end |
#stop! ⇒ Object
stops the server gracefully
120 121 122 |
# File 'lib/tiny_tcp_service.rb', line 120 def stop! @running = false end |