packet 0.1.5 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -252,4 +252,3 @@ end
252
252
 
253
253
 
254
254
 
255
-
data/Rakefile CHANGED
@@ -17,6 +17,7 @@ $LOAD_PATH.unshift __DIR__+'/lib'
17
17
  require 'packet'
18
18
 
19
19
  CLEAN.include ['**/.*.sw?', '*.gem', '.config','*.rbc']
20
+ Dir["tasks/**/*.rake"].each { |rake| load rake }
20
21
 
21
22
 
22
23
  @windows = (PLATFORM =~ /win32/)
@@ -30,17 +31,6 @@ task :default => [:package]
30
31
 
31
32
  task :doc => [:rdoc]
32
33
 
33
-
34
- Rake::RDocTask.new do |rdoc|
35
- files = ['README', 'MIT-LICENSE', 'CHANGELOG',
36
- 'lib/**/*.rb']
37
- rdoc.rdoc_files.add(files)
38
- rdoc.main = 'README'
39
- rdoc.title = 'Packet Docs'
40
- rdoc.rdoc_dir = 'doc/rdoc'
41
- rdoc.options << '--line-numbers' << '--inline-source'
42
- end
43
-
44
34
  spec = Gem::Specification.new do |s|
45
35
  s.name = NAME
46
36
  s.version = Packet::VERSION
@@ -55,10 +45,10 @@ spec = Gem::Specification.new do |s|
55
45
  s.email = 'mail@gnufied.org'
56
46
  s.homepage = 'http://code.google.com/p/packet/'
57
47
  s.required_ruby_version = '>= 1.8.5'
58
-
59
48
  s.files = %w(MIT-LICENSE README Rakefile TODO) + Dir.glob("{spec,lib,examples}/**/*")
60
-
61
49
  s.require_path = "lib"
50
+ s.bindir = "bin"
51
+ s.executables = "packet_worker_runner"
62
52
  end
63
53
 
64
54
  Rake::GemPackageTask.new(spec) do |p|
@@ -75,16 +65,6 @@ task :uninstall => [:clean] do
75
65
  sh %{#{SUDO} gem uninstall #{NAME}}
76
66
  end
77
67
 
78
- ##############################################################################
79
- # SVN
80
- ##############################################################################
81
-
82
- desc "Add new files to subversion"
83
- task :svn_add do
84
- system "svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add"
85
- end
86
-
87
-
88
68
  desc "Converts a YAML file into a test/spec skeleton"
89
69
  task :yaml_to_spec do
90
70
  require 'yaml'
@@ -93,3 +73,4 @@ task :yaml_to_spec do
93
73
  t+(s ?%.context "#{c}" do.+s.map{|d|%.\n xspecify "#{d}" do\n end\n.}*''+"end\n\n":'')
94
74
  }.strip
95
75
  end
76
+
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ PACKET_LIB_PATH = File.expand_path(File.dirname(__FILE__))
3
+ ["lib"].each { |x| $LOAD_PATH.unshift(File.join(PACKET_LIB_PATH,"..",x))}
4
+
5
+ require "packet"
6
+
7
+ module Packet
8
+ class WorkerRunner
9
+ include Packet::NbioHelper
10
+ def initialize args
11
+ cmd_args = args.split(':')
12
+ worker_name = cmd_args[2]
13
+ initial_arg_data_length = cmd_args[3].to_i
14
+ @worker_root = cmd_args[4]
15
+ @worker_load_env = cmd_args[5]
16
+
17
+
18
+ @worker_read_fd = UNIXSocket.for_fd(cmd_args[0].to_i)
19
+
20
+ @worker_write_fd = UNIXSocket.for_fd(cmd_args[1].to_i)
21
+
22
+ initial_arg_data = @worker_read_fd.read(initial_arg_data_length)
23
+
24
+ Packet::WorkerRunner.const_set(:WORKER_OPTIONS,Marshal.load(initial_arg_data))
25
+ require @worker_load_env if @worker_load_env && !@worker_load_env.empty?
26
+ load_worker worker_name
27
+ end
28
+
29
+ def load_worker worker_name
30
+ if @worker_root && (File.file? "#{@worker_root}/#{worker_name}.rb")
31
+ require "#{@worker_root}/#{worker_name}"
32
+ worker_klass = Object.const_get(packet_classify(worker_name))
33
+ worker_klass.start_worker(:read_end => @worker_read_fd,:write_end => @worker_write_fd,:options => WORKER_OPTIONS)
34
+ else
35
+ require worker_name
36
+ worker_klass = Object.const_get(packet_classify(worker_name))
37
+ if worker_klass.is_worker?
38
+ worker_klass.start_worker(:read_end => @worker_read_fd,:write_end => @worker_write_fd,:options => WORKER_OPTIONS)
39
+ else
40
+ raise Packet::InvalidWorker.new(worker_name)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ Packet::WorkerRunner.new(ARGV[0])
48
+
49
+
50
+
@@ -6,8 +6,11 @@ require "yaml"
6
6
  require "forwardable"
7
7
  require "ostruct"
8
8
  require "thread"
9
+ require "fcntl"
10
+ #require "enumerable"
9
11
 
10
12
  require "packet/packet_parser"
13
+ require "packet/packet_invalid_worker"
11
14
  require "packet/packet_guid"
12
15
  require "packet/packet_helper"
13
16
  require "packet/double_keyed_hash"
@@ -26,5 +29,5 @@ require "packet/packet_worker"
26
29
  PACKET_APP = File.expand_path'../' unless defined?(PACKET_APP)
27
30
 
