packet 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README +4 -0
- data/Rakefile +16 -8
- data/TODO +8 -0
- data/examples/asteroid.c +296 -0
- data/examples/asteroid.h +5 -0
- data/examples/concurrent_thread.c +53 -0
- data/examples/extconf.h +4 -0
- data/examples/extconf.rb +10 -0
- data/examples/persistent_print.rb +24 -0
- data/examples/sample_server.rb +19 -0
- data/examples/use_stuff.rb +3 -0
- data/lib/bin_parser.rb +16 -8
- data/lib/class_helpers.rb +74 -0
- data/lib/connection.rb +18 -18
- data/lib/core.rb +38 -13
- data/lib/double_keyed_hash.rb +6 -0
- data/lib/meta_pimp.rb +20 -6
- data/lib/nbio.rb +27 -30
- data/lib/packet.rb +6 -6
- data/lib/packet_master.rb +55 -58
- data/lib/pimp.rb +1 -0
- data/lib/thread_pool.rb +54 -0
- data/lib/timer_store.rb +63 -0
- data/lib/worker.rb +4 -28
- data/lib/worker_pool.rb +10 -0
- metadata +66 -55
- data/LICENSE +0 -4
- data/bin/packet_mongrel.rb +0 -215
- data/bin/runner.rb +0 -35
- data/lib/attribute_accessors.rb +0 -48
- data/lib/buftok.rb +0 -127
- data/lib/cpu_worker.rb +0 -19
- data/lib/deferrable.rb +0 -210
- data/lib/io_worker.rb +0 -6
- data/lib/ruby_hacks.rb +0 -125
data/examples/extconf.h
ADDED
data/examples/extconf.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "eventmachine"
|
3
|
+
|
4
|
+
module Client
|
5
|
+
def receive_data data
|
6
|
+
@tokenizer.extract(data).each do |b_data|
|
7
|
+
client_data = b_data
|
8
|
+
p "Client has sent #{client_data}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def start_push_on_client
|
13
|
+
send_data("Hello World : #{Time.now}\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
def post_init
|
17
|
+
@tokenizer = BufferedTokenizer.new
|
18
|
+
EM::add_periodic_timer(1) { start_push_on_client }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
EM.run do
|
23
|
+
EM.start_server("localhost",11009,Client)
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "asteroid"
|
2
|
+
|
3
|
+
module Server
|
4
|
+
def receive_data data
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
def post_init
|
9
|
+
puts "A new client connected"
|
10
|
+
end
|
11
|
+
|
12
|
+
def unbind
|
13
|
+
puts "client disconnected"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Asteroid::run("0.0.0.0", 11007, Server) do
|
18
|
+
puts "Someone connected"
|
19
|
+
end
|
data/lib/bin_parser.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# FIXME: write this stupid parser in C.
|
2
1
|
class BinParser
|
3
2
|
def initialize
|
4
3
|
@size = 0
|
@@ -10,8 +9,8 @@ class BinParser
|
|
10
9
|
@numeric_length = 0
|
11
10
|
end
|
12
11
|
|
13
|
-
|
14
|
-
|
12
|
+
def extract new_data, &block
|
13
|
+
extracter_block = block
|
15
14
|
if @parser_state == 0
|
16
15
|
length_to_read = 9 - @length_string.length
|
17
16
|
len_str,remaining = new_data.unpack("a#{length_to_read}a*")
|
@@ -25,13 +24,22 @@ class BinParser
|
|
25
24
|
if remaining.length < @numeric_length
|
26
25
|
@data << remaining
|
27
26
|
@numeric_length = @numeric_length - remaining.length
|
28
|
-
|
27
|
+
elsif remaining.length == @numeric_length
|
29
28
|
@data << remaining
|
30
|
-
|
29
|
+
extracter_block.call(@data.join)
|
30
|
+
@data = []
|
31
|
+
@parser_state = 0
|
32
|
+
@length_string = ""
|
33
|
+
@numeric_length = 0
|
34
|
+
else
|
35
|
+
pack_data,remaining = remaining.unpack("a#{@numeric_length}a*")
|
36
|
+
@data << pack_data
|
37
|
+
extracter_block.call(@data.join)
|
31
38
|
@data = []
|
32
39
|
@parser_state = 0
|
33
40
|
@length_string = ""
|
34
41
|
@numeric_length = 0
|
42
|
+
extract(remaining,&extracter_block)
|
35
43
|
end
|
36
44
|
end
|
37
45
|
elsif @parser_state == 1
|
@@ -41,19 +49,19 @@ class BinParser
|
|
41
49
|
@numeric_length = @numeric_length - pack_data.length
|
42
50
|
elsif pack_data.length == @numeric_length
|
43
51
|
@data << pack_data
|
44
|
-
|
52
|
+
extracter_block.call(@data.join)
|
45
53
|
@data = []
|
46
54
|
@parser_state = 0
|
47
55
|
@length_string = ""
|
48
56
|
@numeric_length = 0
|
49
57
|
else
|
50
58
|
@data << pack_data
|
51
|
-
|
59
|
+
extracter_block.call(@data.join)
|
52
60
|
@data = []
|
53
61
|
@parser_state = 0
|
54
62
|
@length_string = ""
|
55
63
|
@numeric_length = 0
|
56
|
-
extract(remaining)
|
64
|
+
extract(remaining,&extracter_block)
|
57
65
|
end
|
58
66
|
end
|
59
67
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Packet
|
2
|
+
module ClassHelpers
|
3
|
+
def metaclass; class << self; self; end; end
|
4
|
+
|
5
|
+
def iattr_accessor *args
|
6
|
+
metaclass.instance_eval do
|
7
|
+
attr_accessor *args
|
8
|
+
args.each do |attr|
|
9
|
+
define_method("set_#{attr}") do |b_value|
|
10
|
+
self.send("#{attr}=",b_value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
args.each do |attr|
|
16
|
+
class_eval do
|
17
|
+
define_method(attr) do
|
18
|
+
self.class.send(attr)
|
19
|
+
end
|
20
|
+
define_method("#{attr}=") do |b_value|
|
21
|
+
self.class.send("#{attr}=",b_value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end # end of method iattr_accessor
|
26
|
+
|
27
|
+
def cattr_reader(*syms)
|
28
|
+
syms.flatten.each do |sym|
|
29
|
+
next if sym.is_a?(Hash)
|
30
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
31
|
+
unless defined? @@#{sym}
|
32
|
+
@@#{sym} = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.#{sym}
|
36
|
+
@@#{sym}
|
37
|
+
end
|
38
|
+
|
39
|
+
def #{sym}
|
40
|
+
@@#{sym}
|
41
|
+
end
|
42
|
+
EOS
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def cattr_writer(*syms)
|
47
|
+
options = syms.last.is_a?(Hash) ? syms.pop : {}
|
48
|
+
syms.flatten.each do |sym|
|
49
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
50
|
+
unless defined? @@#{sym}
|
51
|
+
@@#{sym} = nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.#{sym}=(obj)
|
55
|
+
@@#{sym} = obj
|
56
|
+
end
|
57
|
+
|
58
|
+
#{"
|
59
|
+
def #{sym}=(obj)
|
60
|
+
@@#{sym} = obj
|
61
|
+
end
|
62
|
+
" unless options[:instance_writer] == false }
|
63
|
+
EOS
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def cattr_accessor(*syms)
|
68
|
+
cattr_reader(*syms)
|
69
|
+
cattr_writer(*syms)
|
70
|
+
end
|
71
|
+
module_function :metaclass,:iattr_accessor, :cattr_writer, :cattr_reader, :cattr_accessor
|
72
|
+
end # end of module ClassHelpers
|
73
|
+
end
|
74
|
+
|
data/lib/connection.rb
CHANGED
@@ -2,32 +2,32 @@
|
|
2
2
|
# main eventloop.
|
3
3
|
|
4
4
|
module Packet
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def unbind
|
13
|
-
|
5
|
+
module Connection
|
6
|
+
def send_data p_data
|
7
|
+
begin
|
8
|
+
write_data(p_data,connection)
|
9
|
+
rescue DisconnectError => sock_error
|
10
|
+
close_connection
|
11
|
+
end
|
14
12
|
end
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
def invoke_init
|
15
|
+
@initialized = true
|
16
|
+
post_init if respond_to?(:post_init)
|
19
17
|
end
|
20
18
|
|
21
|
-
def
|
22
|
-
|
19
|
+
def close_connection
|
20
|
+
unbind if respond_to?(:unbind)
|
21
|
+
reactor.remove_connection(connection)
|
23
22
|
end
|
24
23
|
|
25
|
-
def
|
26
|
-
|
24
|
+
def close_connection_after_writing
|
25
|
+
connection.flush
|
26
|
+
close_connection
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
|
29
|
+
def send_object p_object
|
30
|
+
dump_object(p_object,connection)
|
31
31
|
end
|
32
32
|
end # end of class Connection
|
33
33
|
end # end of module Packet
|
data/lib/core.rb
CHANGED
@@ -4,17 +4,19 @@ module Packet
|
|
4
4
|
def self.included(base_klass)
|
5
5
|
base_klass.extend(ClassMethods)
|
6
6
|
base_klass.instance_eval do
|
7
|
-
# iattr_accessor :connection_callbacks
|
8
7
|
@@connection_callbacks ||= {}
|
8
|
+
|
9
|
+
iattr_accessor :thread_pool_size
|
9
10
|
cattr_accessor :connection_callbacks
|
10
11
|
attr_accessor :read_ios, :write_ios, :listen_sockets
|
11
12
|
attr_accessor :connection_completion_awaited
|
12
|
-
attr_accessor :connections
|
13
|
+
attr_accessor :connections, :thread_pool, :windows_flag
|
13
14
|
include CommonMethods
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
18
|
module ClassMethods
|
19
|
+
include Packet::ClassHelpers
|
18
20
|
def after_connection p_method
|
19
21
|
connection_callbacks[:after_connection] ||= []
|
20
22
|
connection_callbacks[:after_connection] << p_method
|
@@ -64,9 +66,9 @@ module Packet
|
|
64
66
|
|
65
67
|
def accept_connection(sock_opts)
|
66
68
|
sock_io = sock_opts[:socket]
|
67
|
-
|
68
69
|
begin
|
69
70
|
client_socket,client_sockaddr = sock_io.accept_nonblock
|
71
|
+
client_socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
|
70
72
|
rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
|
71
73
|
puts "not ready yet"
|
72
74
|
return
|
@@ -87,7 +89,8 @@ module Packet
|
|
87
89
|
|
88
90
|
read_ios << t_sock if actually_connected
|
89
91
|
write_ios.delete(t_sock)
|
90
|
-
decorate_handler(t_sock,actually_connected,sock_opts[:sock_addr]
|
92
|
+
decorate_handler(t_sock,actually_connected,sock_opts[:sock_addr],\
|
93
|
+
sock_opts[:module],&sock_opts[:block])
|
91
94
|
connection_completion_awaited.delete(t_sock.fileno)
|
92
95
|
end
|
93
96
|
|
@@ -110,12 +113,9 @@ module Packet
|
|
110
113
|
|
111
114
|
# method opens a socket for listening
|
112
115
|
def start_server(ip,port,t_module,&block)
|
113
|
-
|
114
|
-
t_socket.
|
115
|
-
|
116
|
-
t_socket.bind(sockaddr)
|
117
|
-
t_socket.listen(50)
|
118
|
-
t_socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
|
116
|
+
BasicSocket.do_not_reverse_lookup = true
|
117
|
+
t_socket = TCPServer.new(ip,port.to_i)
|
118
|
+
# t_socket.setsockopt(*@tcp_defer_accept_opts) rescue nil
|
119
119
|
listen_sockets[t_socket.fileno] = { :socket => t_socket,:block => block,:module => t_module }
|
120
120
|
@read_ios << t_socket
|
121
121
|
end
|
@@ -126,11 +126,15 @@ module Packet
|
|
126
126
|
Signal.trap("INT") { shutdown }
|
127
127
|
loop do
|
128
128
|
check_for_timer_events
|
129
|
+
user_thread_window #=> let user level threads run for a while
|
129
130
|
ready_fds = select(@read_ios,@write_ios,nil,0.005)
|
130
|
-
next if ready_fds.blank?
|
131
|
+
#next if ready_fds.blank?
|
132
|
+
|
133
|
+
next if !ready_fds or ready_fds.empty?
|
134
|
+
|
131
135
|
ready_fds = ready_fds.flatten.compact
|
132
136
|
ready_fds.each do |t_sock|
|
133
|
-
if t_sock.is_a?
|
137
|
+
if(unix? && t_sock.is_a?(UNIXSocket))
|
134
138
|
handle_internal_messages(t_sock)
|
135
139
|
else
|
136
140
|
handle_external_messages(t_sock)
|
@@ -139,11 +143,18 @@ module Packet
|
|
139
143
|
end
|
140
144
|
end
|
141
145
|
|
146
|
+
def user_thread_window
|
147
|
+
# run_user_threads if respond_to?(:run_user_threads)
|
148
|
+
@thread_pool.exclusive_run
|
149
|
+
end
|
150
|
+
|
142
151
|
def terminate_me
|
152
|
+
# FIXME: close the open sockets
|
143
153
|
exit
|
144
154
|
end
|
145
155
|
|
146
156
|
def shutdown
|
157
|
+
# FIXME: close the open sockets
|
147
158
|
exit
|
148
159
|
end
|
149
160
|
|
@@ -182,6 +193,7 @@ module Packet
|
|
182
193
|
|
183
194
|
def add_timer(elapsed_time,&block)
|
184
195
|
t_timer = Event.new(elapsed_time,&block)
|
196
|
+
# @timer_hash.store(timer)
|
185
197
|
@timer_hash[t_timer.timer_signature] = t_timer
|
186
198
|
return t_timer
|
187
199
|
end
|
@@ -197,11 +209,24 @@ module Packet
|
|
197
209
|
@connections ||= {}
|
198
210
|
@listen_sockets ||= {}
|
199
211
|
|
212
|
+
# @timer_hash = Packet::TimerStore
|
200
213
|
@timer_hash ||= {}
|
214
|
+
@thread_pool = ThreadPool.new(thread_pool_size || 20)
|
215
|
+
@windows_flag = windows?
|
216
|
+
end
|
217
|
+
|
218
|
+
def windows?
|
219
|
+
return true if RUBY_PLATFORM =~ /win32/i
|
220
|
+
return false
|
221
|
+
end
|
222
|
+
|
223
|
+
def unix?
|
224
|
+
!@windows_flag
|
201
225
|
end
|
202
226
|
|
203
227
|
def check_for_timer_events
|
204
228
|
@timer_hash.each do |key,timer|
|
229
|
+
@timer_hash.delete(key) if timer.cancel_flag
|
205
230
|
if timer.run_now?
|
206
231
|
timer.run
|
207
232
|
@timer_hash.delete(key) if !timer.respond_to?(:interval)
|
@@ -231,7 +256,7 @@ module Packet
|
|
231
256
|
t_signature = Guid.hexdigest
|
232
257
|
handler_instance.signature = t_signature
|
233
258
|
connections[t_socket.fileno] =
|
234
|
-
OpenStruct.new(
|
259
|
+
OpenStruct.new(:socket => t_socket, :instance => handler_instance, :signature => t_signature,:sock_addr => sock_addr)
|
235
260
|
block.call(handler_instance) if block
|
236
261
|
handler_instance.connection_completed if handler_instance.respond_to?(:connection_completed)
|
237
262
|
end
|
data/lib/double_keyed_hash.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
class DoubleKeyedHash
|
2
|
+
attr_accessor :internal_hash
|
2
3
|
def initialize
|
3
4
|
@keys1 = {}
|
4
5
|
@internal_hash = {}
|
@@ -13,6 +14,11 @@ class DoubleKeyedHash
|
|
13
14
|
@internal_hash[key] || @internal_hash[@keys1[key]]
|
14
15
|
end
|
15
16
|
|
17
|
+
def delete(key)
|
18
|
+
@keys1.delete(key)
|
19
|
+
@internal_hash.delete(key)
|
20
|
+
end
|
21
|
+
|
16
22
|
def each
|
17
23
|
@internal_hash.each { |key,value| yield(key,value)}
|
18
24
|
end
|
data/lib/meta_pimp.rb
CHANGED
@@ -4,16 +4,16 @@
|
|
4
4
|
class Packet::MetaPimp < Packet::Pimp
|
5
5
|
# initializer of pimp
|
6
6
|
attr_accessor :callback_hash
|
7
|
-
attr_accessor :worker_status
|
7
|
+
attr_accessor :worker_status, :worker_key
|
8
8
|
def pimp_init
|
9
9
|
@callback_hash ||= {}
|
10
10
|
@worker_status = nil
|
11
|
+
@worker_result = nil
|
12
|
+
@worker_key = nil
|
11
13
|
@tokenizer = BinParser.new
|
12
14
|
end
|
13
15
|
|
14
16
|
# will be invoked whenever there is a response from the worker
|
15
|
-
# Possible bug with reading large responses.
|
16
|
-
# response would be binary but base64 encoded and must be decoded and then loaded
|
17
17
|
def receive_data p_data
|
18
18
|
@tokenizer.extract(p_data) do |b_data|
|
19
19
|
t_data = Marshal.load(b_data)
|
@@ -29,11 +29,18 @@ class Packet::MetaPimp < Packet::Pimp
|
|
29
29
|
process_response(data_options)
|
30
30
|
when :status
|
31
31
|
save_worker_status(data_options)
|
32
|
+
when :result
|
33
|
+
save_worker_result(data_options)
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
37
|
+
def save_worker_result(data_options = { })
|
38
|
+
@worker_result = data_options[:data]
|
39
|
+
end
|
40
|
+
|
35
41
|
def save_worker_status(data_options = { })
|
36
|
-
@worker_status = data_options[:data]
|
42
|
+
# @worker_status = data_options[:data]
|
43
|
+
reactor.update_result(worker_key,data_options[:data])
|
37
44
|
end
|
38
45
|
|
39
46
|
def process_request(data_options = {})
|
@@ -45,9 +52,16 @@ class Packet::MetaPimp < Packet::Pimp
|
|
45
52
|
def process_response(data_options = {})
|
46
53
|
if callback_signature = data_options[:callback_signature]
|
47
54
|
callback = callback_hash[callback_signature]
|
48
|
-
|
55
|
+
# there coule be bug when you are trying to send the data back to the client
|
56
|
+
begin
|
57
|
+
callback.invoke(data_options)
|
58
|
+
rescue
|
59
|
+
end
|
49
60
|
elsif client_signature = data_options[:client_signature]
|
50
|
-
|
61
|
+
begin
|
62
|
+
reactor.connections[client_signature].instance.worker_receive(data_options)
|
63
|
+
rescue
|
64
|
+
end
|
51
65
|
end
|
52
66
|
end
|
53
67
|
|