packet 0.1.5 → 0.1.7

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/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