28
31
  module Packet
29
- VERSION='0.1.5'
32
+ VERSION='0.1.7'
30
33
  end
@@ -1,31 +1,40 @@
1
- class DoubleKeyedHash
2
- attr_accessor :internal_hash
3
- def initialize
4
- @keys1 = {}
5
- @internal_hash = {}
6
- end
1
+ module Packet
2
+ class DoubleKeyedHash
3
+ # include Enumerable
4
+ attr_accessor :internal_hash
5
+ def initialize
6
+ @keys1 = {}
7
+ @internal_hash = {}
8
+ end
7
9
 
8
- def []=(key1,key2,value)
9
- @keys1[key2] = key1
10
- @internal_hash[key1] = value
11
- end
10
+ def []=(key1,key2,value)
11
+ @keys1[key2] = key1
12
+ @internal_hash[key1] = value
13
+ end
12
14
 
13
- def [] key
14
- @internal_hash[key] || @internal_hash[@keys1[key]]
15
- end
15
+ def [] key
16
+ @internal_hash[key] || @internal_hash[@keys1[key]]
17
+ end
16
18
 
17
- def delete(key)
18
- t_key = @keys1[key]
19
- if t_key
20
- @keys1.delete(key)
21
- @internal_hash.delete(t_key)
22
- else
23
- @keys1.delete_if { |key,value| value == key }
24
- @internal_hash.delete(key)
19
+ def delete(key)
20
+ t_key = @keys1[key]
21
+ if t_key
22
+ @keys1.delete(key)
23
+ @internal_hash.delete(t_key)
24
+ else
25
+ @keys1.delete_if { |key,value| value == key }
26
+ @internal_hash.delete(key)
27
+ end
28
+ end
29
+
30
+ def length
31
+ @internal_hash.keys.length
25
32
  end
26
- end
27
33
 
28
- def each
29
- @internal_hash.each { |key,value| yield(key,value)}
34
+ def each
35
+ @internal_hash.each { |key,value| yield(key,value)}
36
+ end
30
37
  end
31
38
  end
39
+
40
+
@@ -12,3 +12,4 @@ module Packet
12
12
  end
13
13
  end
14
14
  end
15
+
@@ -1,14 +1,18 @@
1
- # FIMXE: following class must modify the fd_watchlist thats being monitored by
2
- # main eventloop.
3
-
4
1
  module Packet
5
2
  module Connection
6
3
  attr_accessor :outbound_data,:connection_live
4
+ attr_accessor :worker,:connection,:reactor, :initialized,:signature
5
+ include NbioHelper
6
+
7
+ def unbind; end
8
+ def connection_completed; end
9
+ def post_init; end
10
+ def receive_data data; end
7
11
 
8
12
  def send_data p_data
9
13
  @outbound_data << p_data
10
14
  begin
11
- write_and_schedule(connection)
15
+ write_and_schedule(connection)
12
16
  rescue DisconnectError => sock
13
17
  close_connection
14
18
  end
@@ -18,23 +22,69 @@ module Packet
18
22
  @initialized = true
19
23
  @connection_live = true
20
24
  @outbound_data = []
21
- post_init if respond_to?(:post_init)
25
+ post_init
22
26
  end
23
27
 
24
28
  def close_connection(sock = nil)
25
- unbind if respond_to?(:unbind)
29
+ unbind
26
30
  reactor.cancel_write(connection)
27
31
  reactor.remove_connection(connection)
28
32
  end
29
33
 
30
34
  def close_connection_after_writing
31
- connection.flush
35
+ connection.flush unless connection.closed?
32
36
  close_connection
33
37
  end
34
38
 
39
+ def get_peername
40
+ connection.getpeername
41
+ end
42
+
35
43
  def send_object p_object
36
44
  dump_object(p_object,connection)
37
45
  end
38
46
 
47
+ def ask_worker(*args)
48
+ worker_name = args.shift
49
+ data_options = *args
50
+ data_options[:client_signature] = connection.fileno
51
+ t_worker = reactor.live_workers[worker_name]
52
+ raise Packet::InvalidWorker.new("Invalid worker with name #{worker_name} and key #{data_options[:data][:worker_key]}") unless t_worker
53
+ t_worker.send_request(data_options)
54
+ end
55
+ def start_server ip,port,t_module,&block
56
+ reactor.start_server(ip,port,t_module,block)
57
+ end
58
+
59
+ def connect ip,port,t_module,&block
60
+ reactor.connect(ip,port,t_module,block)
61
+ end
62
+
63
+ def add_periodic_timer interval, &block
64
+ reactor.add_periodic_timer(interval,block)
65
+ end
66
+
67
+ def add_timer(t_time,&block)
68
+ reactor.add_timer(t_time,block)
69
+ end
70
+
71
+ def cancel_timer(t_timer)
72
+ reactor.cancel_timer(t_timer)
73
+ end
74
+
75
+ def reconnect server,port,handler
76
+ reactor.reconnect(server,port,handler)
77
+ end
78
+
79
+ def start_worker(worker_options = {})
80
+ reactor.start_worker(worker_options)
81
+ end
82
+
83
+ def delete_worker worker_options = {}
84
+ reactor.delete_worker(worker_options)
85
+ end
86
+
39
87
  end # end of class Connection
40
88
  end # end of module Packet
89
+
90
+
@@ -4,9 +4,8 @@ module Packet
4
4
  def self.included(base_klass)
5
5
  base_klass.extend(ClassMethods)
6
6
  base_klass.instance_eval do
