Module: Iodine

Extended by:
Iodine
Included in:
Iodine
Defined in:
lib/iodine.rb,
lib/iodine/io.rb,
lib/iodine/core.rb,
lib/iodine/http.rb,
lib/iodine/timers.rb,
lib/iodine/logging.rb,
lib/iodine/version.rb,
lib/iodine/protocol.rb,
lib/iodine/settings.rb,
lib/iodine/http/hpack.rb,
lib/iodine/http/http1.rb,
lib/iodine/http/http2.rb,
lib/iodine/http/request.rb,
lib/iodine/http/session.rb,
lib/iodine/http/response.rb,
lib/iodine/ssl_connector.rb,
lib/iodine/http/websockets.rb,
lib/iodine/http/rack_support.rb,
lib/iodine/http/websocket_client.rb,
lib/iodine/http/websocket_handler.rb

Overview

Iodine is an easy Object-Oriented library for writing network applications (servers) with your own network protocol.

Please read the README file for an introduction to Iodine.

Here’s a quick and easy echo server, notice how Iodine will automatically start running once you finish setting everything up:

require 'iodine'

class MyProtocol < Iodine::Protocol
   # Iodine will call this whenever a new connection is opened.
   def on_open
      # Iodine includes logging as well as unique assigned instance ID's.
      Iodine.info "New connection id: #{id}"
      # Iodine includes timeout support with automatic pinging or connection termination.
      set_timeout 5
   end
   def on_message data
      write("-- Closing connection, goodbye.\n") && close if data =~ /^(bye|close|exit)/i
      write(">> #{data.chomp}\n")
   end
   # Iodine will call this whenever a new connection is closed.
   def on_close
      Iodine.info "Closing connection id: #{id}"
   end
   # Iodine will call this whenever a a timeout is reached.
   def ping
      # If `write` fails, it automatically closes the connection.
      write("-- Are you still there?\n")
   end
end

# setting up the server is as easy as plugging in your Protocol class:
Iodine.protocol = MyProtocol

# if you are excecuting this script from IRB, exit IRB to start Iodine.
exit

Defined Under Namespace

Modules: Base Classes: Http, Protocol, SSLConnector, TimedEvent

Constant Summary collapse

VERSION =
"0.0.4"

Instance Method Summary collapse

Instance Method Details

#bindObject

Gets the IP binding address. Defaults to the command line ‘-ip` argument, or the ENV or 0.0.0.0 (in this order).



39
40
41
# File 'lib/iodine/settings.rb', line 39

def bind
	@bind
end

#bind=(address) ⇒ Object

Sets the IP binding address. Defaults to the command line ‘-ip` argument, or the ENV or 0.0.0.0 (in this order).



35
36
37
# File 'lib/iodine/settings.rb', line 35

def bind= address
	@bind = address
end

#debug(data, &block) ⇒ String, ...

logs debug info

Returns:

  • (String, Exception, Object)

    always returns the Object sent to the log.



17
18
19
20
# File 'lib/iodine/logging.rb', line 17

def debug data, &block
	@logger.debug data, &block if @logger
	data
end

#error(data, &block) ⇒ String, ...

logs errors

Returns:

  • (String, Exception, Object)

    always returns the Object sent to the log.



29
30
31
32
# File 'lib/iodine/logging.rb', line 29

def error data, &block
	@logger.error data, &block if @logger
	data
end

#fatal(data, &block) ⇒ String, ...

logs a fatal error

Returns:

  • (String, Exception, Object)

    always returns the Object sent to the log.



35
36
37
38
# File 'lib/iodine/logging.rb', line 35

def fatal data, &block
	@logger.fatal data, &block if @logger
	data
end

#force_start!Object

forces Iodine to start prematurely and asyncronously. This might case Iodine to exit abruptly, depending how the hosting application behaves.



35
36
37
38
# File 'lib/iodine/core.rb', line 35

def force_start!
	thread = Thread.new { startup true }
	Kernel.at_exit {thread.raise("stop"); thread.join}
end

#info(data, &block) ⇒ String, ...

logs info

Returns:

  • (String, Exception, Object)

    always returns the Object sent to the log.



11
12
13
14
# File 'lib/iodine/logging.rb', line 11

def info data, &block
	@logger.info data, &block if @logger
	data
end

#log(raw_text) ⇒ String

logs a raw text

Returns:

  • (String)

    always returns the Object sent to the log.



41
42
43
44
# File 'lib/iodine/logging.rb', line 41

