packet 0.1.0 → 0.1.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/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
|
|