7
- @@connection_callbacks ||= {}
8
-
9
- cattr_accessor :connection_callbacks
7
+ iattr_accessor :connection_callbacks
8
+ inheritable_attribute(:connection_callbacks,:default => {})
10
9
  attr_accessor :read_ios, :write_ios, :listen_sockets
11
10
  attr_accessor :connection_completion_awaited,:write_scheduled
12
11
  attr_accessor :connections, :windows_flag
@@ -22,6 +21,7 @@ module Packet
22
21
  connection_callbacks[:after_connection] << p_method
23
22
  end
24
23
 
24
+ # FIXME: following callbacks hasn't been tested and not usable.
25
25
  def after_unbind p_method
26
26
  connection_callbacks[:after_unbind] ||= []
27
27
  connection_callbacks[:after_unbind] << p_method
@@ -53,7 +53,9 @@ module Packet
53
53
 
54
54
  def reconnect(server,port,handler)
55
55
  raise "invalid handler" unless handler.respond_to?(:connection_completed)
56
- return handler if connections.keys.include?(handler.connection.fileno)
56
+ if !handler.connection.closed? && connections.keys.include?(handler.connection.fileno)
57
+ return handler
58
+ end
57
59
  connect(server,port,handler)
58
60
  end
59
61
 
@@ -101,9 +103,10 @@ module Packet
101
103
  connections.delete(t_sock.fileno)
102
104
  t_sock.close
103
105
  rescue
106
+ puts "#{$!.message}"
104
107
  end
105
108
  end
106
-
109
+
107
110
  def next_turn &block
108
111
  @on_next_tick = block
109
112
  end
@@ -111,7 +114,17 @@ module Packet
111
114
  # method opens a socket for listening
112
115
  def start_server(ip,port,t_module,&block)
113
116
  BasicSocket.do_not_reverse_lookup = true
114
- t_socket = TCPServer.new(ip,port.to_i)
117
+ # Comment TCPServer for the time being
118
+ #t_socket = TCPServer.new(ip,port.to_i)
119
+ #t_socket = TCPSocket.
120
+
121
+ t_socket = Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)
122
+ t_socket.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR,true)
123
+ sockaddr = Socket.sockaddr_in(port.to_i,ip)
124
+ t_socket.bind(sockaddr)
125
+ t_socket.listen(50)
126
+ t_socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
127
+
115
128
  # t_socket.setsockopt(*@tcp_defer_accept_opts) rescue nil
116
129
  listen_sockets[t_socket.fileno] = { :socket => t_socket,:block => block,:module => t_module }
117
130
  @read_ios << t_socket
@@ -124,7 +137,8 @@ module Packet
124
137
  loop do
125
138
  check_for_timer_events
126
139
  @on_next_tick.call if @on_next_tick
127
- ready_read_fds,ready_write_fds,read_error_fds = select(read_ios,write_ios,nil,0.005)
140
+
141
+ ready_read_fds,ready_write_fds,read_error_fds = select(read_ios,write_ios,[],0.005)
128
142
 
129
143
  if ready_read_fds && !ready_read_fds.empty?
130
144
  handle_read_event(ready_read_fds)
@@ -135,23 +149,25 @@ module Packet
135
149
 
136
150
  end
137
151
 
138
- def schedule_write(t_sock)
152
+ def schedule_write(t_sock,internal_instance = nil)
139
153
  fileno = t_sock.fileno
140
154
  if UNIXSocket === t_sock && internal_scheduled_write[fileno].nil?
141
155
  write_ios << t_sock
142
- internal_scheduled_write[t_sock.fileno] ||= self
143
- elsif write_scheduled[fileno].nil?
156
+ internal_scheduled_write[t_sock.fileno] ||= internal_instance
157
+ elsif write_scheduled[fileno].nil? && !(t_sock.is_a?(UNIXSocket))
144
158
  write_ios << t_sock
145
- write_scheduled[fileno] ||= connections[fileno].instance
159
+ write_scheduled[fileno] ||= connections[fileno][:instance]
146
160
  end
147
161
  end
148
162
 
149
163
  def cancel_write(t_sock)
150
- fileno = t_sock.fileno
151
- if UNIXSocket === t_sock
152
- internal_scheduled_write.delete(fileno)
153
- else
154
- write_scheduled.delete(fileno)
164
+ if !t_sock.closed?
165
+ fileno = t_sock.fileno
166
+ if UNIXSocket === t_sock
167
+ internal_scheduled_write.delete(fileno)
168
+ else
169
+ write_scheduled.delete(fileno)
170
+ end
155
171
  end
156
172
  write_ios.delete(t_sock)
157
173
  end
@@ -159,12 +175,12 @@ module Packet
159
175
  def handle_write_event(p_ready_fds)
160
176
  p_ready_fds.each do |sock_fd|
161
177
  fileno = sock_fd.fileno
162
- if UNIXSocket === sock_fd && internal_scheduled_write[fileno]
163
- write_and_schedule(sock_fd)
178
+ if UNIXSocket === sock_fd && (internal_instance = internal_scheduled_write[fileno])
179
+ internal_instance.write_and_schedule(sock_fd)
164
180
  elsif extern_opts = connection_completion_awaited[fileno]
165
181
  complete_connection(sock_fd,extern_opts)
166
182
  elsif handler_instance = write_scheduled[fileno]
167
- handler_instance.write_scheduled(sock_fd)
183
+ handler_instance.write_and_schedule(sock_fd)
168
184
  end
169
185
  end
170
186
  end
@@ -172,7 +188,7 @@ module Packet
172
188
  def handle_read_event(p_ready_fds)
173
189
  ready_fds = p_ready_fds.flatten.compact
