GithubHelp home page GithubHelp logo

cool.io's Introduction

Cool.io

Cool.io is an event library for Ruby, built on the libev event library which provides a cross-platform interface to high performance system calls . This includes the epoll system call for Linux, the kqueue system call for BSDs and OS X, and the completion ports interface for Solaris.

Cool.io also binds asynchronous wrappers to Ruby's core socket classes so you can use them in conjunction with Cool.io to build asynchronous event-driven applications.

You can include Cool.io in your programs with:

require 'cool.io'

Anatomy

Cool.io builds on two core classes which bind to the libev API:

  • Cool.io::Loop - This class represents an event loop which uses underlying high performance system calls to wait for events.

  • Cool.io::Watcher - This is the base class for event observers. Once you attach an event observer to a loop and start running it, you will begin receiving callbacks to particlar methods when events occur.

Watchers

There are presently four types of watchers:

  • Cool.io::IOWatcher - This class waits for an IO object to become readable, writable, or both.

  • Cool.io::TimerWatcher - This class waits for a specified duration then fires an event. You can also configure it to fire an event at specified intervals.

  • Cool.io::StatWatcher - Monitors files or directories for changes

  • Cool.io::AsyncWatcher - Can be used to wake up a Cool.io::Loop running in a different thread. This allows each thread to run a separate Cool.io::Loop and for the different event loops to be able to signal each other.

Using Watchers

Watchers have five important methods:

  • attach(loop) - This binds a watcher to the specified event loop. If the watcher is already bound to a loop it will be detached first, then attached to the new one.

  • detach - This completely unbinds a watcher from an event loop.

  • disable - This stops the watcher from receiving events but does not unbind it from the loop. If you are trying to toggle a watcher on and off, it's best to use this method (and enable) as it performs better than completely removing the watcher from the event loop.

  • enable - This re-enables a watcher which has been disabled in the past. The watcher must still be bound to an event loop.

  • evloop - This returns the Cool.io::Loop object which the watcher is currently bound to.

Asynchronous Wrappers

Several classes which provide asynchronous event-driven wrappers for Ruby's core socket classes are also provided. Among these are:

  • Cool.io::TCPSocket - A buffered wrapper to core Ruby's Socket class for use with TCP sockets. You can asynchronously create outgoing TCP connections using its Cool.io::TCPSocket.connect method. Cool.io::TCPSocket provides write buffering to ensure that writing never blocks, and has asynchronous callbacks for several events, including when the connection is opened (or failed), when data is received, when the write buffer has been written out completely, and when the connection closes.

  • Cool.io::TCPServer - A wrapper for TCPServer which creates new instances of Cool.io::TCPSocket (or any subclass you wish to provide) whenever an incoming connection is received.

Example Program

Cool.io provides a Sinatra-like DSL for authoring event-driven programs:

require 'cool.io'
require 'cool.io/dsl'

ADDR = '127.0.0.1'
PORT = 4321

cool.io.connection :echo_server_connection do
  on_connect do
    puts "#{remote_addr}:#{remote_port} connected"
  end

  on_close do
    puts "#{remote_addr}:#{remote_port} disconnected"
  end

  on_read do |data|
    write data
  end
end

puts "Echo server listening on #{ADDR}:#{PORT}"
cool.io.server ADDR, PORT, :echo_server_connection
cool.io.run

This creates a new connection class called :echo_server_connection and defines a set of callbacks for when various events occur.

We then create a new server on the given address and port. When this server receives new connections, it will create new instances of the given connection class for each connection.

Finally, we kick everything off with cool.io.run. Calling cool.io.run will block, listening for events on our server.

Using Cool.io subclasses directly

Below is an example of how to write an echo server using a subclass instead of the DSL:

require 'cool.io'
HOST = 'localhost'
PORT = 4321

class EchoServerConnection < Cool.io::TCPSocket
  def on_connect
    puts "#{remote_addr}:#{remote_port} connected"
  end

  def on_close
    puts "#{remote_addr}:#{remote_port} disconnected"
  end

  def on_read(data)
    write data
  end
end

server = Cool.io::TCPServer.new(HOST, PORT, EchoServerConnection)
server.attach(Cool.io::Loop.default)

puts "Echo server listening on #{HOST}:#{PORT}"
Cool.io::Loop.default.run

Here a new observer type (EchoServerConnection) is made by subclassing an existing one and adding new implementations to existing event handlers.

A new event loop is created, and a new Cool.io::TCPServer (whose base class is Cool.io::Watcher) is created and attached to the event loop.

Once this is done, the event loop is started with event_loop.run. This method will block until there are no active watchers for the loop or the loop is stopped explicitly with event_loop.stop.

cool.io's People

Contributors

authornari avatar caueguerra avatar cosmo0920 avatar dirtyice avatar godfat avatar hsbt avatar ioquatix avatar k0kubun avatar kenhys avatar kou avatar larskanis avatar listout avatar luislavena avatar naritta avatar nurse avatar okkez avatar paddor avatar rdp avatar repeatedly avatar rhenium avatar sonots avatar taichi avatar tarcieri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cool.io's Issues

cool.io v1.7.1 fat gem doesn't include Ruby 3.0 binaries

On Windows, users still couldn't use cool.io v1.7.1 fat gem.
rubygems complains as follows:

cool.io-1.7.1-x64-mingw32 requires ruby version < 2.8.dev, >= 2.4, which is
incompatible with the current version, ruby 3.0.0p0
rake aborted!

"Assertion failed" when an event handler raises an exception

Hello,

cool.io dumps "Assertion failed" and terminates the execution when Loop#run_once is called after an event handler raises an exception.

