Module: Iodine

Defined in:
lib/iodine.rb,
lib/iodine/http.rb,
lib/iodine/version.rb,
lib/iodine/protocol.rb,
lib/rack/handler/iodine.rb,
ext/iodine/iodine_core.c

Overview

Iodine is both a Rack server and a platform for writing evented network services on Ruby.

Here is a sample Echo server using Iodine:

# define the protocol for our service
class EchoProtocol
  @timeout = 10
  # this is just one possible callback with a recyclable buffer
  def on_message buffer
    # write the data we received
    write "echo: #{buffer}"
    # close the connection when the time comes
    close if buffer =~ /^bye[\n\r]/
  end
end
# create the service instance
Iodine.listen 3000, EchoProtocol
# start the service
Iodine.start

Please read the README file for an introduction to Iodine and an overview of it’s API.

Defined Under Namespace

Modules: Base, Protocol, Rack, Websocket

Constant Summary collapse

VERSION =
'0.3.3'.freeze

Class Method Summary collapse

Class Method Details

.countObject



605
606
607
608
# File 'ext/iodine/iodine_core.c', line 605

static VALUE iodine_count(VALUE self) {
  (void)(self);
  return ULONG2NUM(facil_count(NULL));
}

.listen(port, handler) ⇒ Object

Sets up a listening socket. Conncetions received at the assigned port will be handled by the assigned handler.

Multiple services (listening sockets) can be registered before starting the Iodine event loop.



445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'ext/iodine/iodine_core.c', line 445

static VALUE iodine_listen_dyn_protocol(VALUE self, VALUE port, VALUE handler) {
  // validate that the handler is a class and include the Iodine::Protocol
  if (TYPE(handler) == T_CLASS) {
    // include the Protocol module
    // // do we neet to check?
    // if (rb_mod_include_p(protocol, rDynProtocol) == Qfalse)
    rb_include_module(handler, DynamicProtocol);
    rb_extend_object(handler, DynamicProtocolClass);
  } else {
    rb_raise(rb_eTypeError, "The connection handler MUST be of type Class.");
    return Qnil;
  }
  if (TYPE(port) != T_FIXNUM && TYPE(port) != T_STRING)
    rb_raise(rb_eTypeError, "The port variable must be a Fixnum or a String.");
  if (TYPE(port) == T_FIXNUM)
    port = rb_funcall2(port, to_s_method_id, 0, NULL);
  rb_ivar_set(self, rb_intern("_port"), port);
  // listen
  facil_listen(.port = StringValueCStr(port), .udata = (void *)handler,
               .on_open = on_open_dyn_protocol,
               .on_start = on_server_start_for_handler,
               .on_finish = on_server_on_finish_for_handler);
  return self;
}

.processesObject

Get/Set the number of worker processes. A value greater then 1 will cause the Iodine to “fork” any extra worker processes needed.



54
55
56
# File 'lib/iodine.rb', line 54

def self.processes
  @processes
end

.processes=(count) ⇒ Object

Get/Set the number of worker processes. A value greater then 1 will cause the Iodine to “fork” any extra worker processes needed.



59
60
61
# File 'lib/iodine.rb', line 59

def self.processes=(count)
  @processes = count.to_i
end

.runObject

Runs the required block later. The block might run concurrently with the existing code (depending on the amount and availability of worker threads).

Returns the block object. The block will run only while Iodine is running (run will be delayed until Iodine.start is called, unless Iodine’s event loop is active).



528
529
530
531
532
533
534
535
536
537
538
539
# File 'ext/iodine/iodine_core.c', line 528

static VALUE iodine_run_async(VALUE self) {
  (void)(self);
  // requires a block to be passed
  rb_need_block();
  VALUE block = rb_block_proc();
  if (block == Qnil)
    return Qfalse;
  Registry.add(block);
  if (defer(iodine_run_once2, (void *)block, NULL))
    perror("ERROR: dropped defered task");
  return block;
}

.run_after(milliseconds) ⇒ Object