174
190
  ready_fds.each do |t_sock|
175
- if(unix? && t_sock.is_a?(UNIXSocket))
191
+ if(t_sock.is_a?(UNIXSocket))
176
192
  handle_internal_messages(t_sock)
177
193
  else
178
194
  handle_external_messages(t_sock)
@@ -206,11 +222,12 @@ module Packet
206
222
  end
207
223
 
208
224
  def read_external_socket(t_sock)
209
- handler_instance = connections[t_sock.fileno].instance
225
+ handler_instance = connections[t_sock.fileno][:instance]
210
226
  begin
211
227
  t_data = read_data(t_sock)
212
- handler_instance.receive_data(t_data) if handler_instance.respond_to?(:receive_data)
228
+ handler_instance.receive_data(t_data)
213
229
  rescue DisconnectError => sock_error
230
+ handler_instance.receive_data(sock_error.data) unless (sock_error.data).empty?
214
231
  handler_instance.close_connection
215
232
  end
216
233
  end
@@ -275,7 +292,7 @@ module Packet
275
292
  end
276
293
  end
277
294
  end
278
-
295
+
279
296
  # close the connection with internal specified socket
280
297
  def close_connection(sock = nil)
281
298
  begin
@@ -289,28 +306,38 @@ module Packet
289
306
  return p_module if(!p_module.is_a?(Class) and !p_module.is_a?(Module))
290
307
  handler =
291
308
  if(p_module and p_module.is_a?(Class))
292
- p_module
309
+ p_module and p_module.send(:include,Connection)
293
310
  else
294
- Class.new(Connection) { p_module and include p_module }
311
+ Class.new { include Connection; include p_module; }
295
312
  end
296
313
  return handler.new
297
314
  end
298
315
 
299
316
  def decorate_handler(t_socket,actually_connected,sock_addr,t_module,&block)
300
317
  handler_instance = initialize_handler(t_module)
301
- connection_callbacks[:after_connection].each { |t_callback| self.send(t_callback,handler_instance,t_socket)}
318
+ after_connection_callbacks = connection_callbacks ? connection_callbacks[:after_connection] : nil
319
+ after_connection_callbacks && after_connection_callbacks.each { |t_callback| self.send(t_callback,handler_instance,t_socket)}
320
+ handler_instance.worker = self
321
+ handler_instance.connection = t_socket
322
+ handler_instance.reactor = self
302
323
  handler_instance.invoke_init unless handler_instance.initialized
303
324
  unless actually_connected
304
- handler_instance.unbind if handler_instance.respond_to?(:unbind)
325
+ handler_instance.unbind
305
326
  return
306
327
  end
307
328
  handler_instance.signature = binding_str
308
- connections[t_socket.fileno] =
309
- OpenStruct.new(:socket => t_socket, :instance => handler_instance, :signature => handler_instance.signature,:sock_addr => sock_addr)
329
+ # FIXME: An Struct is more fashionable, but will have some performance hit, can use a simple hash here
330
+ # klass = Struct.new(:socket,:instance,:signature,:sock_addr)
331
+ connection_data = { :socket => t_socket,:instance => handler_instance,:signature => binding_str,:sock_addr => sock_addr }
332
+ connections[t_socket.fileno] = connection_data
333
+ # connections[t_socket.fileno] = klass.new(t_socket,handler_instance,handler_instance.signature,sock_addr)
334
+
310
335
  block.call(handler_instance) if block
311
- handler_instance.connection_completed if handler_instance.respond_to?(:connection_completed)
336
+ handler_instance.connection_completed #if handler_instance.respond_to?(:connection_completed)
337
+ handler_instance
312
338
  end
313
339
 
314
340
  end # end of module#CommonMethods
315
341
  end #end of module#Core
316
342
  end #end of module#Packet
343
+
@@ -22,4 +22,4 @@ module Packet
22
22
  end
23
23
  end
24
24
  end
25
- # WOW
25
+
@@ -14,3 +14,4 @@ module Packet
14
14
  end
15
15
  end
16
16
  end
17
+
@@ -23,52 +23,24 @@ module Packet
23
23
  end
24
24
  end
25
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}
26
+
27
+ def inheritable_attribute *options_args
28
+ option_hash = options_args.last
29
+ args = options_args[0..-2]
30
+ args.each {|attr| instance_variable_set(:"@#{attr}",option_hash[:default] || nil )}
31
+ metaclass.instance_eval { attr_accessor *args }
32
+ args.each do |attr|
33
+ class_eval do
34
+ define_method(attr) do
35
+ self.class.send(attr)
36
+ end
37
+ define_method("#{attr}=") do |b_value|
38
+ self.class.send("#{attr}=",b_value)
39
+ end
41
40
  end
42
- EOS
43
41
  end
44
42
  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
43
+ module_function :metaclass,:iattr_accessor,:inheritable_attribute
72
44
  end # end of module ClassHelpers
73
45
  end
74
46
 
@@ -0,0 +1,8 @@
1
+ module Packet
2
+ class InvalidWorker < RuntimeError
3
+ attr_accessor :message
4
+ def initialize message
5
+ @message = message
6
+ end
7
+ end
8
+ end
@@ -6,7 +6,7 @@ module Packet
6
6
  attr_accessor :result_hash
7
7
 
8
8
  attr_accessor :live_workers
9
- after_connection :provide_workers
9
+ #after_connection :provide_workers
10
10
 
11
11
  def self.server_logger= (log_file_name)
12
12
  @@server_logger = log_file_name
@@ -30,62 +30,34 @@ module Packet
30
30
  @result_hash[worker_key.to_sym] = result