$ echo | ruby t.rb
RuntimeError
ruby: loop.c:192: Coolio_Loop_run_once: Assertion `loop_data->ev_loop && !loop_data->events_received' failed.
Aborted

$ cat t.rb
require "cool.io"

class FooIO < Cool.io::IO
def on_read(buffer)
raise
end
end

l = Cool.io::Loop.default

FooIO.new($stdin).attach(l)

begin
l.run_once
rescue Exception
p $! #=> RuntimeError
end

l.run_once #=> Assertion failed.

JRuby support

Does it support JRuby? I ran example with JRuby 1.6.4. It gives me

LoadError: load error: cool.io_ext -- java.lang.UnsatisfiedLinkError: Could not locate Init_cool.io_ext module entry point

EM::Deferrable replacement

I'm currently using EventMachine, but Cool.IO seems nicer to me(and I think that libev is faster that libevent), but after checking all source I can't find anything like EM::Deferrable - is it unnecessary in Cool.IO or it is just not implemented yet?

Cool.io::TCPServer continues to receive data even if its close method is called

I expect Cool.io::TCPServer to stop receiving data after Cool.io::TCPServer#close is called, but it continues to receive data. Is this behavior expected?

Here is a reproducible code:

require 'socket'
require 'cool.io'

HOST = '127.0.0.1'
PORT = 1234

class ServerConnection < Coolio::TCPSocket
  def on_read(data)
    puts "received: #{data}"
  end
end

event_loop = Coolio::Loop.new
server = Cool.io::TCPServer.new(HOST, PORT, ServerConnection)
server.attach(event_loop)

server_thr = Thread.new { event_loop.run }
sock = TCPSocket.new(HOST, PORT)

puts "cool.io version: #{Coolio::VERSION}"

puts 'send a message'
sock.send "message", 0
sleep 1

server.close
puts 'server stopped'
sleep 1

puts 'send a message'
sock.send "message", 0
sleep 1

puts 'done'

Output

% docker run --rm -v $PWD/coolio_example.rb:/coolio_example.rb ruby:2.4.2 bash -c 'gem install cool.io && ruby /coolio_example.rb'
Building native extensions.  This could take a while...
Successfully installed cool.io-1.5.1
1 gem installed
cool.io version: 1.5.1
send a message
received: message
server stopped
send a message
received: message
done

Crash on Windows XP SP3 (Mingw32) with Ruby 1.9.1-p129

---revtest.rb
require 'rev'

HOST = '127.0.0.1'
PORT = 4321

server = Rev::TCPServer.new(HOST, PORT) do |c|
c.on_connect { puts "#{remote_addr}:#{remote_port} connected" }
c.on_close { puts "#{remote_addr}:#{remote_port} disconnected" }
c.on_read { |data| write data }
end

server.attach(Rev::Loop.default)

puts "Echo server listening on #{HOST}:#{PORT}"

Rev::Loop.default.run

C:\source\revtest>ruby -v
ruby 1.9.1p129 (2009-05-12 revision 23412) [i386-mingw32]

C:\source\revtest>ruby revtest.rb
Echo server listening on 127.0.0.1:4321
Assertion failed: ("libev: only socket fds supported in this configuration", ioc
tlsocket (anfd->handle, FIONREAD, &arg) == 0), file ../libev/ev.c, line 753

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

C:\source\revtest>gem list rev

*** LOCAL GEMS ***

rev (0.2.4)
revactor (0.1.4)

cool.io is no longer buildable on Ruby 3.3.0-dev

cool.io is no longer buildable on recent Ruby 3.3.0-dev.

We'll write a patch later.
Here is just for our note:

refs:

The error we got:
https://github.com/fluent/fluentd/actions/runs/5116211066/jobs/9540155372

2023-06-15T05:15:09.2576071Z compiling cool.io_ext.c
2023-06-15T05:15:09.2576325Z In file included from cool.io_ext.c:11:
2023-06-15T05:15:09.2576749Z cool.io.h:21:6: warning: "HAVE_RB_IO_T" is not defined, evaluates to 0 [-Wundef]
2023-06-15T05:15:09.2577109Z 21 | #if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR ==
2023-06-15T05:15:09.2577371Z 8)
2023-06-15T05:15:09.2577569Z       |      ^~~~~~~~~~~~
2023-06-15T05:15:09.2578462Z cool.io_ext.c: In function โ€˜Init_coolโ€™:
2023-06-15T05:15:09.2578866Z cool.io_ext.c:16:6: warning: old-style function definition
2023-06-15T05:15:09.2579199Z [-Wold-style-definition]
2023-06-15T05:15:09.2579431Z    16 | void Init_cool()
2023-06-15T05:15:09.2579643Z       |      ^~~~~~~~~
2023-06-15T05:15:09.2579853Z At top level:
2023-06-15T05:15:09.2580367Z cool.io_ext.c:13:14: warning: โ€˜mCoolioโ€™ defined but not used [-Wunused-variable]
2023-06-15T05:15:09.2580681Z    13 | static VALUE mCoolio = Qnil;
2023-06-15T05:15:09.2580948Z       |              ^~~~~~~
2023-06-15T05:15:09.2581397Z cc1: note: unrecognized command-line option โ€˜-Wno-self-assignโ€™ may have been
2023-06-15T05:15:09.2581736Z intended to silence earlier diagnostics
2023-06-15T05:15:09.2582205Z cc1: note: unrecognized command-line option โ€˜-Wno-parentheses-equalityโ€™ may have
2023-06-15T05:15:09.2582582Z been intended to silence earlier diagnostics
2023-06-15T05:15:09.2583375Z cc1: note: unrecognized command-line option โ€˜-Wno-constant-logical-operandโ€™ may
2023-06-15T05:15:09.2583904Z have been intended to silence earlier diagnostics
2023-06-15T05:15:09.2584184Z compiling iowatcher.c
2023-06-15T05:15:09.2584428Z In file included from iowatcher.c:16:
2023-06-15T05:15:09.2584857Z cool.io.h:21:6: warning: "HAVE_RB_IO_T" is not defined, evaluates to 0 [-Wundef]
2023-06-15T05:15:09.2585232Z 21 | #if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR ==
2023-06-15T05:15:09.2585496Z 8)
2023-06-15T05:15:09.2585669Z       |      ^~~~~~~~~~~~
2023-06-15T05:15:09.2585997Z iowatcher.c: In function โ€˜Init_coolio_iowatcherโ€™:
2023-06-15T05:15:09.2586390Z iowatcher.c:40:6: warning: old-style function definition
2023-06-15T05:15:09.2586706Z [-Wold-style-definition]
2023-06-15T05:15:09.2586966Z    40 | void Init_coolio_iowatcher()
2023-06-15T05:15:09.2587204Z       |      ^~~~~~~~~~~~~~~~~~~~~
2023-06-15T05:15:09.2587536Z iowatcher.c: In function โ€˜Coolio_IOWatcher_initializeโ€™:
2023-06-15T05:15:09.2587923Z iowatcher.c:68:5: warning: "HAVE_RB_IO_T" is not defined, evaluates to 0
2023-06-15T05:15:09.2588223Z [-Wundef]
2023-06-15T05:15:09.2588414Z    68 | #if HAVE_RB_IO_T
2023-06-15T05:15:09.2588622Z       |     ^~~~~~~~~~~~
2023-06-15T05:15:09.2588988Z iowatcher.c:71:3: error: unknown type name โ€˜OpenFileโ€™; did you mean
2023-06-15T05:15:09.2589292Z โ€˜GetOpenFileโ€™?
2023-06-15T05:15:09.2589519Z    71 |   OpenFile *fptr;
2023-06-15T05:15:09.2589730Z       |   ^~~~~~~~
2023-06-15T05:15:09.2589922Z       |   GetOpenFile
2023-06-15T05:15:09.2590324Z iowatcher.c:79:15: warning: assignment discards โ€˜constโ€™ qualifier from pointer
2023-06-15T05:15:09.2590725Z target type [-Wdiscarded-qualifiers]
2023-06-15T05:15:09.2590988Z    79 |     flags_str = "r";
2023-06-15T05:15:09.2591185Z       |               ^
2023-06-15T05:15:09.2591423Z In file included from iowatcher.c:9:
2023-06-15T05:15:09.2591838Z /home/runner/.rubies/ruby-head/include/ruby-3.3.0+0/ruby/io.h:395:55: warning:
2023-06-15T05:15:09.2592294Z assignment to โ€˜int *โ€™ from incompatible pointer type โ€˜struct rb_io *โ€™
2023-06-15T05:15:09.2592696Z [-Wincompatible-pointer-types]
2023-06-15T05:15:09.2593025Z 395 | #define RB_IO_POINTER(obj,fp) rb_io_check_closed((fp) =
2023-06-15T05:15:09.2593357Z RFILE(rb_io_taint_check(obj))->fptr)
2023-06-15T05:15:09.2593621Z       |                                                       ^
2023-06-15T05:15:09.2594019Z /home/runner/.rubies/ruby-head/include/ruby-3.3.0+0/ruby/io.h:401:21: note: in
2023-06-15T05:15:09.2594372Z expansion of macro โ€˜RB_IO_POINTERโ€™
2023-06-15T05:15:09.2594652Z   401 | #define GetOpenFile RB_IO_POINTER
2023-06-15T05:15:09.2594904Z       |                     ^~~~~~~~~~~~~
2023-06-15T05:15:09.2595260Z iowatcher.c:91:3: note: in expansion of macro โ€˜GetOpenFileโ€™
2023-06-15T05:15:09.2595599Z    91 |   GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
2023-06-15T05:15:09.2596399Z       |   ^~~~~~~~~~~
2023-06-15T05:15:09.2596797Z /home/runner/.rubies/ruby-head/include/ruby-3.3.0+0/ruby/io.h:395:55: warning:
2023-06-15T05:15:09.2597284Z passing argument 1 of โ€˜rb_io_check_closedโ€™ from incompatible pointer type
2023-06-15T05:15:09.2597682Z [-Wincompatible-pointer-types]
2023-06-15T05:15:09.2598014Z 395 | #define RB_IO_POINTER(obj,fp) rb_io_check_closed((fp) =
2023-06-15T05:15:09.2598348Z RFILE(rb_io_taint_check(obj))->fptr)
2023-06-15T05:15:09.2598607Z |                                                 
2023-06-15T05:15:09.2598842Z ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2023-06-15T05:15:09.2599072Z       |                                                       |
2023-06-15T05:15:09.2599333Z       |                                                       int *
2023-06-15T05:15:09.2599744Z /home/runner/.rubies/ruby-head/include/ruby-3.3.0+0/ruby/io.h:401:21: note: in
2023-06-15T05:15:09.2600117Z expansion of macro โ€˜RB_IO_POINTERโ€™
2023-06-15T05:15:09.2600383Z   401 | #define GetOpenFile RB_IO_POINTER
2023-06-15T05:15:09.2600636Z       |                     ^~~~~~~~~~~~~
2023-06-15T05:15:09.2601182Z iowatcher.c:91:3: note: in expansion of macro โ€˜GetOpenFileโ€™
2023-06-15T05:15:09.2601648Z    91 |   GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
2023-06-15T05:15:09.2601929Z       |   ^~~~~~~~~~~
2023-06-15T05:15:09.2602315Z /home/runner/.rubies/ruby-head/include/ruby-3.3.0+0/ruby/io.h:638:34: note:
2023-06-15T05:15:09.2602753Z expected โ€˜rb_io_t *โ€™ {aka โ€˜struct rb_io *โ€™} but argument is of type โ€˜int *โ€™
2023-06-15T05:15:09.2603086Z   638 | void rb_io_check_closed(rb_io_t *fptr);
2023-06-15T05:15:09.2603349Z       |                         ~~~~~~~~~^~~~
2023-06-15T05:15:09.2603587Z In file included from ev_wrap.h:9,
2023-06-15T05:15:09.2603847Z                  from iowatcher.c:14:
2023-06-15T05:15:09.2604259Z ../libev/ev.h:687:4: warning: dereferencing type-punned pointer will break
2023-06-15T05:15:09.2604659Z strict-aliasing rules [-Wstrict-aliasing]
2023-06-15T05:15:09.2605021Z   687 |   ((ev_watcher *)(void *)(ev))->active  =       \
2023-06-15T05:15:09.2605274Z       |   ~^~~~~~~~~~~~~~~~~~~~~~~~~~~
2023-06-15T05:15:09.2605643Z ../libev/ev.h:707:51: note: in expansion of macro โ€˜ev_initโ€™
2023-06-15T05:15:09.2605975Z 707 | #define ev_io_init(ev,cb,fd,events)          do { ev_init ((ev), (cb));
2023-06-15T05:15:09.2606287Z ev_io_set ((ev),(fd),(events)); } while (0)
2023-06-15T05:15:09.2606556Z       |                                                   ^~~~~~~
2023-06-15T05:15:09.2606910Z iowatcher.c:94:3: note: in expansion of macro โ€˜ev_io_initโ€™
2023-06-15T05:15:09.2607296Z 94 |   ev_io_init(&watcher_data->event_types.ev_io,
2023-06-15T05:15:09.2607626Z Coolio_IOWatcher_libev_callback, FPTR_TO_FD(fptr), events);
2023-06-15T05:15:09.2607896Z       |   ^~~~~~~~~~
2023-06-15T05:15:09.2608268Z ../libev/ev.h:688:4: warning: dereferencing type-punned pointer will break
2023-06-15T05:15:09.2608676Z strict-aliasing rules [-Wstrict-aliasing]
2023-06-15T05:15:09.2609052Z   688 |   ((ev_watcher *)(void *)(ev))->pending = 0;    \
2023-06-15T05:15:09.2609293Z       |   ~^~~~~~~~~~~~~~~~~~~~~~~~~~~
2023-06-15T05:15:09.2609646Z ../libev/ev.h:707:51: note: in expansion of macro โ€˜ev_initโ€™
2023-06-15T05:15:09.2609997Z 707 | #define ev_io_init(ev,cb,fd,events)          do { ev_init ((ev), (cb));
2023-06-15T05:15:09.2610292Z ev_io_set ((ev),(fd),(events)); } while (0)
2023-06-15T05:15:09.2610553Z       |                                                   ^~~~~~~
2023-06-15T05:15:09.2610919Z iowatcher.c:94:3: note: in expansion of macro โ€˜ev_io_initโ€™
2023-06-15T05:15:09.2611284Z 94 |   ev_io_init(&watcher_data->event_types.ev_io,
2023-06-15T05:15:09.2611612Z Coolio_IOWatcher_libev_callback, FPTR_TO_FD(fptr), events);
2023-06-15T05:15:09.2611874Z       |   ^~~~~~~~~~
2023-06-15T05:15:09.2612257Z ../libev/ev.h:732:50: warning: dereferencing type-punned pointer will break
2023-06-15T05:15:09.2612637Z strict-aliasing rules [-Wstrict-aliasing]
2023-06-15T05:15:09.2612977Z 732 | # define ev_set_priority(ev,pri)             (   (ev_watcher *)(void
2023-06-15T05:15:09.2613300Z *)(ev))->priority = (pri)
2023-06-15T05:15:09.2613564Z |                                             
2023-06-15T05:15:09.2613788Z ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
2023-06-15T05:15:09.2614148Z ../libev/ev.h:689:3: note: in expansion of macro โ€˜ev_set_priorityโ€™
2023-06-15T05:15:09.2614451Z   689 |   ev_set_priority ((ev), 0);                    \
2023-06-15T05:15:09.2614691Z       |   ^~~~~~~~~~~~~~~
2023-06-15T05:15:09.2615067Z ../libev/ev.h:707:51: note: in expansion of macro โ€˜ev_initโ€™
2023-06-15T05:15:09.2615391Z 707 | #define ev_io_init(ev,cb,fd,events)          do { ev_init ((ev), (cb));
2023-06-15T05:15:09.2615702Z ev_io_set ((ev),(fd),(events)); } while (0)
2023-06-15T05:15:09.2615965Z       |                                                   ^~~~~~~
2023-06-15T05:15:09.2616329Z iowatcher.c:94:3: note: in expansion of macro โ€˜ev_io_initโ€™
2023-06-15T05:15:09.2616695Z 94 |   ev_io_init(&watcher_data->event_types.ev_io,
2023-06-15T05:15:09.2617025Z Coolio_IOWatcher_libev_callback, FPTR_TO_FD(fptr), events);
2023-06-15T05:15:09.2617291Z       |   ^~~~~~~~~~
2023-06-15T05:15:09.2617910Z ../libev/ev.h:738:79: warning: dereferencing type-punned pointer will break
2023-06-15T05:15:09.2618317Z strict-aliasing rules [-Wstrict-aliasing]
2023-06-15T05:15:09.2618637Z 738 | # define ev_set_cb(ev,cb_)                   (ev_cb_ (ev) = (cb_),
2023-06-15T05:15:09.2619028Z memmove (&((ev_watcher *)(ev))->cb, &ev_cb_ (ev), sizeof (ev_cb_ (ev))))
2023-06-15T05:15:09.2619338Z |                                                                         
2023-06-15T05:15:09.2619565Z ~^~~~~~~~~~~~~~~~~~~
2023-06-15T05:15:09.2619890Z ../libev/ev.h:690:3: note: in expansion of macro โ€˜ev_set_cbโ€™
2023-06-15T05:15:09.2620188Z   690 |   ev_set_cb ((ev), cb_);                        \
2023-06-15T05:15:09.2620420Z       |   ^~~~~~~~~
2023-06-15T05:15:09.2620753Z ../libev/ev.h:707:51: note: in expansion of macro โ€˜ev_initโ€™
2023-06-15T05:15:09.2621077Z 707 | #define ev_io_init(ev,cb,fd,events)          do { ev_init ((ev), (cb));
2023-06-15T05:15:09.2621387Z ev_io_set ((ev),(fd),(events)); } while (0)
2023-06-15T05:15:09.2621674Z       |                                                   ^~~~~~~
2023-06-15T05:15:09.2622026Z iowatcher.c:94:3: note: in expansion of macro โ€˜ev_io_initโ€™
2023-06-15T05:15:09.2622402Z 94 |   ev_io_init(&watcher_data->event_types.ev_io,
2023-06-15T05:15:09.2622726Z Coolio_IOWatcher_libev_callback, FPTR_TO_FD(fptr), events);
2023-06-15T05:15:09.2622978Z       |   ^~~~~~~~~~
2023-06-15T05:15:09.2623361Z cool.io.h:22:37: error: request for member โ€˜fโ€™ in something not a structure or
2023-06-15T05:15:09.2623648Z union
2023-06-15T05:15:09.2623933Z    22 | #define FPTR_TO_FD(fptr) fileno(fptr->f)
2023-06-15T05:15:09.2624194Z       |                                     ^~
2023-06-15T05:15:09.2624545Z ../libev/ev.h:693:63: note: in definition of macro โ€˜ev_io_setโ€™
2023-06-15T05:15:09.2624949Z 693 | #define ev_io_set(ev,fd_,events_)            do { (ev)->fd = (fd_);
2023-06-15T05:15:09.2625308Z (ev)->events = (events_) | EV__IOFDSET; } while (0)
2023-06-15T05:15:09.2625588Z       |                                                               ^~~
2023-06-15T05:15:09.2625967Z iowatcher.c:94:3: note: in expansion of macro โ€˜ev_io_initโ€™
2023-06-15T05:15:09.2626329Z 94 |   ev_io_init(&watcher_data->event_types.ev_io,
2023-06-15T05:15:09.2626654Z Coolio_IOWatcher_libev_callback, FPTR_TO_FD(fptr), events);
2023-06-15T05:15:09.2626917Z       |   ^~~~~~~~~~
2023-06-15T05:15:09.2627244Z iowatcher.c:94:81: note: in expansion of macro โ€˜FPTR_TO_FDโ€™
2023-06-15T05:15:09.2627619Z 94 |   ev_io_init(&watcher_data->event_types.ev_io,
2023-06-15T05:15:09.2627943Z Coolio_IOWatcher_libev_callback, FPTR_TO_FD(fptr), events);
2023-06-15T05:15:09.2628243Z |                                                                         
2023-06-15T05:15:09.2628454Z ^~~~~~~~~~
2023-06-15T05:15:09.2628673Z iowatcher.c: At top level:
2023-06-15T05:15:09.2629095Z cc1: note: unrecognized command-line option โ€˜-Wno-self-assignโ€™ may have been
2023-06-15T05:15:09.2629432Z intended to silence earlier diagnostics
2023-06-15T05:15:09.2629918Z cc1: note: unrecognized command-line option โ€˜-Wno-parentheses-equalityโ€™ may have
2023-06-15T05:15:09.2630298Z been intended to silence earlier diagnostics
2023-06-15T05:15:09.2630753Z cc1: note: unrecognized command-line option โ€˜-Wno-constant-logical-operandโ€™ may
2023-06-15T05:15:09.2631140Z have been intended to silence earlier diagnostics
2023-06-15T05:15:09.2631441Z make: *** [Makefile:248: iowatcher.o] Error 1
2023-06-15T05:15:09.2631610Z 
2023-06-15T05:15:09.2631694Z make failed, exit code 2

CPU100% on Windows Server 2012

I got a problem with version 1.2.1.
CPU Usage becomes 100% on Widows Server 2012, Ruby version is 1.9.3 p545
Please try this code.

require 'cool.io'
ADDR = '127.0.0.1'
PORT = 4321
cool.io.server ADDR, PORT do
end
cool.io.run

Question

Basically i have a custom cool.io tcpsockt which is acting as an http proxy, after i am done parsing the http headers, i am trying to use the cool.io http client to make the parsed and modified request with custom callbacks and a reference to the original tcp connection. Problem is it never connects, i attach a new loop to it and run but my on_connect etc never even get called

require 'cool.io'
require 'http/parser'
require 'uri'

class Hash
  def downcase_key
    keys.each do |k|
      store(k.downcase, Array === (v = delete(k)) ? v.map(&:downcase_key) : v)
    end
    self
  end
end

module ShadyProxy
  extend self

  module ClientParserCallbacks
    extend self

    def on_message_complete(conn)
      lambda do
        puts "on_message_complete"
        PluginHooks.before_request_to_server(conn)
      end
    end

    def on_headers_complete(conn)
      lambda do |headers|
        conn.headers = headers
      end
    end

    def on_body(conn)
      lambda do |chunk|
        conn.body << chunk
      end
    end

  end

  module PluginHooks
    extend self

    def before_request_to_server(conn)
      # modify request here
      conn.parser.headers.delete "Proxy-Connection"
      conn.parser.headers.downcase_key
      send_to_server(conn)
    end

    def send_to_server(conn)
      parser = conn.parser
      uri = URI::parse(parser.request_url)
      l = Coolio::Loop.default
      puts uri.scheme + "://" + uri.host
      c = ShadyHttpClient.connect(uri.scheme + "://" + uri.host,uri.port).attach(l)
      c.connection_reference = conn
      c.request(parser.http_method,uri.request_uri)
      l.run #should be calling on_connect after this runs right?
    end

    def before_reply_to_client(conn)

    end

  end

  class ShadyHttpClient < Coolio::HttpClient

    def connection_reference=(conn)
      puts "haz connection ref"
      @connection_reference = conn
    end

    def connection_reference
      @connection_reference
    end

    def on_connect
      super
      puts "cool connect" #never gets here
      @headers = nil
      @body = ''
      @buffer = ''
    end

    def on_connect_failed
      super
      puts "***********************************************" # or here
    end

    def on_response_header(header)
      @headers = header
    end

    def on_body_data(data)
      puts "on data?"
      @body << data
      STDOUT.write data
    end

    def on_request_complete
      puts "Headers"
      puts @headers
      puts "Body"
      puts @body
    end


    def on_error(reason)
      STDERR.puts "Error: #{reason}"
    end

  end

  class ShadyProxyConnection < Cool.io::TCPSocket
    attr_accessor :headers, :body, :buffer, :parser

    def on_connect
      @headers = nil
      @body = ''
      @buffer = ''
      @parser = Http::Parser.new
      @parser.on_message_complete = ClientParserCallbacks.on_message_complete(self)
      @parser.on_headers_complete = ClientParserCallbacks.on_headers_complete(self)
      @parser.on_body = ClientParserCallbacks.on_body(self)
    end

    def on_close
      puts "huh?"
    end

    def on_read(data)
      @buffer << data
      @parser << data 
    end

  end

  module Server
    def run(opts)
      begin
      # Start our server to handle connections (will raise things on errors)
      l = Coolio::Loop.new
      @socket = Cool.io::TCPServer.new(opts[:host],opts[:port], ShadyProxy::ShadyProxyConnection)
      @socket.attach(l)
      l.run
      # Handle every request in another thread
      loop do
        #s = @socket.accept
        Thread.new s = @socket.accept #, &method(:do_request)
      end 
      # CTRL-C
      rescue Interrupt
        puts 'Got Interrupt..'
      # Ensure that we release the socket on errors
      ensure
        if @socket
          @socket.close
          puts 'Socked closed..'
        end
        puts 'Quitting.'
      end

    end

    module_function :run
  end

end

ShadyProxy::Server.run(:host => '0.0.0.0',:port => 1234)

I can't find Cool.io::StatWatcher

I can see async_watcher.rb, iowatcher.rb and timer_watcher.rb but I can't find any implementation of the StatWatcher. Is this already implemented?

Easier HTTP client for cool.io?

I am a bit tired of em-http-request, so I am looking for alternative HTTP
clients for event-driven architecture, either on eventmachine or cool.io.

However, the built in HTTP client in cool.io doesn't seem very appearing
to me... I am looking for something like rest-client. Would you accept
something like below merged into cool.io?

The usage would be like this:

Client.request(:url => 'http://graph.facebook.com/spellbook'){ |r, h|
  puts "r: #{r}"
  puts "h: #{h}"
}
Coolio::Loop.default.run
puts "DONE"

A quick implementation:

require 'uri'
require 'rest-client'
require 'cool.io'

class Client < Coolio::HttpClient
  def self.request opts={}, &block
    method  = opts[:method]  || opts['method']  || :get
    url     = opts[:url]     || opts['url']
    payload = opts[:payload] || opts['payload'] || {}
    headers = opts[:headers] || opts['headers']
    query   = opts[:query]   || opts['query']   || {}
    loop    = opts[:loop]    || opts['loop']    || Coolio::Loop.default

    uri = URI.parse(url)
    q   = (uri.query || '').split('&').inject({}){ |r, i|
            k, v = i.split('=')
            r[k] = v
            r}.merge(query.inject({}){ |r, (k, v)| r[k.to_s] = v.to_s; r })

    connect(uri.host, uri.port).attach(loop).
      request(method.to_s.upcase, uri.path, :query => q,
             :body => RestClient::Payload.generate(payload).read, &block)
  end

  def initialize socket
    super
    @rc_data = []
  end

  def request method, path, opts={}, &block
    @rc_callback = block
    super
  end

  def on_response_header response_header
    @rc_response_header = response_header
  end

  def on_body_data data
    @rc_data << data
  end

  def on_request_complete
    super
    @rc_callback.call(@rc_data.join, @rc_response_header)
  end
end

Client.request(:url => 'http://graph.facebook.com/spellbook'){ |r, h|
  puts "r: #{r}"
  puts "h: #{h}"
}
Coolio::Loop.default.run
puts "DONE"

This would be used inside rest-core.

Crash with telnet

Hi,

I'm now using the server with Rev::TCPServer.new, and try to connect by telnet command on Linux. After the connection is established and typing the enter key, then the server crashed. This is the backtrace.

 unexpected response message
  /opt/sedue/gems/clx-0.0.6/lib/clx/rpc.rb:252:in `on_response'
  /opt/sedue/gems/clx-0.0.6/lib/clx/rpc.rb:76:in `on_response'
  /opt/sedue/gems/clx-0.0.6/lib/clx/rpc.rb:55:in `on_message'
  /opt/sedue/gems/clx-0.0.6/lib/clx/rpc.rb:112:in `on_read'
  /opt/sedue/gems/rev-0.3.1/lib/rev/io.rb:108:in `on_readable'
  /opt/sedue/gems/rev-0.3.1/lib/rev/io.rb:163:in `__send__'
  /opt/sedue/gems/rev-0.3.1/lib/rev/io.rb:163:in `on_readable'
  /opt/sedue/gems/rev-0.3.1/lib/rev/loop.rb:96:in `run_once'
  /opt/sedue/gems/rev-0.3.1/lib/rev/loop.rb:96:in `run'
  /opt/sedue/gems/clx-0.0.6/lib/clx/rpc.rb:342:in `run'
  /opt/sedue/gems/clx-0.0.6/lib/clx/core.rb:58:in `run'
  /opt/sedue/gems/clx-0.0.6/bin/clx-agent:152
  /opt/sedue/bin/clx-agent:19:in `load'
  /opt/sedue/bin/clx-agent:19
ruby: rev_loop.c:183: Rev_Loop_run_once: Assertion `loop_data->ev_loop && !loop_data->events_received' failed.

