eventmachine 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|