31
31
  end
32
32
 
33
- def provide_workers(handler_instance,t_sock)
34
- class << handler_instance
35
- extend Forwardable
36
- attr_accessor :workers,:connection,:reactor, :initialized,:signature
37
- include NbioHelper
38
- include Connection
39
- def ask_worker(*args)
40
- worker_name = args.shift
41
- data_options = *args
42
- worker_name_key = gen_worker_key(worker_name,data_options[:job_key])
43
- data_options[:client_signature] = connection.fileno
44
- reactor.live_workers[worker_name_key].send_request(data_options)
45
- end
46
-
47
- def_delegators(:@reactor, :start_server, :connect, :add_periodic_timer, \
48
- :add_timer, :cancel_timer,:reconnect, :start_worker,:delete_worker)
49
-
50
- end
51
- handler_instance.workers = @live_workers
52
- handler_instance.connection = t_sock
53
- handler_instance.reactor = self
54
- end
55
-
56
- # FIXME: right now, each worker is tied to its connection and this can be problematic
57
- # what if a worker wants to return results in a async manner
58
33
  def handle_internal_messages(t_sock)
59
34
  sock_fd = t_sock.fileno
60
35
  worker_instance = @live_workers[sock_fd]
61
36
  begin
62
37
  raw_data = read_data(t_sock)
63
- # t_data = Marshal.load(raw_data)
64
38
  worker_instance.receive_data(raw_data) if worker_instance.respond_to?(:receive_data)
65
39
  rescue DisconnectError => sock_error
40
+ worker_instance.receive_data(sock_error.data) if worker_instance.respond_to?(:receive_data)
66
41
  remove_worker(t_sock)
67
42
  end
68
43
  end
69
-
44
+
70
45
 
71
46
  def remove_worker(t_sock)
72
47
  @live_workers.delete(t_sock.fileno)
73
48
  read_ios.delete(t_sock)
74
49
  end
75
-
50
+
76
51
  def delete_worker(worker_options = {})
77
52
  worker_name = worker_options[:worker]
78
- worker_name_key = gen_worker_key(worker_name,worker_options[:job_key])
53
+ worker_name_key = gen_worker_key(worker_name,worker_options[:worker_key])
79
54
  worker_options[:method] = :exit
80
55
  @live_workers[worker_name_key].send_request(worker_options)
81
56
  end
82
57
 
83
58
  def load_workers
84
- if defined?(WORKER_ROOT)
85
- worker_root = WORKER_ROOT
86
- else
87
- worker_root = "#{PACKET_APP}/worker"
88
- end
59
+ worker_root = defined?(WORKER_ROOT) ? WORKER_ROOT : "#{PACKET_APP}/worker"
60
+
89
61
  t_workers = Dir["#{worker_root}/**/*.rb"]
90
62
  return if t_workers.empty?
91
63
  t_workers.each do |b_worker|
@@ -99,7 +71,7 @@ module Packet
99
71
 
100
72
  def start_worker(worker_options = { })
101
73
  worker_name = worker_options[:worker].to_s
102
- worker_name_key = gen_worker_key(worker_name,worker_options[:job_key])
74
+ worker_name_key = gen_worker_key(worker_name,worker_options[:worker_key])
103
75
  return if @live_workers[worker_name_key]
104
76
  worker_options.delete(:worker)
105
77
  begin
@@ -107,15 +79,17 @@ module Packet
107
79
  worker_klass = Object.const_get(packet_classify(worker_name))
108
80
  fork_and_load(worker_klass,worker_options)
109
81
  rescue LoadError
110
- puts "no such worker #{worker_name}"
111
- rescue MissingSourceFile
112
- puts "no such worker #{worker_name}"
82
+ puts "no such worker #{worker_name}"
113
83
  return
114
84
  end
115
85
  end
116
86
 
117
- # method forks given worker file in a new process
118
- # method should use job_key if provided in options hash.
87
+ def enable_nonblock io
88
+ f = io.fcntl(Fcntl::F_GETFL,0)
89
+ io.fcntl(Fcntl::F_SETFL,Fcntl::O_NONBLOCK | f)
90
+ end
91
+
92
+ # method should use worker_key if provided in options hash.
119
93
  def fork_and_load(worker_klass,worker_options = { })
120
94
  t_worker_name = worker_klass.worker_name
121
95
  worker_pimp = worker_klass.worker_proxy.to_s
@@ -124,18 +98,20 @@ module Packet
124
98
  master_read_end,worker_write_end = UNIXSocket.pair(Socket::SOCK_STREAM)
125
99
  # socket to which master process is going to write
126
100
  worker_read_end,master_write_end = UNIXSocket.pair(Socket::SOCK_STREAM)
127
- # worker_read_fd,master_write_fd = UNIXSocket.pair
128
101
 
129
- if((pid = fork()).nil?)
130
- $0 = "ruby #{worker_klass.worker_name}"
131
- [master_write_end,master_read_end].each { |x| x.close }
102
+ option_dump = Marshal.dump(worker_options)
103
+ option_dump_length = option_dump.length
104
+ master_write_end.write(option_dump)
132
105
 
133
- worker_klass.start_worker(:write_end => worker_write_end,:read_end => worker_read_end,\
134
- :options => worker_options)
106
+ if(!(pid = fork))
107
+ [master_write_end,master_read_end].each { |x| x.close }
108
+ [worker_read_end,worker_write_end].each { |x| enable_nonblock(x) }
109
+ exec form_cmd_line(worker_read_end.fileno,worker_write_end.fileno,t_worker_name,option_dump_length)
135
110
  end
