green 0.0.1 → 0.1
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/Gemfile +17 -1
- data/Gemfile.lock +61 -8
- data/README.md +46 -1
- data/green.gemspec +24 -5
- data/lib/active_record/connection_adapters/green_mysql2_adapter.rb +92 -0
- data/lib/green/activerecord.rb +21 -0
- data/lib/green/connection_pool.rb +72 -0
- data/lib/green/event.rb +3 -7
- data/lib/green/ext.rb +10 -2
- data/lib/green/group.rb +20 -6
- data/lib/green/hub/em.rb +49 -9
- data/lib/green/hub/nio4r.rb +147 -0
- data/lib/green/hub.rb +12 -3
- data/lib/green/monkey.rb +11 -13
- data/lib/green/mysql2.rb +16 -0
- data/lib/green/semaphore.rb +136 -6
- data/lib/green/socket.rb +124 -0
- data/lib/green/zmq.rb +92 -0
- data/lib/green-em/em-http.rb +3 -4
- data/lib/green.rb +92 -33
- data/spec/green/activerecord_spec.rb +100 -0
- data/spec/green/connection_pool_spec.rb +45 -0
- data/spec/green/event_spec.rb +24 -0
- data/spec/green/group_spec.rb +68 -0
- data/spec/green/monkey_spec.rb +22 -0
- data/spec/green/mysql2_spec.rb +52 -0
- data/spec/green/semaphore_spec.rb +169 -0
- data/spec/green/socket_spec.rb +26 -0
- data/spec/green/tcpsocket_spec.rb +417 -0
- data/spec/green/zmq_spec.rb +121 -0
- data/spec/green_spec.rb +37 -0
- data/spec/helpers.rb +0 -0
- data/spec/spec_helper.rb +32 -0
- metadata +56 -9
- data/Readme.md +0 -55
- data/lib/green/tcp_socket.rb +0 -25
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'nio'
|
2
|
+
require 'algorithms'
|
3
|
+
|
4
|
+
class Green
|
5
|
+
class Hub
|
6
|
+
class Nio4r < Hub
|
7
|
+
class SocketWaiter < Green::SocketWaiter
|
8
|
+
attr_reader :reactor
|
9
|
+
def initialize(reactor, socket)
|
10
|
+
super socket
|
11
|
+
@reactor = reactor
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait_read
|
15
|
+
make_monitor :r
|
16
|
+
end
|
17
|
+
|
18
|
+
def wait_write
|
19
|
+
make_monitor :w
|
20
|
+
end
|
21
|
+
|
22
|
+
def make_monitor(interest)
|
23
|
+
m = reactor.selector.register(socket, interest)
|
24
|
+
g = Green.current
|
25
|
+
m.value = proc { g.switch }
|
26
|
+
Green.hub.switch
|
27
|
+
ensure
|
28
|
+
reactor.selector.deregister socket
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Timer
|
33
|
+
attr_reader :reactor, :fire_at, :clb
|
34
|
+
def initialize(reactor, fire_at, &clb)
|
35
|
+
@reactor, @fire_at, @clb = reactor, fire_at, clb
|
36
|
+
end
|
37
|
+
|
38
|
+
def run
|
39
|
+
@runned = true
|
40
|
+
clb.call
|
41
|
+
end
|
42
|
+
|
43
|
+
def green_cancel
|
44
|
+
return if @canceled || @runned
|
45
|
+
@canceled = true
|
46
|
+
reactor.cancel_timer self
|
47
|
+
end
|
48
|
+
|
49
|
+
def <=>(v)
|
50
|
+
@fire_at <=> v.fire_at
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
MIN_TIMEOUT = 0.0001
|
55
|
+
MAX_TIMEOUT = 0.01
|
56
|
+
|
57
|
+
attr_reader :callbacks, :timers, :cancel_timers
|
58
|
+
def initialize(*args)
|
59
|
+
@callbacks = []
|
60
|
+
@timers = Containers::MinHeap.new
|
61
|
+
@cancel_timers = {}
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
def reactor_running?
|
66
|
+
@reactor_running
|
67
|
+
end
|
68
|
+
|
69
|
+
def run
|
70
|
+
@reactor_running = true
|
71
|
+
@selector = NIO::Selector.new
|
72
|
+
while @reactor_running
|
73
|
+
run_callbacks
|
74
|
+
run_timers
|
75
|
+
@selector.select(time_till_first_event) do |m|
|
76
|
+
m.value.call
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def run_timers
|
82
|
+
now = Time.now
|
83
|
+
while (t = @timers.next)
|
84
|
+
if t.fire_at <= now
|
85
|
+
@timers.pop
|
86
|
+
if @cancel_timers[t]
|
87
|
+
@cancel_timers.delete t
|
88
|
+
else
|
89
|
+
t.run
|
90
|
+
end
|
91
|
+
else
|
92
|
+
break
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def run_callbacks
|
98
|
+
jobs, @callbacks = @callbacks, []
|
99
|
+
begin
|
100
|
+
i = 0
|
101
|
+
while i < jobs.size
|
102
|
+
job = jobs[i]
|
103
|
+
jobs[i] = nil
|
104
|
+
job.call
|
105
|
+
i += 1
|
106
|
+
end
|
107
|
+
ensure
|
108
|
+
@callbacks[0...0] = jobs[i..-1] if i < jobs.size
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def time_till_first_event
|
113
|
+
if @callbacks.size > 0
|
114
|
+
MIN_TIMEOUT
|
115
|
+
elsif @timers.size > 0
|
116
|
+
@timers.next.fire_at - Time.now + MIN_TIMEOUT
|
117
|
+
else
|
118
|
+
MAX_TIMEOUT
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def selector
|
123
|
+
@selector
|
124
|
+
end
|
125
|
+
|
126
|
+
def cancel_timer(timer)
|
127
|
+
@cancel_timers[timer] = true
|
128
|
+
end
|
129
|
+
|
130
|
+
def timer(n, &blk)
|
131
|
+
@timers << Timer.new(self, Time.now + n, &blk)
|
132
|
+
end
|
133
|
+
|
134
|
+
def callback(cb=nil, &blk)
|
135
|
+
@callbacks << (cb || blk)
|
136
|
+
end
|
137
|
+
|
138
|
+
def socket_waiter(socket)
|
139
|
+
SocketWaiter.new self, socket
|
140
|
+
end
|
141
|
+
|
142
|
+
def stop
|
143
|
+
@reactor_running = false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
data/lib/green/hub.rb
CHANGED
@@ -14,17 +14,18 @@ class Green
|
|
14
14
|
g.switch
|
15
15
|
end
|
16
16
|
|
17
|
-
def wait(
|
17
|
+
def wait(proc = nil, &cancel_clb)
|
18
18
|
switch
|
19
19
|
rescue => e
|
20
|
-
|
20
|
+
(proc || cancel_clb).call
|
21
21
|
raise e
|
22
22
|
end
|
23
23
|
|
24
24
|
def sleep(n)
|
25
25
|
g = Green.current
|
26
26
|
t = timer(n) { g.switch }
|
27
|
-
wait t
|
27
|
+
wait { t.green_cancel }
|
28
|
+
t
|
28
29
|
end
|
29
30
|
|
30
31
|
def run
|
@@ -38,5 +39,13 @@ class Green
|
|
38
39
|
def callback(&blk)
|
39
40
|
raise "override"
|
40
41
|
end
|
42
|
+
|
43
|
+
def socket_waiter(socket)
|
44
|
+
raise "override"
|
45
|
+
end
|
46
|
+
|
47
|
+
def stop
|
48
|
+
raise "override"
|
49
|
+
end
|
41
50
|
end
|
42
51
|
end
|
data/lib/green/monkey.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|
1
|
+
require 'green/socket'
|
2
|
+
|
3
|
+
original_verbosity = $VERBOSE
|
4
|
+
$VERBOSE = nil
|
5
|
+
|
6
|
+
Socket = Green::Socket
|
7
|
+
TCPSocket = Green::TCPSocket
|
8
|
+
TCPServer = Green::TCPServer
|
9
|
+
|
10
|
+
|
11
|
+
$VERBOSE = original_verbosity
|
data/lib/green/mysql2.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mysql2'
|
2
|
+
class Green
|
3
|
+
module Mysql2
|
4
|
+
class Client < ::Mysql2::Client
|
5
|
+
def query(sql, opts={})
|
6
|
+
super(sql, opts.merge(:async => true))
|
7
|
+
green_waiter.wait_read
|
8
|
+
async_result
|
9
|
+
end
|
10
|
+
|
11
|
+
def green_waiter
|
12
|
+
@green_waiter ||= Green.hub.socket_waiter(Socket.for_fd(self.socket))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/green/semaphore.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
class Green
|
2
2
|
class Semaphore
|
3
|
-
|
4
|
-
attr_accessor :counter
|
3
|
+
attr_accessor :counter, :value
|
5
4
|
def initialize(value = 1)
|
5
|
+
@value = value
|
6
6
|
@counter = value
|
7
7
|
@links = []
|
8
8
|
end
|
9
9
|
|
10
|
+
def wait_links
|
11
|
+
@wait_links ||= []
|
12
|
+
end
|
13
|
+
|
10
14
|
def acquire
|
11
15
|
if counter > 0
|
12
16
|
self.counter -= 1
|
@@ -14,7 +18,7 @@ class Green
|
|
14
18
|
else
|
15
19
|
g = Green.current
|
16
20
|
clb = rawlink { g.switch }
|
17
|
-
Green.hub.wait
|
21
|
+
Green.hub.wait { unlink clb }
|
18
22
|
self.counter -= 1
|
19
23
|
true
|
20
24
|
end
|
@@ -22,10 +26,11 @@ class Green
|
|
22
26
|
|
23
27
|
def release
|
24
28
|
self.counter += 1
|
29
|
+
wait_links.dup.each(&:call)
|
25
30
|
if @links.size > 0
|
26
31
|
l = @links.pop
|
27
32
|
Green.hub.callback { l.call }
|
28
|
-
end
|
33
|
+
end
|
29
34
|
end
|
30
35
|
|
31
36
|
def rawlink(&clb)
|
@@ -37,8 +42,133 @@ class Green
|
|
37
42
|
@links.delete clb
|
38
43
|
end
|
39
44
|
|
40
|
-
def
|
41
|
-
|
45
|
+
def wait(v = value)
|
46
|
+
if counter >= v
|
47
|
+
return counter
|
48
|
+
else
|
49
|
+
g = Green.current
|
50
|
+
clb = proc do
|
51
|
+
if counter >= v && @links.size == 0
|
52
|
+
wait_links.delete clb
|
53
|
+
Green.hub.callback { g.switch }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
wait_links << clb
|
57
|
+
Green.hub.wait { wait_links.delete clb }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def wait_avaliable
|
62
|
+
wait value - 1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# With Ruby compatible API
|
67
|
+
class Mutex < Semaphore
|
68
|
+
def initialize
|
69
|
+
super 1
|
70
|
+
@slept = {}
|
71
|
+
end
|
72
|
+
|
73
|
+
def synchronize
|
74
|
+
lock
|
75
|
+
yield
|
76
|
+
ensure
|
77
|
+
unlock
|
78
|
+
end
|
79
|
+
|
80
|
+
def lock
|
81
|
+
if Green.current.locals["mutex_locked_#{self.object_id}"]
|
82
|
+
Green.current.locals.delete "mutex_locked_#{self.object_id}"
|
83
|
+
raise Green::GreenError.new
|
84
|
+
end
|
85
|
+
Green.current.locals["mutex_locked_#{self.object_id}"] = true
|
86
|
+
acquire
|
87
|
+
end
|
88
|
+
|
89
|
+
def unlock
|
90
|
+
raise Green::GreenError.new unless Green.current.locals["mutex_locked_#{self.object_id}"]
|
91
|
+
Green.current.locals.delete "mutex_locked_#{self.object_id}"
|
92
|
+
release
|
93
|
+
end
|
94
|
+
|
95
|
+
def _wakeup(green)
|
96
|
+
if @slept.delete(green)
|
97
|
+
Green.hub.callback { green.switch }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def sleep(timeout = nil)
|
102
|
+
unlock
|
103
|
+
beg = Time.now
|
104
|
+
current = Green.current
|
105
|
+
@slept[current] = true
|
106
|
+
begin
|
107
|
+
if timeout
|
108
|
+
t = Green.hub.timer(timeout) { _wakeup(current) }
|
109
|
+
Green.hub.switch
|
110
|
+
t.green_cancel
|
111
|
+
else
|
112
|
+
Green.hub.switch
|
113
|
+
end
|
114
|
+
ensure
|
115
|
+
@slept.delete current
|
116
|
+
end
|
117
|
+
yield if block_given?
|
118
|
+
lock
|
119
|
+
Time.now - beg
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class ConditionVariable
|
124
|
+
def initialize
|
125
|
+
@waiters = []
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
|
130
|
+
#
|
131
|
+
# If +timeout+ is given, this method returns after +timeout+ seconds passed,
|
132
|
+
# even if no other thread doesn't signal.
|
133
|
+
#
|
134
|
+
def wait(mutex, timeout=nil)
|
135
|
+
current = Green.current
|
136
|
+
pair = [mutex, current]
|
137
|
+
@waiters << pair
|
138
|
+
mutex.sleep timeout do
|
139
|
+
@waiters.delete pair
|
140
|
+
end
|
141
|
+
self
|
142
|
+
end
|
143
|
+
|
144
|
+
def _wakeup(mutex, green)
|
145
|
+
if alive = green.alive?
|
146
|
+
Green.hub.callback {
|
147
|
+
mutex._wakeup(green)
|
148
|
+
}
|
149
|
+
end
|
150
|
+
alive
|
151
|
+
end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Wakes up the first thread in line waiting for this lock.
|
155
|
+
#
|
156
|
+
def signal
|
157
|
+
while (pair = @waiters.shift)
|
158
|
+
break if _wakeup(*pair)
|
159
|
+
end
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Wakes up all threads waiting for this lock.
|
165
|
+
#
|
166
|
+
def broadcast
|
167
|
+
@waiters.each do |mutex, green|
|
168
|
+
_wakeup(mutex, green)
|
169
|
+
end
|
170
|
+
@waiters.clear
|
171
|
+
self
|
42
172
|
end
|
43
173
|
end
|
44
174
|
end
|
data/lib/green/socket.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require "fcntl"
|
2
|
+
require 'socket'
|
3
|
+
require 'kgio'
|
4
|
+
|
5
|
+
class Green
|
6
|
+
|
7
|
+
ERRORS = Errno::constants.each_with_object({}) do |c, h|
|
8
|
+
const = Errno.const_get(c)
|
9
|
+
h[const::Errno] = const
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO puts
|
13
|
+
class Socket < ::Socket
|
14
|
+
READ_BUFFER_SIZE = 65536
|
15
|
+
|
16
|
+
include Kgio::SocketMethods
|
17
|
+
|
18
|
+
def write(str)
|
19
|
+
kgio_write(str)
|
20
|
+
str.bytesize
|
21
|
+
end
|
22
|
+
|
23
|
+
def read(length = nil, buffer = nil)
|
24
|
+
res = []
|
25
|
+
readed = 0
|
26
|
+
begin # begin ... while
|
27
|
+
need_read = if length
|
28
|
+
length - readed
|
29
|
+
else
|
30
|
+
READ_BUFFER_SIZE
|
31
|
+
end
|
32
|
+
data = kgio_read(need_read)
|
33
|
+
if data.nil? && length.nil? && readed == 0
|
34
|
+
return ''
|
35
|
+
elsif data.nil? && readed == 0
|
36
|
+
return nil
|
37
|
+
elsif data.nil?
|
38
|
+
return buffer ? buffer.replace(res * '') : res * ''
|
39
|
+
else
|
40
|
+
readed += data.size
|
41
|
+
res << data
|
42
|
+
end
|
43
|
+
end while length != readed
|
44
|
+
return buffer ? buffer.replace(res * '') : res * ''
|
45
|
+
end
|
46
|
+
|
47
|
+
def recv(maxlen, flags = 0)
|
48
|
+
recv_nonblock(maxlen)
|
49
|
+
rescue Errno::EAGAIN
|
50
|
+
waiter.wait_read
|
51
|
+
retry
|
52
|
+
end
|
53
|
+
|
54
|
+
def send(mesg, flags, dest_sockaddr = nil)
|
55
|
+
# FIXME
|
56
|
+
write mesg
|
57
|
+
end
|
58
|
+
|
59
|
+
def kgio_wait_readable
|
60
|
+
waiter.wait_write
|
61
|
+
end
|
62
|
+
|
63
|
+
def kgio_wait_readable
|
64
|
+
waiter.wait_read
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.accept_socket_class
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def accept
|
72
|
+
s, a = accept_nonblock
|
73
|
+
[self.class.accept_socket_class.for_fd(s.fileno), a]
|
74
|
+
rescue Errno::EAGAIN
|
75
|
+
waiter.wait_read
|
76
|
+
retry
|
77
|
+
end
|
78
|
+
|
79
|
+
def connect(sock_addr)
|
80
|
+
connect_nonblock(sock_addr)
|
81
|
+
rescue Errno::EINPROGRESS
|
82
|
+
error, = getsockopt(::Socket::SOL_SOCKET, ::Socket::SO_ERROR).unpack('i')
|
83
|
+
if error != 0
|
84
|
+
raise ERRORS[error]
|
85
|
+
else
|
86
|
+
waiter.wait_write
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def waiter
|
91
|
+
@waiter ||= Green.hub.socket_waiter(self)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class TCPSocket < Socket
|
96
|
+
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
97
|
+
addrinfo = Addrinfo.tcp(remote_host, remote_port)
|
98
|
+
super(addrinfo.ipv4? ? :INET : :INET6, :STREAM, 0)
|
99
|
+
if local_host && local_port
|
100
|
+
bind(Addrinfo.tcp(local_host, local_port))
|
101
|
+
end
|
102
|
+
connect addrinfo
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class TCPServer < Socket
|
107
|
+
def initialize(host, port)
|
108
|
+
addrinfo = Addrinfo.tcp(host, port)
|
109
|
+
super(addrinfo.ipv4? ? :INET : :INET6, :STREAM, 0)
|
110
|
+
setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
|
111
|
+
bind(addrinfo)
|
112
|
+
listen(5)
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def self.accept_socket_class
|
117
|
+
TCPSocket
|
118
|
+
end
|
119
|
+
|
120
|
+
def accept
|
121
|
+
super[0]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/green/zmq.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'green'
|
2
|
+
require 'ffi-rzmq'
|
3
|
+
|
4
|
+
class Green
|
5
|
+
module ZMQ
|
6
|
+
class Waiter
|
7
|
+
attr_reader :socket_waiter, :waiters
|
8
|
+
def initialize(fd)
|
9
|
+
@socket_waiter = Green.hub.socket_waiter(Socket.for_fd(fd))
|
10
|
+
@waiters = []
|
11
|
+
@notifier = Green.spawn do
|
12
|
+
while true
|
13
|
+
@socket_waiter.wait_read
|
14
|
+
wake
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def lock
|
20
|
+
g = Green.current
|
21
|
+
@waiters << g
|
22
|
+
Green.hub.wait { @waiters.delete g }
|
23
|
+
end
|
24
|
+
|
25
|
+
def wake
|
26
|
+
w = @waiters.shift
|
27
|
+
Green.hub.callback { w.switch } if w
|
28
|
+
end
|
29
|
+
|
30
|
+
def cancel
|
31
|
+
@notifier.kill
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module ZMQ
|
38
|
+
class Context
|
39
|
+
alias :original_terminate :terminate
|
40
|
+
def terminate
|
41
|
+
Green.hub.callback do
|
42
|
+
original_terminate
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Socket
|
48
|
+
def initialize(*args)
|
49
|
+
super
|
50
|
+
fd, = [].tap { |a| getsockopt(ZMQ::FD, a) }
|
51
|
+
@waiter = Green::ZMQ::Waiter.new fd
|
52
|
+
end
|
53
|
+
|
54
|
+
alias :bsendmsg :sendmsg
|
55
|
+
def sendmsg(message, flags = 0)
|
56
|
+
return bsendmsg(message, flags) if (flags & ZMQ::NonBlocking) != 0
|
57
|
+
flags |= ZMQ::NonBlocking
|
58
|
+
loop do
|
59
|
+
rc = bsendmsg message, flags
|
60
|
+
if rc == -1 && ZMQ::Util.errno == EAGAIN
|
61
|
+
@waiter.lock
|
62
|
+
else
|
63
|
+
@waiter.wake
|
64
|
+
return rc
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
alias :brecvmsg :recvmsg
|
70
|
+
def recvmsg(message, flags = 0)
|
71
|
+
return brecvmsg(message, flags) if (flags & ZMQ::NonBlocking) != 0
|
72
|
+
flags |= ZMQ::NonBlocking
|
73
|
+
loop do
|
74
|
+
rc = brecvmsg message, flags
|
75
|
+
if rc == -1 && ZMQ::Util.errno == EAGAIN
|
76
|
+
@waiter.lock
|
77
|
+
else
|
78
|
+
@waiter.wake
|
79
|
+
return rc
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
alias :original_close :close
|
85
|
+
def close
|
86
|
+
@waiter.cancel
|
87
|
+
Green.hub.callback do
|
88
|
+
original_close
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/green-em/em-http.rb
CHANGED
@@ -12,15 +12,14 @@ module EventMachine
|
|
12
12
|
alias :a#{type} :#{type}
|
13
13
|
def #{type}(options = {}, &blk)
|
14
14
|
g = Green.current
|
15
|
-
|
16
15
|
conn = setup_request(:#{type}, options, &blk)
|
17
16
|
if conn.error.nil?
|
18
17
|
conn.callback { g.switch(conn) }
|
19
|
-
conn.errback { g.throw(HTTPException.new
|
18
|
+
conn.errback { g.throw(HTTPException.new) }
|
20
19
|
|
21
|
-
Green.hub.wait
|
20
|
+
Green.hub.wait { conn.green_cancel }
|
22
21
|
else
|
23
|
-
raise HTTPException.new
|
22
|
+
raise HTTPException.new
|
24
23
|
end
|
25
24
|
end
|
26
25
|
]
|