Could you look into this problem?

Thanks in advance.
Kazuki

Two test failures with IPv6?

Failures:

  1) DNS connects to valid domains
     Failure/Error: c.close

     NoMethodError:
       undefined method `close' for nil:NilClass
     # ./spec/dns_spec.rb:32:in `ensure in block (2 levels) in <top (required)>'
     # ./spec/dns_spec.rb:32:in `block (2 levels) in <top (required)>'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:254:in `instance_exec'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:254:in `block in run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:500:in `block in with_around_and_singleton_context_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:457:in `block in with_around_example_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/hooks.rb:464:in `block in run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/hooks.rb:602:in `run_around_example_hooks_for'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/hooks.rb:464:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:457:in `with_around_example_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:500:in `with_around_and_singleton_context_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:251:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:629:in `block in run_examples'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:625:in `map'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:625:in `run_examples'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:591:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:116:in `block (3 levels) in run_specs'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:116:in `map'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:116:in `block (2 levels) in run_specs'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/configuration.rb:1989:in `with_suite_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:111:in `block in run_specs'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:74:in `report'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:110:in `run_specs'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:87:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:71:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:45:in `invoke'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/exe/rspec:4:in `<main>'
     # ------------------
     # --- Caused by: ---
     # SocketError:
     #   getaddrinfo: Address family for hostname not supported
     #   ./lib/cool.io/dns_resolver.rb:110:in `send'

  2) DNS fires on_resolve_failed for invalid domains
     Failure/Error: @socket.send request_message, 0, @nameservers.first, DNS_PORT

     SocketError:
       getaddrinfo: Address family for hostname not supported
     # ./lib/cool.io/dns_resolver.rb:110:in `send'
     # ./lib/cool.io/dns_resolver.rb:110:in `send_request'
     # ./lib/cool.io/dns_resolver.rb:77:in `attach'
     # (eval):3:in `attach'
     # ./spec/dns_spec.rb:37:in `block (2 levels) in <top (required)>'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:254:in `instance_exec'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:254:in `block in run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:500:in `block in with_around_and_singleton_context_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:457:in `block in with_around_example_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/hooks.rb:464:in `block in run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/hooks.rb:602:in `run_around_example_hooks_for'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/hooks.rb:464:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:457:in `with_around_example_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:500:in `with_around_and_singleton_context_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:251:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:629:in `block in run_examples'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:625:in `map'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:625:in `run_examples'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:591:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:116:in `block (3 levels) in run_specs'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:116:in `map'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:116:in `block (2 levels) in run_specs'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/configuration.rb:1989:in `with_suite_hooks'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:111:in `block in run_specs'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:74:in `report'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:110:in `run_specs'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:87:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:71:in `run'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:45:in `invoke'
     # /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/exe/rspec:4:in `<main>'