136
111
  Process.detach(pid)
112
+ [master_read_end,master_write_end].each { |x| enable_nonblock(x) }
137
113
 
138
- worker_name_key = gen_worker_key(t_worker_name,worker_options[:job_key])
114
+ worker_name_key = gen_worker_key(t_worker_name,worker_options[:worker_key])
139
115
 
140
116
  if worker_pimp && !worker_pimp.empty?
141
117
  require worker_pimp
@@ -152,5 +128,12 @@ module Packet
152
128
  worker_write_end.close
153
129
  read_ios << master_read_end
154
130
  end # end of fork_and_load method
131
+
132
+ def form_cmd_line *args
133
+ min_string = "packet_worker_runner #{args[0]}:#{args[1]}:#{args[2]}:#{args[3]}"
134
+ min_string << ":#{WORKER_ROOT}" if defined? WORKER_ROOT
135
+ min_string << ":#{WORKER_LOAD_ENV}" if defined? WORKER_LOAD_ENV
136
+ min_string
137
+ end
155
138
  end # end of Reactor class
156
139
  end # end of Packet module
@@ -10,7 +10,7 @@ class Packet::MetaPimp < Packet::Pimp
10
10
  @worker_status = nil
11
11
  @worker_result = nil
12
12
  @worker_key = nil
13
- @tokenizer = BinParser.new
13
+ @tokenizer = Packet::BinParser.new
14
14
  end
15
15
 
16
16
  # will be invoked whenever there is a response from the worker
@@ -44,7 +44,7 @@ class Packet::MetaPimp < Packet::Pimp
44
44
  end
45
45
 
46
46
  def process_request(data_options = {})
47
- if requested_worker = data_options[:requested_worker]
47
+ if((requested_worker = data_options[:requested_worker]) && (reactor.live_workers[requested_worker]))
48
48
  reactor.live_workers[requested_worker].send_request(data_options)
49
49
  end
50
50
  end
@@ -59,7 +59,7 @@ class Packet::MetaPimp < Packet::Pimp
59
59
  end
60
60
  elsif client_signature = data_options[:client_signature]
61
61
  begin
62
- reactor.connections[client_signature].instance.worker_receive(data_options)
62
+ reactor.connections[client_signature][:instance].worker_receive(data_options)
63
63
  rescue
64
64
  end
65
65
  end
@@ -5,16 +5,16 @@ module Packet
5
5
  return word_parts.map { |x| x.capitalize}.join
6
6
  end
7
7
 
8
- def gen_worker_key(worker_name,job_key = nil)
9
- return worker_name if job_key.nil?
10
- return "#{worker_name}_#{job_key}".to_sym
8
+ def gen_worker_key(worker_name,worker_key = nil)
9
+ return worker_name if worker_key.nil?
10
+ return "#{worker_name}_#{worker_key}".to_sym
11
11
  end
12
12
 
13
13
  def read_data(t_sock)
14
14
  sock_data = []
15
15
  begin
16
- while(t_data = t_sock.recv_nonblock((16*1024)-1))
17
- raise DisconnectError.new(t_sock,sock_data.join) if t_data.empty?
16
+ while(t_data = t_sock.read_nonblock((16*1024)-1))
17
+ #raise DisconnectError.new(t_sock,sock_data.join) if t_data.empty?
18
18
  sock_data << t_data
19
19
  end
20
20
  rescue Errno::EAGAIN
@@ -45,22 +45,31 @@ module Packet
45
45
  raise DisconnectError.new(p_sock)
46
46
  end
47
47
  end
48
-
48
+
49
49
  # write the data in socket buffer and schedule the thing
50
50
  def write_and_schedule sock
51
51
  outbound_data.each_with_index do |t_data,index|
52
52
  leftover = write_once(t_data,sock)
53
53
  if leftover.empty?
54
- outbound_data.delete_at(index)
54
+ outbound_data[index] = nil
55
55
  else
56
56
  outbound_data[index] = leftover
57
- reactor.schedule_write(sock)
57
+ reactor.schedule_write(sock,self)
58
58
  break
59
59
  end
60
60
  end
61
+ outbound_data.compact!
61
62
  reactor.cancel_write(sock) if outbound_data.empty?
62
63
  end
63
64
 
65
+ # returns Marshal dump of the specified object
66
+ def object_dump p_data
67
+ object_dump = Marshal.dump(p_data)
68
+ dump_length = object_dump.length.to_s
69
+ length_str = dump_length.rjust(9,'0')
70
+ final_data = length_str + object_dump
71
+ end
72
+
64
73
  # method dumps the object in a protocol format which can be easily picked by a recursive descent parser
65
74
  def dump_object(p_data,p_sock)
66
75
  object_dump = Marshal.dump(p_data)
@@ -68,8 +77,8 @@ module Packet
68
77
  length_str = dump_length.rjust(9,'0')
69
78
  final_data = length_str + object_dump
70
79
  outbound_data << final_data
71
- begin
72
- write_and_schedule(p_sock)
80
+ begin
81
+ write_and_schedule(p_sock)
73
82
  rescue DisconnectError => sock
74
83
  close_connection(sock)
75
84
  end