def log raw_text
	@logger << raw_text if @logger
	raw_text
end

#loggerObject

Gets the logging object and allows you to call logging methods (i.e. ‘Iodine.log.info “Running”`).



5
6
7
# File 'lib/iodine/logging.rb', line 5

def logger
	@logger
end

#logger=(obj) ⇒ Object

Sets the logging object, which needs to act like ‘Logger`. The default logger is `Logger.new(STDOUT)`.



8
9
10
# File 'lib/iodine/settings.rb', line 8

def logger= obj
	@logger = obj
end

#on_shutdown(*args, &block) ⇒ Iodine

Returns Adds a shutdown tasks. These tasks should be executed in order of creation.

Returns:

  • (Iodine)

    Adds a shutdown tasks. These tasks should be executed in order of creation.



23
24
25
26
# File 'lib/iodine/core.rb', line 23

def on_shutdown *args, &block
	@shutdown_queue << [block, args]
	self
end

#portObject

Gets Iodine’s server port. Defaults to the command line ‘-p` argument, or the ENV or 3000 (in this order).



31
32
33
# File 'lib/iodine/settings.rb', line 31

def port
	@port
end

#port=(port) ⇒ Object

Sets Iodine’s server port. Defaults to the command line ‘-p` argument, or the ENV or 3000 (in this order).



27
28
29
# File 'lib/iodine/settings.rb', line 27

def port= port
	@port = port
end

#processes=(count) ⇒ Object

Sets the number of processes that should be spawned in Server mode. Defaults to 1 (no processes spawned).

  • Forking (spwaning processes) might NOT work on all systems (forking is supported by Ruby on Unix systems).

  • Please make sure your code is safe to fork into different processes. For instance, Websocket broadcasting and unicasting won’t work across different processes unless synced using an external Pub/Sub service/database such as Redis.

  • Forking might cause some tasks (such as time based tasks) to be performed twice (once for each process). This is a feature. To avoid duplicated task performance, use a task (delayed execution) to initialize any tasks you want to perform only once. While the initial time based tasks and the server are shared across processes, the initial task stack will only run on the main process.



22
23
24
# File 'lib/iodine/settings.rb', line 22

def processes= count
	@spawn_count = count
end

#protocolObject

Returns the cutrently active Iodine protocol (if exists).



51
52
53
# File 'lib/iodine/settings.rb', line 51

def protocol
	@protocol
end

#protocol=(protocol) ⇒ Object

Sets the Protocol the Iodine Server will use. Should be a child of Protocol. Defaults to nil (no server).

If the protocol passed does NOT inherit from Protocol, Iodine will cycle without initiating a server until stopped (TimedEvent mode).



46
47
48
49
# File 'lib/iodine/settings.rb', line 46

def protocol= protocol
	@stop = protocol ? false : true
	@protocol = protocol
end

#run(*args, &block) ⇒ Iodine Also known as: run_async

Accepts a block and runs it asynchronously. This method runs asynchronously and returns immediately.

use:

Iodine.run(arg1, arg2, arg3 ...) { |arg1, arg2, arg3...| do_something }

the block will be run within the current context, allowing access to current methods and variables.

Returns:

  • (Iodine)

    always returns the reactor object.



16
17
18
19
# File 'lib/iodine/core.rb', line 16

def run *args, &block
	@queue << [block, args]
	self
end

#run_after(seconds, *args, &block) ⇒ Iodine::TimedEvent

pushes a timed event to the timers’s stack

accepts:

seconds

the minimal amount of seconds to wait before calling the handler’s ‘call` method.

*arg

any arguments that will be passed to the handler’s ‘call` method.

&block

the block to execute.

A block is required.

On top of the arguments passed to the ‘run_after` method, the timer object will be passed as the last agrument to the receiving block.

Timed event’s time of execution is dependant on the workload and continuous uptime of the process (timed events AREN’T persistent).

Returns:



65
66
67
# File 'lib/iodine/timers.rb', line 65

def run_after seconds, *args, &block
	timed_job seconds, 1, args, block
end

#run_every(seconds, *args, &block) ⇒ Iodine::TimedEvent

pushes a repeated timed event to the timers’s stack

accepts:

seconds

the minimal amount of seconds to wait before calling the handler’s ‘call` method.

*arg

any arguments that will be passed to the handler’s ‘call` method.

&block

the block to execute.

A block is required.

On top of the arguments passed to the ‘run_after` method, the timer object will be passed as the last agrument to the receiving block.

Timed event’s time of execution is dependant on the workload and continuous uptime of the process (timed events AREN’T persistent unless you save and reload them yourself).

Returns:



83
84
85
# File 'lib/iodine/timers.rb', line 83

def run_every seconds, *args, &block
	timed_job seconds, -1, args, block
end

#signal_exitnil

Returns Signals Iodine to exit if it was running on Server or Timer mode. Tasks will rundown pending timeout.

Returns:

  • (nil)

    Signals Iodine to exit if it was running on Server or Timer mode. Tasks will rundown pending timeout.



29
30
31
32
# File 'lib/iodine/core.rb', line 29

def signal_exit
	Process.kill("INT", 0) unless @stop
	nil
end

#sslObject

Returns true if Iodine will require that new connection be encrypted.



61
62
63
# File 'lib/iodine/settings.rb', line 61

def ssl
	@ssl
end

#ssl=(required) ⇒ Object

Sets the SSL flag, so that Iodine will require that new connection be encrypted. Defaults to false unless the ‘ssl` command line flag is present.



57
58
59
# File 'lib/iodine/settings.rb', line 57

def ssl= required
	@ssl = required && true
end

#ssl_contextObject

Gets the SSL Context to be used when using an encrypted connection.



75
76
77
# File 'lib/iodine/settings.rb', line 75

def ssl_context
	@ssl_context ||= init_ssl_context
end

#ssl_context=(context) ⇒ Object

Sets the SSL Context to be used when using an encrypted connection. Defaults to a self signed certificate and no verification.

Manually setting the context will automatically set the SSL flag, so that Iodine will require encryption for new incoming connections.



69
70
71
72
# File 'lib/iodine/settings.rb', line 69

def ssl_context= context
	@ssl = true
	@ssl_context = context
end

#ssl_protocolsObject

Gets the SSL Protocol Hash used for



91
92
93
# File 'lib/iodine/settings.rb', line 91

def ssl_protocols
	@ssl_protocols
end

#ssl_protocols=(protocol_hash) ⇒ Object

Sets the an SSL Protocol Hash (‘’name’ => Protocol`), allowing dynamic Protocol Negotiation. At the moment only NPN is supported. ALPN support should be established in a future release.

  • please notice that using allowing dynamic Protocol Negotiation could cause unexpected protocol choices when attempting to implement Opportunistic Encryption with SSLConnector.

