eventmachine 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/DEFERRABLES +138 -0
- data/EPOLL +0 -1
- data/KEYBOARD +38 -0
- data/LIGHTWEIGHT_CONCURRENCY +72 -0
- data/SMTP +9 -0
- data/SPAWNED_PROCESSES +93 -0
- data/ext/cmain.cpp +25 -1
- data/ext/cplusplus.cpp +3 -6
- data/ext/ed.cpp +23 -2
- data/ext/ed.h +34 -3
- data/ext/eee +173 -0
- data/ext/em.cpp +42 -2
- data/ext/em.h +2 -1
- data/ext/eventmachine.h +3 -1
- data/ext/extconf.rb +9 -3
- data/ext/kb.cpp +365 -0
- data/ext/pipe.cpp +3 -4
- data/ext/rubymain.cpp +31 -1
- data/ext/ssl.cpp +29 -5
- data/ext/ssl.h +3 -3
- data/lib/em/deferrable.rb +90 -9
- data/lib/em/spawnable.rb +88 -0
- data/lib/eventmachine.rb +99 -11
- data/lib/eventmachine_version.rb +2 -2
- data/lib/protocols/httpclient.rb +7 -1
- data/lib/protocols/smtpclient.rb +276 -0
- data/lib/protocols/smtpserver.rb +514 -0
- data/lib/svn-commit.tmp +4 -0
- data/tests/test_basic.rb +13 -1
- data/tests/test_futures.rb +83 -6
- data/tests/test_httpclient.rb +17 -1
- data/tests/test_kb.rb +60 -0
- data/tests/test_running.rb +46 -0
- data/tests/test_smtpclient.rb +80 -0
- data/tests/test_smtpserver.rb +92 -0
- data/tests/test_spawn.rb +328 -0
- metadata +23 -3
- data/ext/autoscan.log +0 -0
data/ext/pipe.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: pipe.cpp
|
3
|
+
$Id: pipe.cpp 494 2007-08-15 06:23:09Z blackhedd $
|
4
4
|
|
5
5
|
File: pipe.cpp
|
6
6
|
Date: 30May07
|
@@ -27,12 +27,11 @@ See the file COPYING for complete licensing information.
|
|
27
27
|
PipeDescriptor::PipeDescriptor
|
28
28
|
******************************/
|
29
29
|
|
30
|
-
PipeDescriptor::PipeDescriptor (
|
31
|
-
EventableDescriptor (
|
30
|
+
PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em):
|
31
|
+
EventableDescriptor (fd, parent_em),
|
32
32
|
bReadAttemptedAfterClose (false),
|
33
33
|
LastIo (gCurrentLoopTime),
|
34
34
|
InactivityTimeout (0),
|
35
|
-
//MyStream (fp),
|
36
35
|
OutboundDataSize (0),
|
37
36
|
SubprocessPid (subpid)
|
38
37
|
{
|
data/ext/rubymain.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: rubymain.cpp
|
3
|
+
$Id: rubymain.cpp 502 2007-08-24 09:29:53Z blackhedd $
|
4
4
|
|
5
5
|
File: rubymain.cpp
|
6
6
|
Date: 06Apr06
|
@@ -138,6 +138,21 @@ static VALUE t_start_tls (VALUE self, VALUE signature)
|
|
138
138
|
return Qnil;
|
139
139
|
}
|
140
140
|
|
141
|
+
/***************
|
142
|
+
t_set_tls_parms
|
143
|
+
***************/
|
144
|
+
|
145
|
+
static VALUE t_set_tls_parms (VALUE self, VALUE signature, VALUE privkeyfile, VALUE certchainfile)
|
146
|
+
{
|
147
|
+
/* set_tls_parms takes a series of positional arguments for specifying such things
|
148
|
+
* as private keys and certificate chains.
|
149
|
+
* It's expected that the parameter list will grow as we add more supported features.
|
150
|
+
* ALL of these parameters are optional, and can be specified as empty or NULL strings.
|
151
|
+
*/
|
152
|
+
evma_set_tls_parms (StringValuePtr (signature), StringValuePtr (privkeyfile), StringValuePtr (certchainfile) );
|
153
|
+
return Qnil;
|
154
|
+
}
|
155
|
+
|
141
156
|
/**************
|
142
157
|
t_get_peername
|
143
158
|
**************/
|
@@ -361,6 +376,19 @@ static VALUE t_invoke_popen (VALUE self, VALUE cmd)
|
|
361
376
|
}
|
362
377
|
|
363
378
|
|
379
|
+
/***************
|
380
|
+
t_read_keyboard
|
381
|
+
***************/
|
382
|
+
|
383
|
+
static VALUE t_read_keyboard (VALUE self)
|
384
|
+
{
|
385
|
+
const char *f = evma_open_keyboard();
|
386
|
+
if (!f || !*f)
|
387
|
+
rb_raise (rb_eRuntimeError, "no keyboard reader");
|
388
|
+
return rb_str_new2 (f);
|
389
|
+
}
|
390
|
+
|
391
|
+
|
364
392
|
/********
|
365
393
|
t__epoll
|
366
394
|
********/
|
@@ -452,6 +480,7 @@ extern "C" void Init_rubyeventmachine()
|
|
452
480
|
rb_define_module_function (EmModule, "start_tcp_server", (VALUE(*)(...))t_start_server, 2);
|
453
481
|
rb_define_module_function (EmModule, "stop_tcp_server", (VALUE(*)(...))t_stop_server, 1);
|
454
482
|
rb_define_module_function (EmModule, "start_unix_server", (VALUE(*)(...))t_start_unix_server, 1);
|
483
|
+
rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 3);
|
455
484
|
rb_define_module_function (EmModule, "start_tls", (VALUE(*)(...))t_start_tls, 1);
|
456
485
|
rb_define_module_function (EmModule, "send_data", (VALUE(*)(...))t_send_data, 3);
|
457
486
|
rb_define_module_function (EmModule, "send_datagram", (VALUE(*)(...))t_send_datagram, 5);
|
@@ -459,6 +488,7 @@ extern "C" void Init_rubyeventmachine()
|
|
459
488
|
rb_define_module_function (EmModule, "connect_server", (VALUE(*)(...))t_connect_server, 2);
|
460
489
|
rb_define_module_function (EmModule, "connect_unix_server", (VALUE(*)(...))t_connect_unix_server, 1);
|
461
490
|
rb_define_module_function (EmModule, "open_udp_socket", (VALUE(*)(...))t_open_udp_socket, 2);
|
491
|
+
rb_define_module_function (EmModule, "read_keyboard", (VALUE(*)(...))t_read_keyboard, 0);
|
462
492
|
rb_define_module_function (EmModule, "release_machine", (VALUE(*)(...))t_release_machine, 0);
|
463
493
|
rb_define_module_function (EmModule, "stop", (VALUE(*)(...))t_stop, 0);
|
464
494
|
rb_define_module_function (EmModule, "signal_loopbreak", (VALUE(*)(...))t_signal_loopbreak, 0);
|
data/ext/ssl.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: ssl.cpp
|
3
|
+
$Id: ssl.cpp 498 2007-08-15 14:03:32Z blackhedd $
|
4
4
|
|
5
5
|
File: ssl.cpp
|
6
6
|
Date: 30Apr06
|
@@ -120,11 +120,19 @@ static void InitializeDefaultCredentials()
|
|
120
120
|
SslContext_t::SslContext_t
|
121
121
|
**************************/
|
122
122
|
|
123
|
-
SslContext_t::SslContext_t (bool is_server):
|
123
|
+
SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile):
|
124
124
|
pCtx (NULL),
|
125
125
|
PrivateKey (NULL),
|
126
126
|
Certificate (NULL)
|
127
127
|
{
|
128
|
+
/* TODO: the usage of the specified private-key and cert-chain filenames only applies to
|
129
|
+
* client-side connections at this point. Server connections currently use the default materials.
|
130
|
+
* That needs to be fixed asap.
|
131
|
+
* Also, in this implementation, server-side connections use statically defined X-509 defaults.
|
132
|
+
* One thing I'm really not clear on is whether or not you have to explicitly free X509 and EVP_PKEY
|
133
|
+
* objects when we call our destructor, or whether just calling SSL_CTX_free is enough.
|
134
|
+
*/
|
135
|
+
|
128
136
|
if (!bLibraryInitialized) {
|
129
137
|
bLibraryInitialized = true;
|
130
138
|
SSL_library_init();
|
@@ -159,9 +167,21 @@ SslContext_t::SslContext_t (bool is_server):
|
|
159
167
|
SSL_CTX_sess_set_cache_size (pCtx, 128);
|
160
168
|
SSL_CTX_set_session_id_context (pCtx, (unsigned char*)"eventmachine", 12);
|
161
169
|
}
|
162
|
-
|
170
|
+
else {
|
171
|
+
int e;
|
172
|
+
if (privkeyfile.length() > 0) {
|
173
|
+
e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM);
|
174
|
+
assert (e > 0);
|
175
|
+
}
|
176
|
+
if (certchainfile.length() > 0) {
|
177
|
+
e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str());
|
178
|
+
assert (e > 0);
|
179
|
+
}
|
180
|
+
}
|
163
181
|
}
|
164
182
|
|
183
|
+
|
184
|
+
|
165
185
|
/***************************
|
166
186
|
SslContext_t::~SslContext_t
|
167
187
|
***************************/
|
@@ -182,13 +202,17 @@ SslContext_t::~SslContext_t()
|
|
182
202
|
SslBox_t::SslBox_t
|
183
203
|
******************/
|
184
204
|
|
185
|
-
SslBox_t::SslBox_t (bool is_server):
|
205
|
+
SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile):
|
186
206
|
bIsServer (is_server),
|
187
207
|
pSSL (NULL),
|
188
208
|
pbioRead (NULL),
|
189
209
|
pbioWrite (NULL)
|
190
210
|
{
|
191
|
-
|
211
|
+
/* TODO someday: make it possible to re-use SSL contexts so we don't have to create
|
212
|
+
* a new one every time we come here.
|
213
|
+
*/
|
214
|
+
|
215
|
+
Context = new SslContext_t (bIsServer, privkeyfile, certchainfile);
|
192
216
|
assert (Context);
|
193
217
|
|
194
218
|
pbioRead = BIO_new (BIO_s_mem());
|
data/ext/ssl.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: ssl.h
|
3
|
+
$Id: ssl.h 498 2007-08-15 14:03:32Z blackhedd $
|
4
4
|
|
5
5
|
File: ssl.h
|
6
6
|
Date: 30Apr06
|
@@ -33,7 +33,7 @@ class SslContext_t
|
|
33
33
|
class SslContext_t
|
34
34
|
{
|
35
35
|
public:
|
36
|
-
SslContext_t (bool is_server);
|
36
|
+
SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile);
|
37
37
|
virtual ~SslContext_t();
|
38
38
|
|
39
39
|
private:
|
@@ -57,7 +57,7 @@ class SslBox_t
|
|
57
57
|
class SslBox_t
|
58
58
|
{
|
59
59
|
public:
|
60
|
-
SslBox_t (bool is_server);
|
60
|
+
SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile);
|
61
61
|
virtual ~SslBox_t();
|
62
62
|
|
63
63
|
int PutPlaintext (const char*, int);
|
data/lib/em/deferrable.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: deferrable.rb
|
1
|
+
# $Id: deferrable.rb 534 2007-09-15 23:06:15Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -28,26 +28,50 @@ require 'forwardable'
|
|
28
28
|
module EventMachine
|
29
29
|
|
30
30
|
module Deferrable
|
31
|
+
|
32
|
+
# Specify a block to be executed if and when the Deferrable object receives
|
33
|
+
# a status of :succeeded. See #set_deferred_status for more information.
|
34
|
+
#
|
35
|
+
# Calling this method on a Deferrable object whose status is not yet known
|
36
|
+
# will cause the callback block to be stored on an internal list.
|
37
|
+
# If you call this method on a Deferrable whose status is :succeeded, the
|
38
|
+
# block will be executed immediately, receiving the parameters given to the
|
39
|
+
# prior #set_deferred_status call.
|
40
|
+
#
|
41
|
+
#--
|
42
|
+
# If there is no status, add a callback to an internal list.
|
43
|
+
# If status is succeeded, execute the callback immediately.
|
44
|
+
# If status is failed, do nothing.
|
45
|
+
#
|
31
46
|
def callback &block
|
32
47
|
return unless block
|
33
48
|
if @deferred_status == :succeeded
|
34
49
|
block.call(*@deferred_args)
|
35
|
-
|
50
|
+
elsif @deferred_status != :failed
|
36
51
|
@callbacks ||= []
|
37
52
|
@callbacks.unshift block # << block
|
38
53
|
end
|
39
54
|
end
|
40
55
|
|
56
|
+
# Specify a block to be executed if and when the Deferrable object receives
|
57
|
+
# a status of :failed. See #set_deferred_status for more information.
|
58
|
+
#--
|
59
|
+
# If there is no status, add an errback to an internal list.
|
60
|
+
# If status is failed, execute the errback immediately.
|
61
|
+
# If status is succeeded, do nothing.
|
62
|
+
#
|
41
63
|
def errback &block
|
42
64
|
return unless block
|
43
65
|
if @deferred_status == :failed
|
44
66
|
block.call(*@deferred_args)
|
45
|
-
|
67
|
+
elsif @deferred_status != :succeeded
|
46
68
|
@errbacks ||= []
|
47
69
|
@errbacks.unshift block # << block
|
48
70
|
end
|
49
71
|
end
|
50
72
|
|
73
|
+
# Sets the "disposition" (status) of the Deferrable object. See also the large set of
|
74
|
+
# sugarings for this method.
|
51
75
|
# Note that if you call this method without arguments,
|
52
76
|
# no arguments will be passed to the callback/errback.
|
53
77
|
# If the user has coded these with arguments, then the
|
@@ -59,6 +83,23 @@ module Deferrable
|
|
59
83
|
# on the INSIDE of a callback. This is very useful when a previously-registered
|
60
84
|
# callback wants to change the parameters that will be passed to subsequently-registered
|
61
85
|
# ones.
|
86
|
+
#
|
87
|
+
# You may give either :succeeded or :failed as the status argument.
|
88
|
+
#
|
89
|
+
# If you pass :succeeded, then all of the blocks passed to the object using the #callback
|
90
|
+
# method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
|
91
|
+
# passed to the object using #errback will be discarded.
|
92
|
+
#
|
93
|
+
# If you pass :failed, then all of the blocks passed to the object using the #errback
|
94
|
+
# method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
|
95
|
+
# passed to the object using # callback will be discarded.
|
96
|
+
#
|
97
|
+
# If you pass any arguments to #set_deferred_status in addition to the status argument,
|
98
|
+
# they will be passed as arguments to any callbacks or errbacks that are executed.
|
99
|
+
# It's your responsibility to ensure that the argument lists specified in your callbacks and
|
100
|
+
# errbacks match the arguments given in calls to #set_deferred_status, otherwise Ruby will raise
|
101
|
+
# an ArgumentError.
|
102
|
+
#
|
62
103
|
# --
|
63
104
|
# We're shifting callbacks off and discarding them as we execute them.
|
64
105
|
# This is valid because by definition callbacks are executed no more than
|
@@ -70,25 +111,65 @@ module Deferrable
|
|
70
111
|
# by Kirk Haines, to work around the memory leak bug that still exists in many Ruby
|
71
112
|
# versions.
|
72
113
|
#
|
73
|
-
|
74
|
-
|
114
|
+
# Changed 15Sep07: after processing callbacks or errbacks, CLEAR the other set of
|
115
|
+
# handlers. This gets us a little closer to the behavior of Twisted's "deferred,"
|
116
|
+
# which only allows status to be set once. Prior to making this change, it was possible
|
117
|
+
# to "succeed" a Deferrable (triggering its callbacks), and then immediately "fail" it,
|
118
|
+
# triggering its errbacks! That is clearly undesirable, but it's just as undesirable
|
119
|
+
# to raise an exception is status is set more than once on a Deferrable. The latter
|
120
|
+
# behavior would invalidate the idiom of resetting arguments by setting status from
|
121
|
+
# within a callback or errback, but more seriously it would cause spurious errors
|
122
|
+
# if a Deferrable was timed out and then an attempt was made to succeed it. See the
|
123
|
+
# comments under the new method #timeout.
|
124
|
+
#
|
125
|
+
def set_deferred_status status, *args
|
126
|
+
cancel_timeout
|
127
|
+
@deferred_status = status
|
75
128
|
@deferred_args = args
|
76
129
|
case @deferred_status
|
77
130
|
when :succeeded
|
78
131
|
if @callbacks
|
79
|
-
while cb = @callbacks.pop
|
132
|
+
while cb = @callbacks.pop
|
80
133
|
cb.call(*@deferred_args)
|
81
134
|
end
|
82
135
|
end
|
136
|
+
@errbacks.clear if @errbacks
|
83
137
|
when :failed
|
84
138
|
if @errbacks
|
85
|
-
while eb = @errbacks.pop
|
139
|
+
while eb = @errbacks.pop
|
86
140
|
eb.call(*@deferred_args)
|
87
141
|
end
|
88
142
|
end
|
143
|
+
@callbacks.clear if @callbacks
|
89
144
|
end
|
90
145
|
end
|
91
146
|
|
147
|
+
|
148
|
+
# Setting a timeout on a Deferrable causes it to go into the failed state after
|
149
|
+
# the Timeout expires (passing no arguments to the object's errbacks).
|
150
|
+
# Setting the status at any time prior to a call to the expiration of the timeout
|
151
|
+
# will cause the timer to be cancelled.
|
152
|
+
#--
|
153
|
+
#
|
154
|
+
#
|
155
|
+
def timeout seconds
|
156
|
+
cancel_timeout
|
157
|
+
me = self
|
158
|
+
@deferred_timeout = EventMachine::Timer.new(seconds) {me.fail}
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
# Cancels an outstanding timeout if any. Undoes the action of #timeout.
|
163
|
+
#
|
164
|
+
#
|
165
|
+
def cancel_timeout
|
166
|
+
if @deferred_timeout
|
167
|
+
@deferred_timeout.cancel
|
168
|
+
@deferred_timeout = nil
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
92
173
|
# Equivalent to set_deferred_status(:succeeded, ...)
|
93
174
|
#
|
94
175
|
def set_deferred_success *args
|
@@ -104,13 +185,13 @@ module Deferrable
|
|
104
185
|
# And still more sugar
|
105
186
|
#
|
106
187
|
def succeed *args
|
107
|
-
set_deferred_success
|
188
|
+
set_deferred_success(*args)
|
108
189
|
end
|
109
190
|
|
110
191
|
# Can't get enough sugar
|
111
192
|
#
|
112
193
|
def fail *args
|
113
|
-
set_deferred_failure
|
194
|
+
set_deferred_failure(*args)
|
114
195
|
end
|
115
196
|
end
|
116
197
|
|
data/lib/em/spawnable.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# $Id: spawnable.rb 530 2007-09-13 01:11:38Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 25 Aug 2007
|
6
|
+
#
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
8
|
+
# usage examples.
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
13
|
+
# Gmail: blackhedd
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
|
26
|
+
|
27
|
+
# Support for Erlang-style processes.
|
28
|
+
#
|
29
|
+
|
30
|
+
|
31
|
+
module EventMachine
|
32
|
+
class SpawnedProcess
|
33
|
+
#attr_accessor :receiver
|
34
|
+
def notify *x
|
35
|
+
me = self
|
36
|
+
EM.next_tick {
|
37
|
+
# A notification executes in the context of this
|
38
|
+
# SpawnedProcess object. That makes self and notify
|
39
|
+
# work as one would expect.
|
40
|
+
#
|
41
|
+
y = me.call(*x)
|
42
|
+
if y and y.respond_to?(:pull_out_yield_block)
|
43
|
+
a,b = y.pull_out_yield_block
|
44
|
+
set_receiver a
|
45
|
+
self.notify if b
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
alias_method :resume, :notify
|
50
|
+
alias_method :run, :notify # for formulations like (EM.spawn {xxx}).run
|
51
|
+
|
52
|
+
# I know I'm missing something stupid, but the inside of class << s
|
53
|
+
# can't see locally-bound values. It can see globals, though.
|
54
|
+
def set_receiver blk
|
55
|
+
$em______tmpglobal = blk
|
56
|
+
class << self
|
57
|
+
define_method :call, $em______tmpglobal.dup
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
class YieldBlockFromSpawnedProcess
|
64
|
+
def initialize block, notify
|
65
|
+
@block = [block,notify]
|
66
|
+
end
|
67
|
+
def pull_out_yield_block
|
68
|
+
@block
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def EventMachine.spawn &block
|
73
|
+
s = SpawnedProcess.new
|
74
|
+
s.set_receiver block
|
75
|
+
s
|
76
|
+
end
|
77
|
+
|
78
|
+
def EventMachine.yield &block
|
79
|
+
return YieldBlockFromSpawnedProcess.new( block, false )
|
80
|
+
end
|
81
|
+
|
82
|
+
def EventMachine.yield_and_notify &block
|
83
|
+
return YieldBlockFromSpawnedProcess.new( block, true )
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
|
data/lib/eventmachine.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: eventmachine.rb
|
1
|
+
# $Id: eventmachine.rb 521 2007-09-04 18:22:07Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -66,6 +66,7 @@ require 'em/future'
|
|
66
66
|
require 'em/eventable'
|
67
67
|
require 'em/messages'
|
68
68
|
require 'em/streamer'
|
69
|
+
require 'em/spawnable'
|
69
70
|
|
70
71
|
require 'shellwords'
|
71
72
|
|
@@ -216,15 +217,31 @@ module EventMachine
|
|
216
217
|
@acceptors = {}
|
217
218
|
@timers = {}
|
218
219
|
begin
|
220
|
+
@reactor_running = true
|
219
221
|
initialize_event_machine
|
220
222
|
block and add_timer 0, block
|
221
223
|
run_machine
|
222
224
|
ensure
|
223
225
|
release_machine
|
226
|
+
@reactor_running = false
|
224
227
|
end
|
225
228
|
end
|
226
229
|
|
227
230
|
|
231
|
+
# Sugars a common use case. Will pass the given block to #run, but will terminate
|
232
|
+
# the reactor loop and exit the function as soon as the code in the block completes.
|
233
|
+
# (Normally, #run keeps running indefinitely, even after the block supplied to it
|
234
|
+
# finishes running, until user code calls #stop.)
|
235
|
+
#
|
236
|
+
def EventMachine::run_block &block
|
237
|
+
pr = proc {
|
238
|
+
block.call
|
239
|
+
EventMachine::stop
|
240
|
+
}
|
241
|
+
run(&pr)
|
242
|
+
end
|
243
|
+
|
244
|
+
|
228
245
|
# +deprecated+
|
229
246
|
#--
|
230
247
|
# EventMachine#run_without_threads is semantically identical
|
@@ -766,17 +783,27 @@ module EventMachine
|
|
766
783
|
# It can be fired either by code running on a separate thread (EM#defer) or on
|
767
784
|
# the main thread (EM#next_tick).
|
768
785
|
# It will often happen that a next_tick handler will reschedule itself. We
|
769
|
-
# consume a
|
786
|
+
# consume a copy of the tick queue so that tick events scheduled by tick events
|
770
787
|
# have to wait for the next pass through the reactor core.
|
771
788
|
#
|
772
789
|
def self::run_deferred_callbacks # :nodoc:
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
cback.call result if cback
|
777
|
-
end
|
790
|
+
until (@resultqueue ||= []).empty?
|
791
|
+
result,cback = @resultqueue.pop
|
792
|
+
cback.call result if cback
|
778
793
|
end
|
779
794
|
|
795
|
+
@next_tick_queue ||= []
|
796
|
+
if (l = @next_tick_queue.length) > 0
|
797
|
+
l.times {|i| @next_tick_queue[i].call}
|
798
|
+
@next_tick_queue.slice!( 0...l )
|
799
|
+
end
|
800
|
+
|
801
|
+
=begin
|
802
|
+
(@next_tick_queue ||= []).length.times {
|
803
|
+
cback=@next_tick_queue.pop and cback.call
|
804
|
+
}
|
805
|
+
=end
|
806
|
+
=begin
|
780
807
|
if (@next_tick_queue ||= []) and @next_tick_queue.length > 0
|
781
808
|
ary = @next_tick_queue.dup
|
782
809
|
@next_tick_queue.clear
|
@@ -784,6 +811,7 @@ module EventMachine
|
|
784
811
|
cback=ary.pop and cback.call
|
785
812
|
end
|
786
813
|
end
|
814
|
+
=end
|
787
815
|
end
|
788
816
|
|
789
817
|
|
@@ -810,7 +838,6 @@ module EventMachine
|
|
810
838
|
# after the operation completes.
|
811
839
|
#
|
812
840
|
# <i>Caveats:</i>
|
813
|
-
# This is a <b>provisional</b> implementation and is subject to change.
|
814
841
|
# Note carefully that the code in your deferred operation will be executed on a separate
|
815
842
|
# thread from the main EventMachine processing and all other Ruby threads that may exist in
|
816
843
|
# your program. Also, multiple deferred operations may be running at once! Therefore, you
|
@@ -872,7 +899,7 @@ module EventMachine
|
|
872
899
|
#
|
873
900
|
def self::next_tick pr=nil, &block
|
874
901
|
raise "no argument or block given" unless ((pr && pr.respond_to?(:call)) or block)
|
875
|
-
(@next_tick_queue ||= []) << (pr || block)
|
902
|
+
(@next_tick_queue ||= []) << ( pr || block )
|
876
903
|
EventMachine.signal_loopbreak
|
877
904
|
=begin
|
878
905
|
(@next_tick_procs ||= []) << (pr || block)
|
@@ -944,6 +971,39 @@ module EventMachine
|
|
944
971
|
end
|
945
972
|
|
946
973
|
|
974
|
+
# Tells you whether the EventMachine reactor loop is currently running. Returns true or
|
975
|
+
# false. Useful when writing libraries that want to run event-driven code, but may
|
976
|
+
# be running in programs that are already event-driven. In such cases, if EventMachine#reactor_running?
|
977
|
+
# returns false, your code can invoke EventMachine#run and run your application code inside
|
978
|
+
# the block passed to that method. If EventMachine#reactor_running? returns true, just
|
979
|
+
# execute your event-aware code.
|
980
|
+
#
|
981
|
+
# This method is necessary because calling EventMachine#run inside of another call to
|
982
|
+
# EventMachine#run generates a fatal error.
|
983
|
+
#
|
984
|
+
def self::reactor_running?
|
985
|
+
(@reactor_running || false)
|
986
|
+
end
|
987
|
+
|
988
|
+
|
989
|
+
# (Experimental)
|
990
|
+
#
|
991
|
+
#
|
992
|
+
def EventMachine::open_keyboard handler=nil
|
993
|
+
klass = if (handler and handler.is_a?(Class))
|
994
|
+
handler
|
995
|
+
else
|
996
|
+
Class.new( Connection ) {handler and include handler}
|
997
|
+
end
|
998
|
+
|
999
|
+
s = read_keyboard
|
1000
|
+
c = klass.new s
|
1001
|
+
@conns[s] = c
|
1002
|
+
block_given? and yield c
|
1003
|
+
c
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
|
947
1007
|
|
948
1008
|
private
|
949
1009
|
def EventMachine::event_callback conn_binding, opcode, data
|
@@ -1163,9 +1223,35 @@ class Connection
|
|
1163
1223
|
# Call #start_tls at any point to initiate TLS encryption on connected streams.
|
1164
1224
|
# The method is smart enough to know whether it should perform a server-side
|
1165
1225
|
# or a client-side handshake. An appropriate place to call #start_tls is in
|
1166
|
-
# your redefined #post_init method
|
1226
|
+
# your redefined #post_init method, or in the #connection_completed handler for
|
1227
|
+
# an outbound connection.
|
1228
|
+
#
|
1229
|
+
# #start_tls takes an optional parameter hash that allows you to specify certificate
|
1230
|
+
# and other options to be used with this Connection object. Here are the currently-supported
|
1231
|
+
# options:
|
1232
|
+
# :cert_chain_file : takes a String, which is interpreted as the name of a readable file in the
|
1233
|
+
# local filesystem. The file is expected to contain a chain of X509 certificates in
|
1234
|
+
# PEM format, with the most-resolved certificate at the top of the file, successive
|
1235
|
+
# intermediate certs in the middle, and the root (or CA) cert at the bottom.
|
1236
|
+
#
|
1237
|
+
# :private_key_file : tales a String, which is interpreted as the name of a readable file in the
|
1238
|
+
# local filesystem. The file must contain a private key in PEM format.
|
1239
|
+
#
|
1240
|
+
#--
|
1241
|
+
# TODO: support passing an encryption parameter, which can be string or Proc, to get a passphrase
|
1242
|
+
# for encrypted private keys.
|
1243
|
+
# TODO: support passing key material via raw strings or Procs that return strings instead of
|
1244
|
+
# just filenames.
|
1245
|
+
# What will get nasty is whether we have to define a location for storing this stuff as files.
|
1246
|
+
# In general, the OpenSSL interfaces for dealing with certs and keys in files are much better
|
1247
|
+
# behaved than the ones for raw chunks of memory.
|
1167
1248
|
#
|
1168
|
-
def start_tls
|
1249
|
+
def start_tls args={}
|
1250
|
+
EventMachine::set_tls_parms(
|
1251
|
+
@signature,
|
1252
|
+
args[:private_key_file] || "",
|
1253
|
+
args[:cert_chain_file] || ""
|
1254
|
+
)
|
1169
1255
|
EventMachine::start_tls @signature
|
1170
1256
|
end
|
1171
1257
|
|
@@ -1332,4 +1418,6 @@ require 'protocols/line_and_text'
|
|
1332
1418
|
require 'protocols/header_and_content'
|
1333
1419
|
require 'protocols/linetext2'
|
1334
1420
|
require 'protocols/stomp'
|
1421
|
+
require 'protocols/smtpclient'
|
1422
|
+
require 'protocols/smtpserver'
|
1335
1423
|
|