Method: Iodine.listen

Defined in:
ext/iodine/iodine.c

.listen(args) ⇒ Object

listen can be used to listen to any incoming connections, including HTTP and raw (tcp/ip and unix sockets) connections.

 Iodine.listen(settings)

Supported Settigs:

:url URL indicating service type, host name and port. Path will be parsed as a Unix socket.
:handler (deprecated: :app) see details below.
:address an IP address or a unix socket address. Only relevant if :url is missing.
:log (HTTP only) request logging. For global verbosity see verbosity
:max_body (HTTP only) maximum upload size allowed per request before disconnection (in Mb).
:max_headers (HTTP only) maximum total header length allowed per request (in Kb).
:max_msg (WebSockets only) maximum message size pre message (in Kb).
:ping (:raw clients and WebSockets only) ping interval (in seconds). Up to 255 seconds.
:port port number to listen to either a String or Number)
:public (HTTP server only) public folder for static file service.
:service (:raw / :tls / :ws / :wss / :http / :https ) a supported service this socket will listen to.
:timeout (HTTP only) keep-alive timeout in seconds. Up to 255 seconds.
:tls an TLS context object for encrypted connections.

Some connection settings are only valid when listening to HTTP / WebSocket connections.

If :url is provided, it will overwrite the :address and :port settings (if provided).

For HTTP connections, the :handler must be a valid Rack application object (answers .call(env)).

Here's an example for an HTTP hello world application:

  require 'iodine'
  # a handler can be a block
  Iodine.listen(service: :http, port: "3000") {|env| [200, {"Content-Length" => "12"}, ["Hello World!"]] }
  # start the service
  Iodine.threads = 1
  Iodine.start

Here's another example, using a Unix Socket instead of a TCP/IP socket for an HTTP hello world application.

This example shows how the :url option can be used, but the :address settings could have been used for the same effect (with port: 0).

  require 'iodine'
  # note that unix sockets in URL form use an absolute path.
  Iodine.listen(url: "http://:0/tmp/sock.sock") {|env| [200, {"Content-Length" => "12"}, ["Hello World!"]] }
  # start the service
  Iodine.threads = 1
  Iodine.start

For raw connections, the :handler object should be an object that answer .call and returns a valid callback object that supports the following callbacks (see also Connection):

on_open(client) called after a connection was established
on_message(client,data) called when incoming data is available. Data may be fragmented.
on_drained(client) called after pending client.write events have been processed (see Iodine::Connection#pending).
ping(client) called whenever a timeout has occured (see Iodine::Connection#timeout=).
on_shutdown(client) called if the server is shutting down. This is called before the connection is closed.
on_close(client) called when the connection with the client was closed.

The client argument passed to the :handler callbacks is an Connection instance that represents the connection / the client.

Here's an example for a telnet based chat-room example:

  require 'iodine'
  # define the protocol for our service
  module ChatHandler
    def self.on_open(client)
      # Set a connection timeout
      client.timeout = 10
      # subscribe to the chat channel.
      client.subscribe :chat
      # Write a welcome message
      client.publish :chat, "new member entered the chat\r\n"
    end
    # this is called for incoming data - note data might be fragmented.
    def self.on_message(client, data)
      # publish the data we received
      client.publish :chat, data
      # close the connection when the time comes
      client.close if data =~ /^bye[\n\r]/
    end
    # called whenever timeout occurs.
    def self.ping(client)
      client.write "System: quite, isn't it...?\r\n"
    end
    # called if the connection is still open and the server is shutting down.
    def self.on_shutdown(client)
      # write the data we received
      client.write "Chat server going away. Try again later.\r\n"
    end
    # returns the callback object (self).
    def self.call
      self
    end
  end
  # we use can both the `handler` keyword or a block, anything that answers #call.
  Iodine.listen(service: :raw, port: "3000", handler: ChatHandler)
  # we can listen to more than a single socket at a time.
  Iodine.listen(url: "raw://:3030", handler: ChatHandler)
  # start the service
  Iodine.threads = 1
  Iodine.start

Returns the handler object used.



1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
# File 'ext/iodine/iodine.c', line 1122

static VALUE iodine_listen(VALUE self, VALUE args) {
  // clang-format on
  iodine_connection_args_s s = iodine_connect_args(args, 1);
  intptr_t uuid = -1;
  switch (s.service) {
  case IODINE_SERVICE_RAW:
    uuid = iodine_tcp_listen(s);
    break;
  case IODINE_SERVICE_HTTP: /* overflow */
  case IODINE_SERVICE_WS:
    uuid = iodine_http_listen(s);
    break;
  }
  iodine_connect_args_cleanup(&s);
  if (uuid == -1)
    rb_raise(rb_eRuntimeError, "Couldn't open listening socket.");
  return s.handler;
  (void)self;
}