Finished in 5.48 seconds (files took 0.17962 seconds to load)
38 examples, 2 failures

Failed examples:

rspec ./spec/dns_spec.rb:24 # DNS connects to valid domains
rspec ./spec/dns_spec.rb:36 # DNS fires on_resolve_failed for invalid domains

/usr/bin/ruby -I/usr/lib/ruby/gems/2.7.0/gems/rspec-support-3.8.0/lib:/usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/lib /usr/lib/ruby/gems/2.7.0/gems/rspec-core-3.8.0/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb failed

Hi,
I'm trying to build the gem on my local workstation to create a native arch linux package. during the test run I get the above issues. If I remove my IPv6 resolver from /etc/resolv.conf the tests pass. Any idea how to fix this?

LoadError in Windows: Init_cool could not be found

I have successfully installed Ruby and DevKit from RubyInstaller project. My ruby version is:

C:\xxx>ruby --version
ruby 1.9.2p136 (2010-12-25) [i386-mingw32]

I installed cool.io using the gem:

C:\xxx>gem install cool.io --platform ruby
Temporarily enhancing PATH to include DevKit...
Building native extensions. This could take a while...
Building native extensions. This could take a while...
Successfully installed iobuffer-1.0.0
Successfully installed cool.io-1.0.0
2 gems installed
Installing ri documentation for iobuffer-1.0.0...
Installing ri documentation for cool.io-1.0.0...
Installing RDoc documentation for iobuffer-1.0.0...
Installing RDoc documentation for cool.io-1.0.0...