Runs the required block after the specified number of milliseconds have passed. Time is counted only once Iodine started running (using start).

Always returns a copy of the block object.



547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
# File 'ext/iodine/iodine_core.c', line 547

static VALUE iodine_run_after(VALUE self, VALUE milliseconds) {
  (void)(self);
  if (TYPE(milliseconds) != T_FIXNUM) {
    rb_raise(rb_eTypeError, "milliseconds must be a number");
    return Qnil;
  }
  size_t milli = FIX2UINT(milliseconds);
  // requires a block to be passed
  rb_need_block();
  VALUE block = rb_block_proc();
  if (block == Qnil)
    return Qfalse;
  Registry.add(block);
  facil_run_every(milli, 1, iodine_run_once, (void *)block, NULL);
  return block;
}

.run_every(*args) ⇒ Object

Runs the required block after the specified number of milliseconds have passed. Time is counted only once Iodine started running (using start).

Accepts:

milliseconds

the number of milliseconds between event repetitions.

repetitions

the number of event repetitions. Defaults to 0 (never ending).

block

(required) a block is required, as otherwise there is nothing to

perform.

The event will repeat itself until the number of repetitions had been delpeted.

Always returns a copy of the block object.



580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
# File 'ext/iodine/iodine_core.c', line 580

static VALUE iodine_run_every(int argc, VALUE *argv, VALUE self) {
  (void)(self);
  VALUE milliseconds, repetitions, block;

  rb_scan_args(argc, argv, "11&", &milliseconds, &repetitions, &block);

  if (TYPE(milliseconds) != T_FIXNUM) {
    rb_raise(rb_eTypeError, "milliseconds must be a number.");
    return Qnil;
  }
  if (repetitions != Qnil && TYPE(repetitions) != T_FIXNUM) {
    rb_raise(rb_eTypeError, "repetitions must be a number or `nil`.");
    return Qnil;
  }

  size_t milli = FIX2UINT(milliseconds);
  size_t repeat = (repetitions == Qnil) ? 0 : FIX2UINT(repetitions);
  // requires a block to be passed
  rb_need_block();
  Registry.add(block);
  facil_run_every(milli, repeat, iodine_run_always, (void *)block,
                  (void (*)(void *))Registry.remove);
  return block;
}

.startObject

Starts the Iodine event loop. This will hang the thread until an interrupt (‘^C`) signal is received.

Returns the Iodine module.



686
687
688
689
690
691
692
693
694
# File 'ext/iodine/iodine_core.c', line 686

static VALUE iodine_start(VALUE self) {
  if (iodine_http_review() == -1) {
    perror("Iodine couldn't start HTTP service... port busy? ");
    return Qnil;
  }
  rb_thread_call_without_gvl2(srv_start_no_gvl, (void *)self, NULL, NULL);

  return self;
}

.threadsObject

Get/Set the number of threads used in the thread pool (a static thread pool). Can be 1 (single working thread, the main thread will sleep) and can be 0 (the main thread will be used as the only active thread).



44
45
46
# File 'lib/iodine.rb', line 44

def self.threads
  @threads
end

.threads=(count) ⇒ Object

Get/Set the number of threads used in the thread pool (a static thread pool). Can be 1 (single working thread, the main thread will sleep) and can be 0 (the main thread will be used as the only active thread).



49
50
51
# File 'lib/iodine.rb', line 49

def self.threads=(count)
  @threads = count.to_i
end

.warmupObject

Runs the warmup sequence. warmup attempts to get every “autoloaded” (lazy loaded) file to load now instead of waiting for “first access”. This allows multi-threaded safety and better memory utilization during forking.

Use warmup when either processes or threads are set to more then 1.



67
68
69
70
71
72
73
74
75
# File 'lib/iodine.rb', line 67

def self.warmup
  # load anything marked with `autoload`, since autoload isn't thread safe nor fork friendly.
  Module.constants.each do |n|
    begin
      Object.const_get(n)
    rescue Exception => _e
    end
  end
end