@@ -1,69 +1,75 @@
1
- class BinParser
2
- def initialize
3
- @size = 0
4
- @data = []
5
- # 0 => reading length
6
- # 1 => reading actual data
7
- @parser_state = 0
8
- @length_string = ""
9
- @numeric_length = 0
10
- end
1
+ module Packet
2
+ class BinParser
3
+ attr_accessor :data,:numeric_length,:length_string,:remaining
4
+ attr_accessor :parser_state
5
+ def initialize
6
+ @size = 0
7
+ @data = []
8
+ @remaining = ""
9
+ # 0 => reading length
10
+ # 1 => reading actual data
11
+ @parser_state = 0
12
+ @length_string = ""
13
+ @numeric_length = 0
14
+ end
11
15
 
12
- def extract new_data, &block
13
- extracter_block = block
14
- if @parser_state == 0
15
- length_to_read = 9 - @length_string.length
16
- len_str,remaining = new_data.unpack("a#{length_to_read}a*")
17
- if len_str.length < length_to_read
18
- @length_string << len_str
19
- return
20
- else
21
- @length_string << len_str
22
- @numeric_length = @length_string.to_i
23
- @parser_state = 1
24
- if remaining.length < @numeric_length
25
- @data << remaining
26
- @numeric_length = @numeric_length - remaining.length
27
- elsif remaining.length == @numeric_length
28
- @data << remaining
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)
38
- @data = []
39
- @parser_state = 0
40
- @length_string = ""
41
- @numeric_length = 0
42
- extract(remaining,&extracter_block)
43
- end
44
- end
45
- elsif @parser_state == 1
46
- pack_data,remaining = new_data.unpack("a#{@numeric_length}a*")
47
- if pack_data.length < @numeric_length
48
- @data << pack_data
49
- @numeric_length = @numeric_length - pack_data.length
50
- elsif pack_data.length == @numeric_length
51
- @data << pack_data
52
- extracter_block.call(@data.join)
53
- @data = []
54
- @parser_state = 0
55
- @length_string = ""
56
- @numeric_length = 0
57
- else
58
- @data << pack_data
59
- extracter_block.call(@data.join)
60
- @data = []
61
- @parser_state = 0
62
- @length_string = ""
63
- @numeric_length = 0
64
- extract(remaining,&extracter_block)
65
- end
16
+ def reset
17
+ @data = []
18
+ @parser_state = 0
19
+ @length_string = ""
20
+ @numeric_length = 0
66
21
  end
67
- end
68
- end
22
+
23
+ def extract new_data
24
+ remaining = new_data
25
+
26
+ loop do
27
+ if @parser_state == 0
28
+ length_to_read = 9 - @length_string.length
29
+ len_str,remaining = remaining.unpack("a#{length_to_read}a*")
30
+ break if len_str !~ /^\d+$/
31
+ if len_str.length < length_to_read
32
+ @length_string << len_str
33
+ break
34
+ else
35
+ @length_string << len_str
36
+ @numeric_length = @length_string.to_i
37
+ @parser_state = 1
38
+ if remaining.length < @numeric_length
39
+ @data << remaining
40
+ @numeric_length = @numeric_length - remaining.length
41
+ break
42
+ elsif remaining.length == @numeric_length
43
+ @data << remaining
44
+ yield(@data.join)
45
+ reset
46
+ break
47
+ else
48
+ pack_data,remaining = remaining.unpack("a#{@numeric_length}a*")
49
+ @data << pack_data
50
+ yield(@data.join)
51
+ reset
52
+ end
53
+ end
54
+ elsif @parser_state == 1
55
+ pack_data,remaining = remaining.unpack("a#{@numeric_length}a*")
56
+ if pack_data.length < @numeric_length
57
+ @data << pack_data
58
+ @numeric_length = @numeric_length - pack_data.length
59
+ break
60
+ elsif pack_data.length == @numeric_length
61
+ @data << pack_data
62
+ yield(@data.join)
63
+ reset
64
+ break
65
+ else
66
+ @data << pack_data
67
+ yield(@data.join)
68
+ reset
69
+ end
70
+ end # end of beginning if condition
71
+ end # end of loop do
72
+ end # end of extract method
73
+ end # end of BinParser class
74
+ end # end of packet module
69
75
 
@@ -8,7 +8,6 @@ module Packet
8
8
  attr_accessor :fd_write_end
9
9
  attr_accessor :workers, :reactor,:outbound_data
10
10
 
11
-
12
11
  def initialize(lifeline_socket,worker_pid,p_reactor)
13
12
  @lifeline = lifeline_socket
14
13
  @pid = worker_pid
@@ -7,13 +7,13 @@ module Packet
7
7
  iattr_accessor :no_auto_load
8
8
 
9
9
  attr_accessor :worker_started, :worker_options
10
- after_connection :provide_workers
11
10
 
12
11
  # method initializes the eventloop for the worker
13
12
  def self.start_worker(messengers = {})
14
13
  # @fd_reader = args.shift if args.length > 2
15
14
  @msg_writer = messengers[:write_end]
16
15
  @msg_reader = messengers[:read_end]
16
+
17
17
  t_instance = new
18
18
  t_instance.worker_options = messengers[:options]
19
19
  t_instance.worker_init if t_instance.respond_to?(:worker_init)
@@ -21,6 +21,13 @@ module Packet
21
21
  t_instance
22
22
  end
23
23
 
24
+ # copy the inherited attribute in class thats inheriting this class
25
+ def self.inherited(subklass)
26
+ subklass.send(:"connection_callbacks=",connection_callbacks)
27
+ end
28
+
29
+ def self.is_worker?; true; end
30
+
24
31
  def initialize
25
32
  super
26
33
  @read_ios << msg_reader
@@ -43,8 +50,13 @@ module Packet
43
50
 
44
51
  # method handles internal requests from internal sockets
45
52
  def handle_internal_messages(t_sock)