But, when I attempt to load the gem, it gives me LoadError saying that Init_cool is undefined:

C:\xxx>irb
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'cool.io'
LoadError: 127: The specified procedure could not be found. - Init_cool
C:/Ruby192/lib/ruby/gems/1.9.1/gems/cool.io-1.0.0/lib/cool.io_ext.so
from internal:lib/rubygems/custom_require:29:in require' from <internal:lib/rubygems/custom_require>:29:inrequire'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/cool.io-1.0.0/lib/cool.io.rb:9:
in <top (required)>' from <internal:lib/rubygems/custom_require>:33:inrequire'
from internal:lib/rubygems/custom_require:33:in rescue in require' from <internal:lib/rubygems/custom_require>:29:inrequire'
from (irb):2
from C:/Ruby192/bin/irb:12:in `

'
irb(main):003:0>

I am using Windows XP Professional version 2002 Service Pack 3 (32-bit).

Thread#join using coolio makes a process down on Windows.

Try following code. I got an error on Ruby 1.9 & 2.0, Windows 7.
Anybody can help ? Something wrong ?

require 'thread'
require 'cool.io'

default_loop = nil
w = Coolio::TimerWatcher.new(1, true)
w.on_timer do
  p Time.new
end
t = Thread.new do
  default_loop = Coolio::Loop.default
  default_loop.attach w
  default_loop.run
  p "thread exit"
end

gets
default_loop.stop
t.join

Output is as follows.

#<Thread:0x2278a10 run>
2014-07-30 18:43:32 +0900
2014-07-30 18:43:33 +0900
a
"thread exit"
[BUG] win32_mutex_lock: WAIT_ABANDONED
ruby 2.0.0p481 (2014-05-08) [i386-mingw32]

-- Control frame information -----------------------------------------------


-- C level backtrace information -------------------------------------------
C:\Windows\SYSTEM32\ntdll.dll(KiFastSystemCallRet+0x0) [0x779570F4]
C:\Windows\system32\kernel32.dll(WaitForSingleObjectEx+0x43) [0x75F7C3D3]
C:\Windows\system32\kernel32.dll(WaitForSingleObject+0x12) [0x75F7C382]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_vm_bugreport+0xa7) [0x668F8107]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_name_err_mesg_new+0x69d) [0x667BE36D]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_bug+0x2e) [0x667BF16E]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_mutex_trylock+0x52c) [0x668FEFAC]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_thread_sleep_forever+0x2e2) [0x66902C92]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_thread_sleep_forever+0x48d) [0x66902E3D]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_ensure+0x9b) [0x667C736B]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_thread_list+0xf5f) [0x668FE65F]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_thread_list+0x109f) [0x668FE79F]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_error_arity+0x129) [0x668E3629]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_f_send+0x518) [0x668F2028]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_vm_localjump_error+0x260d) [0x668E808D]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_vm_localjump_error+0x6784) [0x668EC204]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_iseq_eval_main+0x131) [0x668F50D1]
C:\Ruby200\bin\msvcrt-ruby200.dll(rb_check_copyable+0x37c1) [0x667C4641]
C:\Ruby200\bin\msvcrt-ruby200.dll(ruby_run_node+0x2d) [0x667C6A5D]
 [0x0040287F]
 [0x004013FA]
C:\Windows\system32\kernel32.dll(BaseThreadInitThunk+0x12) [0x75F7EE1C]
C:\Windows\SYSTEM32\ntdll.dll(RtlInitializeExceptionChain+0xef) [0x779737EB]

-- Other runtime information -----------------------------------------------

* Loaded script: test_timer.rb

* Loaded features:

    0 enumerator.so
    1 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/enc/encdb.so
    2 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/enc/windows_31j.so
    3 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/enc/trans/transdb.so
    4 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/rbconfig.rb
    5 C:/Ruby200/lib/ruby/2.0.0/rubygems/compatibility.rb
    6 C:/Ruby200/lib/ruby/2.0.0/rubygems/defaults.rb
    7 C:/Ruby200/lib/ruby/2.0.0/rubygems/deprecate.rb
    8 C:/Ruby200/lib/ruby/2.0.0/rubygems/errors.rb
    9 C:/Ruby200/lib/ruby/2.0.0/rubygems/version.rb
   10 C:/Ruby200/lib/ruby/2.0.0/rubygems/requirement.rb
   11 C:/Ruby200/lib/ruby/2.0.0/rubygems/platform.rb
   12 C:/Ruby200/lib/ruby/2.0.0/rubygems/specification.rb
   13 C:/Ruby200/lib/ruby/2.0.0/rubygems/exceptions.rb
   14 C:/Ruby200/lib/ruby/2.0.0/rubygems/defaults/operating_system.rb
   15 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/enc/utf_16le.so
   16 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/enc/trans/utf_16_32.so
   17 C:/Ruby200/lib/ruby/2.0.0/rubygems/core_ext/kernel_gem.rb
   18 C:/Ruby200/lib/ruby/2.0.0/thread.rb
   19 C:/Ruby200/lib/ruby/2.0.0/monitor.rb
   20 C:/Ruby200/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb
   21 C:/Ruby200/lib/ruby/2.0.0/rubygems.rb
   22 C:/Ruby200/lib/ruby/2.0.0/rubygems/path_support.rb
   23 C:/Ruby200/lib/ruby/2.0.0/rubygems/dependency.rb
   24 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/version.rb
   25 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/custom_require.rb
   26 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/iobuffer_ext.so
   27 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io_ext.so
   28 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/loop.rb
   29 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/meta.rb
   30 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/io.rb
   31 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/iowatcher.rb
   32 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/timer_watcher.rb
   33 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/async_watcher.rb
   34 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/socket.so
   35 C:/Ruby200/lib/ruby/2.0.0/socket.rb
   36 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/listener.rb
   37 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/fcntl.so
   38 C:/Ruby200/lib/ruby/2.0.0/timeout.rb
   39 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/digest.so
   40 C:/Ruby200/lib/ruby/2.0.0/digest.rb
   41 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/openssl.so
   42 C:/Ruby200/lib/ruby/2.0.0/openssl/bn.rb
   43 C:/Ruby200/lib/ruby/2.0.0/openssl/cipher.rb
   44 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/stringio.so
   45 C:/Ruby200/lib/ruby/2.0.0/openssl/config.rb
   46 C:/Ruby200/lib/ruby/2.0.0/openssl/digest.rb
   47 C:/Ruby200/lib/ruby/2.0.0/openssl/x509.rb
   48 C:/Ruby200/lib/ruby/2.0.0/openssl/buffering.rb
   49 C:/Ruby200/lib/ruby/2.0.0/openssl/ssl.rb
   50 C:/Ruby200/lib/ruby/2.0.0/openssl.rb
   51 C:/Ruby200/lib/ruby/2.0.0/securerandom.rb
   52 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/fiddle.so
   53 C:/Ruby200/lib/ruby/2.0.0/fiddle/function.rb
   54 C:/Ruby200/lib/ruby/2.0.0/fiddle/closure.rb
   55 C:/Ruby200/lib/ruby/2.0.0/fiddle.rb
   56 C:/Ruby200/lib/ruby/2.0.0/fiddle/value.rb
   57 C:/Ruby200/lib/ruby/2.0.0/fiddle/pack.rb
   58 C:/Ruby200/lib/ruby/2.0.0/fiddle/struct.rb
   59 C:/Ruby200/lib/ruby/2.0.0/fiddle/cparser.rb
   60 C:/Ruby200/lib/ruby/2.0.0/fiddle/import.rb
   61 C:/Ruby200/lib/ruby/2.0.0/win32/registry.rb
   62 C:/Ruby200/lib/ruby/2.0.0/win32/resolv.rb
   63 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/enc/trans/japanese_sjis.so
   64 C:/Ruby200/lib/ruby/2.0.0/resolv.rb
   65 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/dns_resolver.rb
   66 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/socket.rb
   67 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/server.rb
   68 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/http11_client.so
   69 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/http_client.rb
   70 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io/dsl.rb
   71 C:/Ruby200/lib/ruby/gems/2.0.0/gems/cool.io-1.2.4/lib/cool.io.rb
   72 C:/Ruby200/lib/ruby/2.0.0/i386-mingw32/enc/trans/single_byte.so

[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html


This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

And,
following code (coolio is not used) is normally finished. No problem.

require 'thread'

flagexit = false
t = Thread.new do
  while !flagexit
    p Time.new
    sleep(1)
  end
  p "Thread exit"
end

p t

gets
flagexit = true
t.join

jruby compatibility

Right now, installing on jruby fails because iobuffer uses c extensions.
Since cool.io aims to be mostly ruby, it would be very nice if a java alternative was available for those small c parts, so we can use cool.io with jruby.

Performance vs. EventMachine

I have tried cool.io on two projects and both perform worse than EventMachine. This was not using the emulation layer.

One a private server, I was proecssing 19k records per second and that dropped to 12k.
Using Ruby Redis, redis-benchmark results dropped from 20k to 15k.

You can check it out on this commit: (I'm probably going back to EM)
https://github.com/dturnbull/ruby-redis/commit/5efbffc727100

As a client making outbound connections, cool.io was a bit faster.

Fiber-aware deferred operation

I wonder if something like this would be worth to put into cool.io?
Otherwise maybe I'll put this into a gem.
Thanks!

require 'fiber'
require 'coolio'

class Defer < Coolio::AsyncWatcher
  def self.defer loop=Coolio::Loop.default, &block
    new(loop, &block).result
  end

  attr_reader :result

  def initialize loop=Coolio::Loop.default
    super()
    @fiber = Fiber.current
    attach(loop)
    Thread.new{
      @result = yield
      signal
    }
    Fiber.yield
  end

  def on_signal
    puts "ON SIGNAL"
    @fiber.resume
    detach
  end
end

Fiber.new{
  puts Defer.defer{ sleep 1; "DONE" }
}.resume

puts "GO"
Coolio::Loop.default.run

windows ruby1.8.7 support

Do you have any plan to support ruby1.8.7 in windows? If you have, it will help me a lot, or you can tell me how to modify it so i can do this work. thanks

Coolio::HttpClient never calls on_request_complete

When a non chunked-encoding response lacks a Content-Length header, Coolio::HttpClient keeps instance variable, state, equal to :body. (See HttpClient#dispatch and HttpClient#process_body) It does so even when there is no more data to process, IE: the state variable never transitions to :finished.

Example:

class MyHttp < Coolio::HttpClient
attr_reader :response_body, :response_header
def on_response_header(header)
puts "response status: #{header.status}"
end
def on_body_data(data)
@response_body ||= ""
@response_body << data
end
def on_request_complete
puts "HTTP FINISHED"
end
def on_error(reason)
puts "error: #{reason}"
end
end

l = Coolio::Loop.default
http = MyHttp.connect("www.google.com", 80).attach(l)
http.request("GET", '/')
l.run

outputs:
response status: 200

note:

http.response_body.size # => 9922
http.response_header.keys.include? "CONTENT_LENGTH" # => false

Change FT_SETSIZE on Windows

https://support.microsoft.com/en-us/kb/111855

From microsoft document, default FD_SETSIZE is 64.
64 is not good for fluentd like middleware, so setting larger value is better.

Above article also says "If an application is designed to be capable of working with more than 64 sockets, define the manifest FD_SETSIZE in every source file before including WINSOCK.H."
Setting FD_SETSIZE 1024 should work on windows.

Could not install when using Ruby 2.5 (x64-mingw32)

I tried to install cool.io on Windows with Ruby 2.5.
But I cannot do it.

Environment

  • WIndows 10 Home 1803 64 Bit
  • Ruby (from RubyInstaller2) ruby 2.5.0p0 (2017-12-25 revision 61468) [x64-mingw32]

Log

I tried to bundle install on fluent-plugin-mongo local repository.

PS> ridk enable
PS> bundle install --path vendor/bundle
The dependency cool.io (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for x64-mingw32 but the dependency is only for ruby. To add those platforms to the bundle, run `bundle lock --add-platform ruby`.
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
Using rake 12.3.1
Using bson 4.3.0
Using bundler 1.16.2
Fetching cool.io 1.5.3 (x64-mingw32)
Installing cool.io 1.5.3 (x64-mingw32)
Gem::RuntimeRequirementNotMetError: cool.io requires Ruby version < 2.5, >= 2.0.
The current ruby version is 2.5.0.
An error occurred while installing cool.io (1.5.3), and Bundler cannot continue.
Make sure that `gem install cool.io -v '1.5.3' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  fluent-plugin-mongo was resolved to 1.1.2, which depends on
    fluentd was resolved to 1.2.5, which depends on
      cool.io