Raises:

  • (TypeError)


83
84
85
86
87
88
# File 'lib/iodine/settings.rb', line 83

def ssl_protocols= protocol_hash
	raise TypeError, "Iodine.ssl_protocols should be a Hash with Strings for keys (protocol identifiers) and Classes as values (Protocol classes)." unless protocol_hash.is_a?(Hash)
	@ssl = true
	ssl_context.npn_protocols = protocol_hash.keys
	@ssl_protocols = protocol_hash
end

#switch_protocol(*args) ⇒ Protocol

Replaces (or creates) an IO’s protocol object.

Accepts 2 arguments, in the following order:

io

the raw IO object.

protocol

a protocol instance - should be an instance of a class inheriting from Protocol. type will NOT be checked - but Iodine could break if there is a type mismatch.

Returns:



16
17
18
19
# File 'lib/iodine/io.rb', line 16

def switch_protocol *args
	@io_in << args
	args[1]
end

#threads=(count) ⇒ Object

Sets the number of threads in the thread pool used for executing the tasks. Defaults to 1 thread.



13
14
15
# File 'lib/iodine/settings.rb', line 13

def threads= count
	@thread_count = count
end

#timeTime

Returns Gets the last time at which the IO Reactor was last active (last “tick”).

Returns:

  • (Time)

    Gets the last time at which the IO Reactor was last active (last “tick”).



6
7
8
# File 'lib/iodine/io.rb', line 6

def time
	@time
end

#to_aArray

Returns an Array with all the currently active connection’s Protocol instances.

Returns:

  • (Array)

    Returns an Array with all the currently active connection’s Protocol instances.



22
23
24
# File 'lib/iodine/io.rb', line 22

def to_a
	@ios.values
end

#warn(data, &block) ⇒ String, ...

logs warning

Returns:

  • (String, Exception, Object)

    always returns the Object sent to the log.



23
24
25
26
# File 'lib/iodine/logging.rb', line 23

def warn data, &block
	@logger.warn data, &block if @logger
	data
end