46
- t_data = read_data(t_sock)
47
- receive_internal_data(t_data)
53
+ begin
54
+ t_data = read_data(t_sock)
55
+ receive_internal_data(t_data)
56
+ rescue DisconnectError => sock_error
57
+ # Means, when there is an error from sockets from which we are reading better just terminate
58
+ terminate_me()
59
+ end
48
60
  end
49
61
 
50
62
  def receive_internal_data data
@@ -54,21 +66,6 @@ module Packet
54
66
  end
55
67
  end
56
68
 
57
- # FIXME: this method is being duplicated between packet and worker classes, may be its a
58
- # good idea to merge them.
59
- def provide_workers(handler_instance,connection)
60
- class << handler_instance
61
- extend Forwardable
62
- attr_accessor :worker, :connection, :reactor, :initialized, :signature
63
- include NbioHelper
64
- include Connection
65
- def_delegators :@reactor, :start_server, :connect, :add_periodic_timer, :add_timer, :cancel_timer,:reconnect
66
- end
67
- handler_instance.connection = connection
68
- handler_instance.worker = self
69
- handler_instance.reactor = self
70
- end
71
-
72
69
  def log log_data
73
70
  send_data(:requested_worker => :log_worker,:data => log_data,:type => :request)
74
71
  end
@@ -91,3 +88,4 @@ module Packet
91
88
  end # end of class#Worker
92
89
  end
93
90
 
91
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hemant Kumar
@@ -9,14 +9,14 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-28 00:00:00 +05:30
12
+ date: 2008-07-12 00:00:00 +05:30
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
16
  description: Packet, A Pure Ruby library for Event Driven Network Programming.
17
17
  email: mail@gnufied.org
18
- executables: []
19
-
18
+ executables:
19
+ - packet_worker_runner
20
20
  extensions: []
21
21
 
22
22
  extra_rdoc_files:
@@ -28,12 +28,10 @@ files:
28
28
  - README
29
29
  - Rakefile
30
30
  - TODO
31
- - spec/test_double_keyed_hash.rb
32
- - spec/spec_helper.rb
33
- - spec/test_packet_core.rb
34
31
  - lib/packet
35
32
  - lib/packet/disconnect_error.rb
36
33
  - lib/packet/packet_pimp.rb
34
+ - lib/packet/packet_invalid_worker.rb
37
35
  - lib/packet/packet_connection.rb
38
36
  - lib/packet/packet_guid.rb
39
37
  - lib/packet/double_keyed_hash.rb
@@ -50,7 +48,6 @@ files:
50
48
  - lib/packet/packet_event.rb
51
49
  - lib/packet/packet_nbio.rb
52
50
  - lib/packet.rb
53
- - lib/packet.rbc
54
51
  - lib/packet_mongrel.rb
55
52
  - examples/concurrent_thread.c
56
53
  - examples/sample_server.rb
@@ -59,7 +56,6 @@ files:
59
56
  - examples/persistent_print.rb
60
57
  - examples/use_stuff.rb
61
58
  - examples/extconf.h
62
- - examples/netbeans.jpg
63
59
  - examples/asteroid.c
64
60
  - examples/extconf.rb
65
61
  has_rdoc: true
@@ -84,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
80
  requirements: []
85
81
 
86
82
  rubyforge_project:
87
- rubygems_version: 0.9.5
83
+ rubygems_version: 1.2.0
88
84
  signing_key:
89
85
  specification_version: 2
90
86
  summary: Packet, A Pure Ruby library for Event Driven Network Programming.
Binary file
Binary file
@@ -1,10 +0,0 @@
1
- PACKET_APP = File.expand_path(File.join(File.dirname(__FILE__) + "/.."))
2
- ["lib"].each { |x| $LOAD_PATH.unshift(EVAL_APP_ROOT + "/#{x}")}
3
- require "packet"
4
- require "rubygems"
5
- require "test/spec"
6
- require "mocha"
7
-
8
-
9
-
10
-
@@ -1,14 +0,0 @@
1
- require File.join(File.dirname(__FILE__) + "/spec_helper")
2
- context "Double Keyed Hash in general" do
3
- xspecify "should allow muliple keys while storing the value in hash" do
4
- end
5
-
6
- xspecify "should return correct value when either of the keys is used" do
7
- end
8
-
9
- xspecify "should return nil if nither of keys match" do
10
- end
11
-
12
- xspecify "should allow deletion of value from hash based on either of keys" do
13
- end
14
- end
@@ -1,39 +0,0 @@
1
- require File.join(File.dirname(__FILE__) + "/spec_helper")
2
-
3
- context "Packet Core in general when mixed inside a class" do
4
- xspecify "allow the class to act as a reactor" do
5
- end
6
-
7
- xspecify "should start a server on specified port" do
8
- end
9
-
10
- xspecify "should let clients connect to the server" do
11
- end
12
-
13
- xspecify "should be able to connect to external servers" do
14
- end
15
-
16
- xspecify "should be able to read data from clients when socket is ready" do
17
- end
18
-
19
- xspecify "should be able to write data to clients when socket is ready for write" do
20
- end
21
-
22
- xspecify "should invoke receive_data method data is receieved from clients" do
23
- end
24
-
25
- xspecify "should invoke post_init when client connects" do
26
- end
27
-
28
- xspecify "should invoke unbind when a client disconnects" do
29
- end
30
-
31
- xspecify "should invoke connection_completed when connection to external server is connected." do
32
- end
33
-
34
- xspecify "should check for ready timers on each iteration" do
35
- end
36
-
37
- xspecify "should run proper timer on each iteration." do
38
- end
39
- end