I extracted cool.io-1.5.3-x64-mingw32 and inspected:

PS> ls data/lib
PS> 2.0  2.1  2.2  2.3  2.4  cool.io  cool.io.rb  coolio.rb

Shared object for Ruby 2.5 is not included in released cool.io gem.

rev 0.3.2 doesn't link against openssl 1.0.0

x86_64-pc-linux-gnu-gcc -shared -o rev_ext.so libev.o rev_ext.o rev_io_watcher.o rev_loop.o rev_ssl.o rev_stat_watcher.o rev_timer_watcher.o rev_utils.o rev_watcher.o -L. -L/usr/lib64 -Wl,-R/usr/lib64 -L. -Wl,-O1 -Wl,--as-needed -Wl,--hash-style=gnu -rdynamic -Wl,-export-dynamic -Wl,--no-undefined -Wl,-R -Wl,/usr/lib64 -L/usr/lib64 -lruby18 -lrt -lrt -ldl -lcrypt -lm -lc -lrt -lssl -lcrypto
rev_ssl.o: In function Rev_SSL_IO_ssl_setup': rev_ssl.c:(.text+0x508): undefined reference toossl_ssl_ex_ptr_idx'
rev_ssl.c:(.text+0x52b): undefined reference to ossl_ssl_ex_vcb_idx' rev_ssl.c:(.text+0x54e): undefined reference toossl_ssl_ex_client_cert_cb_idx'
rev_ssl.c:(.text+0x571): undefined reference to ossl_ssl_ex_tmp_dh_callback_idx' rev_ssl.c:(.text+0x592): undefined reference toossl_raise'
collect2: ld returned 1 exit status
make: *** [rev_ext.so] Error 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.