Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

merge changes from fork exec branch

  • Loading branch information...
commit 3f16f7bcc3cca86d12c11d6bacef245a64ac07e7 2 parents d713729 + 67f8970
@gnufied authored
Showing with 597 additions and 375 deletions.
  1. +6 −1 .gitignore
  2. +0 −1  README
  3. +1 −27 Rakefile
  4. +4 −0 bin/echo_server.rb
  5. +5 −5 bin/packet_worker_runner
  6. +12 −8 bin/runner.rb
  7. BIN  bin/runner.rbc
  8. +2 −0  lib/packet.rb
  9. +33 −24 lib/packet/double_keyed_hash.rb
  10. +1 −0  lib/packet/packet_callback.rb
  11. +57 −6 lib/packet/packet_connection.rb
  12. +37 −16 lib/packet/packet_core.rb
  13. +1 −1  lib/packet/packet_event.rb
  14. +1 −0  lib/packet/packet_guid.rb
  15. +15 −43 lib/packet/packet_helper.rb
  16. +3 −3 lib/packet/packet_invalid_worker.rb
  17. +5 −34 lib/packet/packet_master.rb
  18. +1 −1  lib/packet/packet_meta_pimp.rb
  19. +3 −3 lib/packet/packet_nbio.rb
  20. +59 −55 lib/packet/packet_parser.rb
  21. +12 −18 lib/packet/packet_worker.rb
  22. +0 −10 spec/spec_helper.rb
  23. +0 −14 spec/test_double_keyed_hash.rb
  24. +0 −39 spec/test_packet_core.rb
  25. +40 −0 tasks/git.rake
  26. +12 −0 tasks/rdoc.rake
  27. +0 −46 tests/echo_server.rb
  28. +0 −2  tests/message_pass.rb
  29. +167 −0 tests/packet_core_test.rb
  30. +5 −0 tests/packet_master_test.rb
  31. +100 −0 tests/packet_parser_test.rb
  32. +0 −5 tests/runner.rb
  33. +8 −0 tests/spec_helper.rb
  34. +0 −5 tests/test_for_next_turn.rb
  35. +0 −2  tests/worker_comm.rb
  36. +7 −6 worker/no_proxy_worker.rb
View
7 .gitignore
@@ -1,4 +1,9 @@
pkg
extras/foo.rb
-hello.patch
+coverage
+TAGS
+bin/*.rbc
+lib/*.rbc
+lib/packet/*.rbc
+worker/*.rbc
View
1  README
@@ -252,4 +252,3 @@ end
-
View
28 Rakefile
@@ -17,6 +17,7 @@ $LOAD_PATH.unshift __DIR__+'/lib'
require 'packet'
CLEAN.include ['**/.*.sw?', '*.gem', '.config','*.rbc']
+Dir["tasks/**/*.rake"].each { |rake| load rake }
@windows = (PLATFORM =~ /win32/)
@@ -30,17 +31,6 @@ task :default => [:package]
task :doc => [:rdoc]
-
-Rake::RDocTask.new do |rdoc|
- files = ['README', 'MIT-LICENSE', 'CHANGELOG',
- 'lib/**/*.rb']
- rdoc.rdoc_files.add(files)
- rdoc.main = 'README'
- rdoc.title = 'Packet Docs'
- rdoc.rdoc_dir = 'doc/rdoc'
- rdoc.options << '--line-numbers' << '--inline-source'
-end
-
spec = Gem::Specification.new do |s|
s.name = NAME
s.version = Packet::VERSION
@@ -75,16 +65,6 @@ task :uninstall => [:clean] do
sh %{#{SUDO} gem uninstall #{NAME}}
end
-##############################################################################
-# SVN
-##############################################################################
-
-desc "Add new files to subversion"
-task :svn_add do
- system "svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add"
-end
-
-
desc "Converts a YAML file into a test/spec skeleton"
task :yaml_to_spec do
require 'yaml'
@@ -94,9 +74,3 @@ task :yaml_to_spec do
}.strip
end
-namespace :git do
- desc "Push changes to central git repo"
- task :push do
- sh("git push origin master")
- end
-end
View
4 bin/echo_server.rb
@@ -12,6 +12,10 @@ def receive_data(p_data)
end
def connection_completed
+ add_timer(3) { say_hello }
+ end
+ def say_hello
+ send_data("Hello \n")
end
def post_init
View
10 bin/packet_worker_runner
@@ -8,13 +8,12 @@ module Packet
class WorkerRunner
include Packet::NbioHelper
def initialize args
-
cmd_args = args.split(':')
worker_name = cmd_args[2]
initial_arg_data_length = cmd_args[3].to_i
@worker_root = cmd_args[4]
@worker_load_env = cmd_args[5]
- require @worker_load_env if @worker_load_env
+
@worker_read_fd = UNIXSocket.for_fd(cmd_args[0].to_i)
@@ -22,7 +21,8 @@ module Packet
initial_arg_data = @worker_read_fd.read(initial_arg_data_length)
- @worker_options = Marshal.load(initial_arg_data)
+ Packet::WorkerRunner.const_set(:WORKER_OPTIONS,Marshal.load(initial_arg_data))
+ require @worker_load_env if @worker_load_env && !@worker_load_env.empty?
load_worker worker_name
end
@@ -30,12 +30,12 @@ module Packet
if @worker_root && (File.file? "#{@worker_root}/#{worker_name}.rb")
require "#{@worker_root}/#{worker_name}"
worker_klass = Object.const_get(packet_classify(worker_name))
- worker_klass.start_worker(:read_end => @worker_read_fd,:write_end => @worker_write_fd,:options => @worker_options)
+ worker_klass.start_worker(:read_end => @worker_read_fd,:write_end => @worker_write_fd,:options => WORKER_OPTIONS)
else
require worker_name
worker_klass = Object.const_get(packet_classify(worker_name))
if worker_klass.is_worker?
- worker_klass.start_worker(:read_end => @worker_read_fd,:write_end => @worker_write_fd,:options => @worker_options)
+ worker_klass.start_worker(:read_end => @worker_read_fd,:write_end => @worker_write_fd,:options => WORKER_OPTIONS)
else
raise Packet::InvalidWorker.new(worker_name)
end
View
20 bin/runner.rb
@@ -4,26 +4,27 @@
["extras","bin","worker","lib"].each { |x| $LOAD_PATH.unshift(EVAL_APP_ROOT + "/#{x}")}
WORKER_ROOT = EVAL_APP_ROOT + "/worker"
-WORKER_LOAD_ENV = EVAL_APP_ROOT + "/extras/foo"
+#WORKER_LOAD_ENV = EVAL_APP_ROOT + "/extras/foo"
require "packet"
#require "buftok"
class Foo
def receive_data p_data
+ p p_data
# @tokenizer.extract(p_data).each do |t_data|
# send_data(p_data)
# end
- @tokenizer.extract(p_data) do |complete_message|
- client_data = Marshal.load(complete_message)
- #p "Receieved message in server : #{client_data.join.size}"
- #ask_worker(:no_proxy_worker,:data => client_data,:type => :request)
- send_object(client_data)
- end
+# @tokenizer.extract(p_data) do |complete_message|
+# client_data = Marshal.load(complete_message)
+# #p "Receieved message in server : #{client_data.join.size}"
+# #ask_worker(:no_proxy_worker,:data => client_data,:type => :request)
+# send_object(client_data)
+# end
# data_callback = Packet::Callback.new { |data| show_result(data) }
# workers[:no_proxy_worker].send_request(:data => p_data,:callback => data_callback)
- # ask_worker(:no_proxy_worker,:data => p_data, :type => :request)
+ ask_worker(:no_proxy_worker,:data => p_data, :type => :request)
#p reactor.live_workers
# ask_worker(:dynamic_worker,:job_key => :hello_world, :data => p_data, :type => :request)
end
@@ -56,6 +57,9 @@ def post_init
def wow
#puts "Wow"
end
+ def unbind
+ puts "Client disconnected"
+ end
end
Packet::Reactor.run do |t_reactor|
View
BIN  bin/runner.rbc
Binary file not shown
View
2  lib/packet.rb
@@ -7,8 +7,10 @@
require "ostruct"
require "thread"
require "fcntl"
+#require "enumerable"
require "packet/packet_parser"
+require "packet/packet_invalid_worker"
require "packet/packet_guid"
require "packet/packet_helper"
require "packet/double_keyed_hash"
View
57 lib/packet/double_keyed_hash.rb
@@ -1,31 +1,40 @@
-class DoubleKeyedHash
- attr_accessor :internal_hash
- def initialize
- @keys1 = {}
- @internal_hash = {}
- end
+module Packet
+ class DoubleKeyedHash
+# include Enumerable
+ attr_accessor :internal_hash
+ def initialize
+ @keys1 = {}
+ @internal_hash = {}
+ end
- def []=(key1,key2,value)
- @keys1[key2] = key1
- @internal_hash[key1] = value
- end
+ def []=(key1,key2,value)
+ @keys1[key2] = key1
+ @internal_hash[key1] = value
+ end
- def [] key
- @internal_hash[key] || @internal_hash[@keys1[key]]
- end
+ def [] key
+ @internal_hash[key] || @internal_hash[@keys1[key]]
+ end
- def delete(key)
- t_key = @keys1[key]
- if t_key
- @keys1.delete(key)
- @internal_hash.delete(t_key)
- else
- @keys1.delete_if { |key,value| value == key }
- @internal_hash.delete(key)
+ def delete(key)
+ t_key = @keys1[key]
+ if t_key
+ @keys1.delete(key)
+ @internal_hash.delete(t_key)
+ else
+ @keys1.delete_if { |key,value| value == key }
+ @internal_hash.delete(key)
+ end
+ end
+
+ def length
+ @internal_hash.keys.length
end
- end
- def each
- @internal_hash.each { |key,value| yield(key,value)}
+ def each
+ @internal_hash.each { |key,value| yield(key,value)}
+ end
end
end
+
+
View
1  lib/packet/packet_callback.rb
@@ -12,3 +12,4 @@ def invoke(*args)
end
end
end
+
View
63 lib/packet/packet_connection.rb
@@ -1,9 +1,14 @@
-# FIMXE: following class must modify the fd_watchlist thats being monitored by
-# main eventloop.
-
module Packet
module Connection
attr_accessor :outbound_data,:connection_live
+ attr_accessor :worker,:connection,:reactor, :initialized,:signature
+ include NbioHelper
+
+ def unbind; end
+ def connection_completed; end
+ def post_init; end
+ def receive_data data; end
+
def send_data p_data
@outbound_data << p_data
begin
@@ -17,23 +22,69 @@ def invoke_init
@initialized = true
@connection_live = true
@outbound_data = []
- post_init if respond_to?(:post_init)
+ post_init
end
def close_connection(sock = nil)
- unbind if respond_to?(:unbind)
+ unbind
reactor.cancel_write(connection)
reactor.remove_connection(connection)
end
def close_connection_after_writing
- connection.flush
+ connection.flush unless connection.closed?
close_connection
end
+ def get_peername
+ connection.getpeername
+ end
+
def send_object p_object
dump_object(p_object,connection)
end
+ def ask_worker(*args)
+ worker_name = args.shift
+ data_options = *args
+ data_options[:client_signature] = connection.fileno
+ t_worker = reactor.live_workers[worker_name]
+ raise Packet::InvalidWorker.new("Invalid worker with name #{worker_name} and key #{data_options[:data][:worker_key]}") unless t_worker
+ t_worker.send_request(data_options)
+ end
+ def start_server ip,port,t_module,&block
+ reactor.start_server(ip,port,t_module,block)
+ end
+
+ def connect ip,port,t_module,&block
+ reactor.connect(ip,port,t_module,block)
+ end
+
+ def add_periodic_timer interval, &block
+ reactor.add_periodic_timer(interval,block)
+ end
+
+ def add_timer(t_time,&block)
+ reactor.add_timer(t_time,block)
+ end
+
+ def cancel_timer(t_timer)
+ reactor.cancel_timer(t_timer)
+ end
+
+ def reconnect server,port,handler
+ reactor.reconnect(server,port,handler)
+ end
+
+ def start_worker(worker_options = {})
+ reactor.start_worker(worker_options)
+ end
+
+ def delete_worker worker_options = {}
+ reactor.delete_worker(worker_options)
+ end
+
end # end of class Connection
end # end of module Packet
+
+
View
53 lib/packet/packet_core.rb
@@ -4,9 +4,8 @@ module Core
def self.included(base_klass)
base_klass.extend(ClassMethods)
base_klass.instance_eval do
- @@connection_callbacks ||= {}
-
- cattr_accessor :connection_callbacks
+ iattr_accessor :connection_callbacks
+ inheritable_attribute(:connection_callbacks,:default => {})
attr_accessor :read_ios, :write_ios, :listen_sockets
attr_accessor :connection_completion_awaited,:write_scheduled
attr_accessor :connections, :windows_flag
@@ -22,6 +21,7 @@ def after_connection p_method
connection_callbacks[:after_connection] << p_method
end
+ # FIXME: following callbacks hasn't been tested and not usable.
def after_unbind p_method
connection_callbacks[:after_unbind] ||= []
connection_callbacks[:after_unbind] << p_method
@@ -103,6 +103,7 @@ def remove_connection(t_sock)
connections.delete(t_sock.fileno)
t_sock.close
rescue
+ puts "#{$!.message}"
end
end
@@ -113,7 +114,17 @@ def next_turn &block
# method opens a socket for listening
def start_server(ip,port,t_module,&block)
BasicSocket.do_not_reverse_lookup = true
- t_socket = TCPServer.new(ip,port.to_i)
+ # Comment TCPServer for the time being
+ #t_socket = TCPServer.new(ip,port.to_i)
+ #t_socket = TCPSocket.
+
+ t_socket = Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)
+ t_socket.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR,true)
+ sockaddr = Socket.sockaddr_in(port.to_i,ip)
+ t_socket.bind(sockaddr)
+ t_socket.listen(50)
+ t_socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
+
# t_socket.setsockopt(*@tcp_defer_accept_opts) rescue nil
listen_sockets[t_socket.fileno] = { :socket => t_socket,:block => block,:module => t_module }
@read_ios << t_socket
@@ -145,7 +156,7 @@ def schedule_write(t_sock,internal_instance = nil)
internal_scheduled_write[t_sock.fileno] ||= internal_instance
elsif write_scheduled[fileno].nil? && !(t_sock.is_a?(UNIXSocket))
write_ios << t_sock
- write_scheduled[fileno] ||= connections[fileno].instance
+ write_scheduled[fileno] ||= connections[fileno][:instance]
end
end
@@ -177,7 +188,7 @@ def handle_write_event(p_ready_fds)
def handle_read_event(p_ready_fds)
ready_fds = p_ready_fds.flatten.compact
ready_fds.each do |t_sock|
- if(unix? && t_sock.is_a?(UNIXSocket))
+ if(t_sock.is_a?(UNIXSocket))
handle_internal_messages(t_sock)
else
handle_external_messages(t_sock)
@@ -211,12 +222,12 @@ def handle_external_messages(t_sock)
end
def read_external_socket(t_sock)
- handler_instance = connections[t_sock.fileno].instance
+ handler_instance = connections[t_sock.fileno][:instance]
begin
t_data = read_data(t_sock)
- handler_instance.receive_data(t_data) if handler_instance.respond_to?(:receive_data)
+ handler_instance.receive_data(t_data)
rescue DisconnectError => sock_error
- handler_instance.receive_data(sock_error.data) if handler_instance.respond_to?(:receive_data)
+ handler_instance.receive_data(sock_error.data) unless (sock_error.data).empty?
handler_instance.close_connection
end
end
@@ -295,28 +306,38 @@ def initialize_handler(p_module)
return p_module if(!p_module.is_a?(Class) and !p_module.is_a?(Module))
handler =
if(p_module and p_module.is_a?(Class))
- p_module
+ p_module and p_module.send(:include,Connection)
else
- Class.new(Connection) { p_module and include p_module }
+ Class.new { include Connection; include p_module; }
end
return handler.new
end
def decorate_handler(t_socket,actually_connected,sock_addr,t_module,&block)
handler_instance = initialize_handler(t_module)
- connection_callbacks[:after_connection].each { |t_callback| self.send(t_callback,handler_instance,t_socket)}
+ after_connection_callbacks = connection_callbacks ? connection_callbacks[:after_connection] : nil
+ after_connection_callbacks && after_connection_callbacks.each { |t_callback| self.send(t_callback,handler_instance,t_socket)}
+ handler_instance.worker = self
+ handler_instance.connection = t_socket
+ handler_instance.reactor = self
handler_instance.invoke_init unless handler_instance.initialized
unless actually_connected
- handler_instance.unbind if handler_instance.respond_to?(:unbind)
+ handler_instance.unbind
return
end
handler_instance.signature = binding_str
- klass = Struct.new(:socket,:instance,:signature,:sock_addr)
- connections[t_socket.fileno] = klass.new(t_socket,handler_instance,handler_instance.signature,sock_addr)
+ # FIXME: An Struct is more fashionable, but will have some performance hit, can use a simple hash here
+ # klass = Struct.new(:socket,:instance,:signature,:sock_addr)
+ connection_data = { :socket => t_socket,:instance => handler_instance,:signature => binding_str,:sock_addr => sock_addr }
+ connections[t_socket.fileno] = connection_data
+# connections[t_socket.fileno] = klass.new(t_socket,handler_instance,handler_instance.signature,sock_addr)
+
block.call(handler_instance) if block
- handler_instance.connection_completed if handler_instance.respond_to?(:connection_completed)
+ handler_instance.connection_completed #if handler_instance.respond_to?(:connection_completed)
+ handler_instance
end
end # end of module#CommonMethods
end #end of module#Core
end #end of module#Packet
+
View
2  lib/packet/packet_event.rb
@@ -22,4 +22,4 @@ def run
end
end
end
-# WOW
+
View
1  lib/packet/packet_guid.rb
@@ -14,3 +14,4 @@ def self.hexdigest
end
end
end
+
View
58 lib/packet/packet_helper.rb
@@ -23,52 +23,24 @@ def iattr_accessor *args
end
end
end # end of method iattr_accessor
-
- def cattr_reader(*syms)
- syms.flatten.each do |sym|
- next if sym.is_a?(Hash)
- class_eval(<<-EOS, __FILE__, __LINE__)
- unless defined? @@#{sym}
- @@#{sym} = nil
- end
-
- def self.#{sym}
- @@#{sym}
- end
-
- def #{sym}
- @@#{sym}
+
+ def inheritable_attribute *options_args
+ option_hash = options_args.last
+ args = options_args[0..-2]
+ args.each {|attr| instance_variable_set(:"@#{attr}",option_hash[:default] || nil )}
+ metaclass.instance_eval { attr_accessor *args }
+ args.each do |attr|
+ class_eval do
+ define_method(attr) do
+ self.class.send(attr)
+ end
+ define_method("#{attr}=") do |b_value|
+ self.class.send("#{attr}=",b_value)
+ end
end
- EOS
end
end
-
- def cattr_writer(*syms)
- options = syms.last.is_a?(Hash) ? syms.pop : {}
- syms.flatten.each do |sym|
- class_eval(<<-EOS, __FILE__, __LINE__)
- unless defined? @@#{sym}
- @@#{sym} = nil
- end
-
- def self.#{sym}=(obj)
- @@#{sym} = obj
- end
-
- #{"
- def #{sym}=(obj)
- @@#{sym} = obj
- end
- " unless options[:instance_writer] == false }
- EOS
- end
- end
-
- def cattr_accessor(*syms)
- cattr_reader(*syms)
- cattr_writer(*syms)
- end
- module_function :metaclass,:iattr_accessor, :cattr_writer, :cattr_reader, :cattr_accessor
+ module_function :metaclass,:iattr_accessor,:inheritable_attribute
end # end of module ClassHelpers
end
View
6 lib/packet/packet_invalid_worker.rb
@@ -1,8 +1,8 @@
module Packet
class InvalidWorker < RuntimeError
- attr_accessor :worker_name
- def initialize worker_name
- @worker_name = worker_name
+ attr_accessor :message
+ def initialize message
+ @message = message
end
end
end
View
39 lib/packet/packet_master.rb
@@ -6,7 +6,7 @@ class Reactor
attr_accessor :result_hash
attr_accessor :live_workers
- after_connection :provide_workers
+ #after_connection :provide_workers
def self.server_logger= (log_file_name)
@@server_logger = log_file_name
@@ -30,29 +30,6 @@ def update_result(worker_key,result)
@result_hash[worker_key.to_sym] = result
end
- def provide_workers(handler_instance,t_sock)
- class << handler_instance
- extend Forwardable
- attr_accessor :workers,:connection,:reactor, :initialized,:signature
- include NbioHelper
- include Connection
- def ask_worker(*args)
- worker_name = args.shift
- data_options = *args
- worker_name_key = gen_worker_key(worker_name,data_options[:job_key])
- data_options[:client_signature] = connection.fileno
- reactor.live_workers[worker_name_key].send_request(data_options)
- end
-
- def_delegators(:@reactor, :start_server, :connect, :add_periodic_timer, \
- :add_timer, :cancel_timer,:reconnect, :start_worker,:delete_worker)
-
- end
- handler_instance.workers = @live_workers
- handler_instance.connection = t_sock
- handler_instance.reactor = self
- end
-
def handle_internal_messages(t_sock)
sock_fd = t_sock.fileno
worker_instance = @live_workers[sock_fd]
@@ -73,7 +50,7 @@ def remove_worker(t_sock)
def delete_worker(worker_options = {})
worker_name = worker_options[:worker]
- worker_name_key = gen_worker_key(worker_name,worker_options[:job_key])
+ worker_name_key = gen_worker_key(worker_name,worker_options[:worker_key])
worker_options[:method] = :exit
@live_workers[worker_name_key].send_request(worker_options)
end
@@ -94,7 +71,7 @@ def load_workers
def start_worker(worker_options = { })
worker_name = worker_options[:worker].to_s
- worker_name_key = gen_worker_key(worker_name,worker_options[:job_key])
+ worker_name_key = gen_worker_key(worker_name,worker_options[:worker_key])
return if @live_workers[worker_name_key]
worker_options.delete(:worker)
begin
@@ -112,8 +89,7 @@ def enable_nonblock io
io.fcntl(Fcntl::F_SETFL,Fcntl::O_NONBLOCK | f)
end
-
- # method should use job_key if provided in options hash.
+ # method should use worker_key if provided in options hash.
def fork_and_load(worker_klass,worker_options = { })
t_worker_name = worker_klass.worker_name
worker_pimp = worker_klass.worker_proxy.to_s
@@ -128,19 +104,14 @@ def fork_and_load(worker_klass,worker_options = { })
master_write_end.write(option_dump)
if(!(pid = fork))
- # $0 = "ruby #{worker_klass.worker_name}"
[master_write_end,master_read_end].each { |x| x.close }
-
[worker_read_end,worker_write_end].each { |x| enable_nonblock(x) }
-
-# worker_klass.start_worker(:write_end => worker_write_end,:read_end => worker_read_end,\
-# :options => worker_options)
exec form_cmd_line(worker_read_end.fileno,worker_write_end.fileno,t_worker_name,option_dump_length)
end
Process.detach(pid)
[master_read_end,master_write_end].each { |x| enable_nonblock(x) }
- worker_name_key = gen_worker_key(t_worker_name,worker_options[:job_key])
+ worker_name_key = gen_worker_key(t_worker_name,worker_options[:worker_key])
if worker_pimp && !worker_pimp.empty?
require worker_pimp
View
2  lib/packet/packet_meta_pimp.rb
@@ -59,7 +59,7 @@ def process_response(data_options = {})
end
elsif client_signature = data_options[:client_signature]
begin
- reactor.connections[client_signature].instance.worker_receive(data_options)
+ reactor.connections[client_signature][:instance].worker_receive(data_options)
rescue
end
end
View
6 lib/packet/packet_nbio.rb
@@ -5,9 +5,9 @@ def packet_classify(original_string)
return word_parts.map { |x| x.capitalize}.join
end
- def gen_worker_key(worker_name,job_key = nil)
- return worker_name if job_key.nil?
- return "#{worker_name}_#{job_key}".to_sym
+ def gen_worker_key(worker_name,worker_key = nil)
+ return worker_name if worker_key.nil?
+ return "#{worker_name}_#{worker_key}".to_sym
end
def read_data(t_sock)
View
114 lib/packet/packet_parser.rb
@@ -1,8 +1,11 @@
module Packet
class BinParser
+ attr_accessor :data,:numeric_length,:length_string,:remaining
+ attr_accessor :parser_state
def initialize
@size = 0
@data = []
+ @remaining = ""
# 0 => reading length
# 1 => reading actual data
@parser_state = 0
@@ -10,62 +13,63 @@ def initialize
@numeric_length = 0
end
- def extract new_data, &block
- extracter_block = block
- if @parser_state == 0
- length_to_read = 9 - @length_string.length
- len_str,remaining = new_data.unpack("a#{length_to_read}a*")
- if len_str.length < length_to_read
- @length_string << len_str
- return
- else
- @length_string << len_str
- @numeric_length = @length_string.to_i
- @parser_state = 1
- if remaining.length < @numeric_length
- @data << remaining
- @numeric_length = @numeric_length - remaining.length
- elsif remaining.length == @numeric_length
- @data << remaining
- extracter_block.call(@data.join)
- @data = []
- @parser_state = 0
- @length_string = ""
- @numeric_length = 0
+ def reset
+ @data = []
+ @parser_state = 0
+ @length_string = ""
+ @numeric_length = 0
+ end
+
+ def extract new_data
+ remaining = new_data
+
+ loop do
+ if @parser_state == 0
+ length_to_read = 9 - @length_string.length
+ len_str,remaining = remaining.unpack("a#{length_to_read}a*")
+ break if len_str !~ /^\d+$/
+ if len_str.length < length_to_read
+ @length_string << len_str
+ break
+ else
+ @length_string << len_str
+ @numeric_length = @length_string.to_i
+ @parser_state = 1
+ if remaining.length < @numeric_length
+ @data << remaining
+ @numeric_length = @numeric_length - remaining.length
+ break
+ elsif remaining.length == @numeric_length
+ @data << remaining
+ yield(@data.join)
+ reset
+ break
+ else
+ pack_data,remaining = remaining.unpack("a#{@numeric_length}a*")
+ @data << pack_data
+ yield(@data.join)
+ reset
+ end
+ end
+ elsif @parser_state == 1
+ pack_data,remaining = remaining.unpack("a#{@numeric_length}a*")
+ if pack_data.length < @numeric_length
+ @data << pack_data
+ @numeric_length = @numeric_length - pack_data.length
+ break
+ elsif pack_data.length == @numeric_length
+ @data << pack_data
+ yield(@data.join)
+ reset
+ break
else
- pack_data,remaining = remaining.unpack("a#{@numeric_length}a*")
@data << pack_data
- extracter_block.call(@data.join)
- @data = []
- @parser_state = 0
- @length_string = ""
- @numeric_length = 0
- extract(remaining,&extracter_block)
+ yield(@data.join)
+ reset
end
- end
- elsif @parser_state == 1
- pack_data,remaining = new_data.unpack("a#{@numeric_length}a*")
- if pack_data.length < @numeric_length
- @data << pack_data
- @numeric_length = @numeric_length - pack_data.length
- elsif pack_data.length == @numeric_length
- @data << pack_data
- extracter_block.call(@data.join)
- @data = []
- @parser_state = 0
- @length_string = ""
- @numeric_length = 0
- else
- @data << pack_data
- extracter_block.call(@data.join)
- @data = []
- @parser_state = 0
- @length_string = ""
- @numeric_length = 0
- extract(remaining,&extracter_block)
- end
- end
- end
- end
-end
+ end # end of beginning if condition
+ end # end of loop do
+ end # end of extract method
+ end # end of BinParser class
+end # end of packet module
View
30 lib/packet/packet_worker.rb
@@ -7,7 +7,6 @@ class Worker
iattr_accessor :no_auto_load
attr_accessor :worker_started, :worker_options
- after_connection :provide_workers
# method initializes the eventloop for the worker
def self.start_worker(messengers = {})
@@ -22,6 +21,11 @@ def self.start_worker(messengers = {})
t_instance
end
+ # copy the inherited attribute in class thats inheriting this class
+ def self.inherited(subklass)
+ subklass.send(:"connection_callbacks=",connection_callbacks)
+ end
+
def self.is_worker?; true; end
def initialize
@@ -46,8 +50,13 @@ def send_request(options = {})
# method handles internal requests from internal sockets
def handle_internal_messages(t_sock)
- t_data = read_data(t_sock)
- receive_internal_data(t_data)
+ begin
+ t_data = read_data(t_sock)
+ receive_internal_data(t_data)
+ rescue DisconnectError => sock_error
+ # Means, when there is an error from sockets from which we are reading better just terminate
+ terminate_me()
+ end
end
def receive_internal_data data
@@ -57,21 +66,6 @@ def receive_internal_data data
end
end
- # FIXME: this method is being duplicated between packet and worker classes, may be its a
- # good idea to merge them.
- def provide_workers(handler_instance,connection)
- class << handler_instance
- extend Forwardable
- attr_accessor :worker, :connection, :reactor, :initialized, :signature
- include NbioHelper
- include Connection
- def_delegators :@reactor, :start_server, :connect, :add_periodic_timer, :add_timer, :cancel_timer,:reconnect
- end
- handler_instance.connection = connection
- handler_instance.worker = self
- handler_instance.reactor = self
- end
-
def log log_data
send_data(:requested_worker => :log_worker,:data => log_data,:type => :request)
end
View
10 spec/spec_helper.rb
@@ -1,10 +0,0 @@
-PACKET_APP = File.expand_path(File.join(File.dirname(__FILE__) + "/.."))
-["lib"].each { |x| $LOAD_PATH.unshift(EVAL_APP_ROOT + "/#{x}")}
-require "packet"
-require "rubygems"
-require "test/spec"
-require "mocha"
-
-
-
-
View
14 spec/test_double_keyed_hash.rb
@@ -1,14 +0,0 @@
-require File.join(File.dirname(__FILE__) + "/spec_helper")
-context "Double Keyed Hash in general" do
- xspecify "should allow muliple keys while storing the value in hash" do
- end
-
- xspecify "should return correct value when either of the keys is used" do
- end
-
- xspecify "should return nil if nither of keys match" do
- end
-
- xspecify "should allow deletion of value from hash based on either of keys" do
- end
-end
View
39 spec/test_packet_core.rb
@@ -1,39 +0,0 @@
-require File.join(File.dirname(__FILE__) + "/spec_helper")
-
-context "Packet Core in general when mixed inside a class" do
- xspecify "allow the class to act as a reactor" do
- end
-
- xspecify "should start a server on specified port" do
- end
-
- xspecify "should let clients connect to the server" do
- end
-
- xspecify "should be able to connect to external servers" do
- end
-
- xspecify "should be able to read data from clients when socket is ready" do
- end
-
- xspecify "should be able to write data to clients when socket is ready for write" do
- end
-
- xspecify "should invoke receive_data method data is receieved from clients" do
- end
-
- xspecify "should invoke post_init when client connects" do
- end
-
- xspecify "should invoke unbind when a client disconnects" do
- end
-
- xspecify "should invoke connection_completed when connection to external server is connected." do
- end
-
- xspecify "should check for ready timers on each iteration" do
- end
-
- xspecify "should run proper timer on each iteration." do
- end
-end
View
40 tasks/git.rake
@@ -0,0 +1,40 @@
+namespace :git do
+ def current_branch
+ branches = `git branch`
+ return branches.split("\n").detect {|x| x =~ /^\*/}.split(' ')[1]
+ end
+
+ desc "Push changes to central git repo"
+ task :push do
+ sh("git push origin master")
+ end
+
+ desc "update master branch"
+ task :up do
+ t_branch = current_branch
+ sh("git checkout master")
+ sh("git pull")
+ sh("git checkout #{t_branch}")
+ end
+
+ desc "rebase current branch to master"
+ task :rebase => [:up] do
+ sh("git rebase master")
+ end
+
+ desc "merge current branch to master"
+ task :merge => [:up] do
+ t_branch = current_branch
+ sh("git checkout master")
+ sh("git merge #{t_branch}")
+ sh("git checkout #{t_branch}")
+ end
+
+ desc "commot current branch"
+ task :commit => [:merge] do
+ t_branch = current_branch
+ sh("git checkout master")
+ sh("git push origin master")
+ sh("git checkout #{t_branch}")
+ end
+end
View
12 tasks/rdoc.rake
@@ -0,0 +1,12 @@
+task :doc => [:rdoc]
+
+
+Rake::RDocTask.new do |rdoc|
+ files = ['README', 'MIT-LICENSE', 'CHANGELOG',
+ 'lib/**/*.rb']
+ rdoc.rdoc_files.add(files)
+ rdoc.main = 'README'
+ rdoc.title = 'Packet Docs'
+ rdoc.rdoc_dir = 'doc/rdoc'
+ rdoc.options << '--line-numbers' << '--inline-source'
+end
View
46 tests/echo_server.rb
@@ -1,46 +0,0 @@
-require File.join(File.dirname(__FILE__) + "/runner")
-
-class Foo
- def receive_data data
- send_data data
- end
-
- def post_init
- puts "Post Init test on server : passed"
- end
-
- def unbind
- puts "Unbind test on server: passed"
- end
-end
-
-class Bar
- def receive_data data
- if data == "fuck\n"
- puts "Echo Server test passed"
- else
- puts "Echo Server test failed"
- end
- close_connection
- end
-
- def post_init
- puts "post init test on client: passed"
- end
-
- def connection_completed
- send_data "fuck\n"
- end
-
- def unbind
- puts "server dropped connection"
- end
-end
-
-Packet::Reactor.run do |t_reactor|
- t_reactor.start_server("0.0.0.0",11007,Foo)
- t_reactor.connect("0.0.0.0",11007,Bar)
-end
-
-
-
View
2  tests/message_pass.rb
@@ -1,2 +0,0 @@
-require File.join(File.dirname(__FILE__) + "/runner")
-
View
167 tests/packet_core_test.rb
@@ -0,0 +1,167 @@
+require File.join(File.dirname(__FILE__),"spec_helper")
+
+context "For Packet Core using classes" do
+ setup do
+ class Foo
+ include Packet::Core
+ end
+ class Bar
+ include Packet::Core
+ after_connection :say_hello
+ end
+
+ class ConnectionObj; end
+ end
+
+ specify "should implement after_connection callback working" do
+ Foo.respond_to?(:after_connection).should == true
+ Foo.respond_to?(:after_unbind).should == true
+ Foo.respond_to?(:before_unbind).should == true
+ end
+
+ specify "accept connection should not inherit callbacks" do
+ a = Foo.new
+ a.connection_callbacks.should.be {}
+ socket_obj = mock()
+ client_socket = mock()
+ socket_obj.expects(:accept_nonblock).returns(client_socket)
+ client_socket.expects(:setsockopt).returns(true)
+ client_socket.expects(:fileno).returns(10)
+
+ sock_opts = {:socket => socket_obj,:module => ConnectionObj}
+ a.accept_connection(sock_opts)
+ end
+
+ specify "accept_connection should invoke correspoding callbacks" do
+ a = Bar.new
+ a.expects(:say_hello).returns(true)
+ socket_obj = mock()
+ client_socket = mock()
+ socket_obj.expects(:accept_nonblock).returns(client_socket)
+ client_socket.expects(:setsockopt).returns(true)
+ client_socket.expects(:fileno).returns(10)
+
+ sock_opts = {:socket => socket_obj,:module => ConnectionObj}
+ a.accept_connection(sock_opts)
+ end
+
+ specify "accept_connection should implement methods from Connection module" do
+ a = Bar.new
+ a.expects(:say_hello).returns(true)
+ socket_obj = mock()
+ client_socket = mock()
+ socket_obj.expects(:accept_nonblock).returns(client_socket)
+ client_socket.expects(:setsockopt).returns(true)
+ client_socket.expects(:fileno).returns(10)
+
+ sock_opts = {:socket => socket_obj,:module => ConnectionObj}
+ d = a.accept_connection(sock_opts)
+ d.respond_to?(:connection_completed).should == true
+ d.respond_to?(:post_init).should == true
+ d.respond_to?(:unbind).should == true
+ d.respond_to?(:receive_data).should == true
+ d.respond_to?(:connect).should == true
+ d.respond_to?(:add_periodic_timer).should == true
+ d.respond_to?(:add_timer).should == true
+ end
+
+ specify "start server should register the handle" do
+ a = Foo.new
+ client_connection = stub(:receive_data => "wow")
+ a.start_server("localhost",11000,client_connection)
+ a.listen_sockets.should.not.be.empty
+ a.read_ios.should.not.be.empty
+ fileno = (a.read_ios[0]).fileno
+ a.listen_sockets[fileno][:module].should == client_connection
+ end
+
+ specify "for normal connect" do
+ a = Foo.new
+ client_connection = stub(:receive_data => "wow")
+ a.connect("localhost",8765,client_connection)
+ a.connection_completion_awaited.should.not.be.empty
+ sock_fd = a.connection_completion_awaited.keys[0]
+ a.write_ios[0].fileno == sock_fd
+ end
+
+ specify "for an external connection thats immediately completed" do
+ a = Foo.new
+ client_connection = stub(:receive_data => "wow")
+ a.connect("localhost",8765,client_connection)
+ a.connection_completion_awaited.should.not.be.empty
+ sock_fd = a.connection_completion_awaited.keys[0]
+ a.write_ios[0].fileno == sock_fd
+ end
+
+ specify "reconnect for a diconnected client should attempt reconnection" do
+
+ end
+
+ specify "for a connected connection socket fd should be there in read watchlist" do
+
+ end
+
+ specify "for removing an active connection socket fd should deleted from read/write watchlist" do
+
+ end
+end
+
+context "Packet Core using modules" do
+ setup do
+ class Foo
+ include Packet::Core
+ end
+ module DummyConnection
+ def unbind; "unbind"; end
+ end
+ end
+
+ specify "accept_connection should initialize a class instance from the supplied module" do
+ a = Foo.new
+ a.connection_callbacks.should.be {}
+ socket_obj = mock()
+ client_socket = mock()
+ socket_obj.expects(:accept_nonblock).returns(client_socket)
+ client_socket.expects(:setsockopt).returns(true)
+ client_socket.expects(:fileno).returns(10)
+
+ sock_opts = {:socket => socket_obj,:module => DummyConnection}
+ d = a.accept_connection(sock_opts)
+ d.unbind.should == "unbind"
+ end
+end
+
+context "Receive in packet" do
+ setup do
+ class Foo
+ include Packet::Core
+ end
+ module DummyConnection
+ end
+ end
+
+ specify "should invoke internal data callback for data read from unix socket" do
+ a = Foo.new
+ end
+
+ specify "should invoke external data callback for data read from tcp socket" do
+
+ end
+end
+
+context "Write in Packet" do
+ specify "should watch the socket fd if write is not complete" do
+
+ end
+
+ specify "fd watch should work for both unix and tcp socket" do
+
+ end
+end
+
+
+
+
+
+
+
View
5 tests/packet_master_test.rb
@@ -0,0 +1,5 @@
+require File.join(File.dirname(__FILE__),"spec_helper")
+
+context "For Packet master" do
+
+end
View
100 tests/packet_parser_test.rb
@@ -0,0 +1,100 @@
+require File.join(File.dirname(__FILE__),"spec_helper")
+
+context "Packet Parser" do
+ include Packet::NbioHelper
+ setup do
+ @huge_payload = object_dump('H'*65000)
+ @array_load = object_dump([1,2,3])
+ @packet_parser = Packet::BinParser.new
+ end
+
+ specify "should able to parse complete messages" do
+ @packet_parser.extract(@huge_payload) do |parsed_data|
+ complete_message = Marshal.load(parsed_data)
+ complete_message.should == ('H'*65000)
+ end
+ @packet_parser.data.should.be.empty
+ @packet_parser.parser_state.should == 0
+ @packet_parser.length_string.should.be.empty
+ @packet_parser.numeric_length.should == 0
+ @packet_parser.remaining.should.be.empty
+
+ @packet_parser.extract(@array_load) do |parsed_data|
+ complete_message = Marshal.load(parsed_data)
+ complete_message.should == [1,2,3]
+ end
+ @packet_parser.data.should.be.empty
+ @packet_parser.parser_state.should == 0
+ @packet_parser.length_string.should.be.empty
+ @packet_parser.numeric_length.should == 0
+ @packet_parser.remaining.should.be.empty
+ end
+
+ specify "should able to parse incomplete messages" do
+ @packet_parser.extract(@array_load[0..1]) do |parsed_data|
+ raise "extract succeeded with incomplete message"
+ end
+ @packet_parser.data.should.be.empty
+ @packet_parser.remaining.should.be.empty
+ @packet_parser.parser_state.should == 0
+ @packet_parser.length_string.should == "00"
+
+ @packet_parser.extract(@array_load[2..10]) do |parsed_data|
+ raise "extract succeeded with incomplete message"
+ end
+ # 11 of 19 bytes has been fed to the parser
+ @packet_parser.length_string.should == "000000010"
+ @packet_parser.numeric_length.should == 8
+ @packet_parser.parser_state.should == 1
+ @packet_parser.data[0].should == "\004\b"
+
+ @packet_parser.extract(@array_load[11..16]) do |parsed_data|
+ raise "extract succeeded with incomplete message"
+ end
+
+ # 17 of 19 bytes has been fed to the parser
+ @packet_parser.length_string.should == "000000010"
+ @packet_parser.numeric_length.should == 2
+ @packet_parser.parser_state.should == 1
+ @packet_parser.data.join.should == "\004\b[\bi\006i\a"
+
+ @packet_parser.extract(@array_load[17..18]) do |parsed_data|
+ parsed_data.should == "\004\b[\bi\006i\ai\b"
+ a = Marshal.load(parsed_data)
+ a.should == [1,2,3]
+ end
+ @packet_parser.length_string.should == ""
+ @packet_parser.numeric_length.should == 0
+ @packet_parser.parser_state.should == 0
+ @packet_parser.data.join.should == ""
+ end
+
+ specify "combo messages should be read as well" do
+ combo_message = @array_load + @huge_payload #=> len = 65034
+
+ @packet_parser.extract(combo_message[0..100]) do |parsed_data|
+ parsed_data.should == "\004\b[\bi\006i\ai\b"
+ a = Marshal.load(parsed_data)
+ a.should == [1,2,3]
+ end
+
+ @packet_parser.length_string.should == "000065006"
+ @packet_parser.numeric_length.should == 64933
+ @packet_parser.parser_state.should == 1
+ @packet_parser.data.join.length.should == 73
+ end
+
+end
+
+context "Packet parser for erraneous messages" do
+ setup do
+ @packet_parser = Packet::BinParser.new
+ end
+
+ specify "should reject length with error part" do
+ a = "h00000076\004\b{\t:\ttype:\020sync_invoke:\vworker:\017foo_worker:\barg\"\bboy:\022worker_method\"\vbarbar"
+ @packet_parser.extract(a) do |parser_data|
+ raise "Should not be called"
+ end
+ end
+end
View
5 tests/runner.rb
@@ -1,5 +0,0 @@
-APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__) + "/.."))
-["lib"].each { |x| $LOAD_PATH.unshift(APP_ROOT + "/#{x}")}
-require "packet"
-require "rubygems"
-require "mocha"
View
8 tests/spec_helper.rb
@@ -0,0 +1,8 @@
+APP_ROOT = File.join(File.dirname(__FILE__),"..")
+
+require "#{APP_ROOT}/lib/packet"
+
+require "rubygems"
+require "mocha"
+require "test/spec"
+
View
5 tests/test_for_next_turn.rb
@@ -1,5 +0,0 @@
-require File.join(File.dirname(__FILE__) + "/runner")
-
-Packet::Reactor.run do |t_reactor|
- t_reactor.next_turn { puts "Hello World" }
-end
View
2  tests/worker_comm.rb
@@ -1,2 +0,0 @@
-require File.join(File.dirname(__FILE__) + "/runner")
-
View
13 worker/no_proxy_worker.rb
@@ -8,11 +8,12 @@ def worker_init
end
def receive_data data_obj
- puts "calling receieve data"
- p data_obj[:data].join.size
-# eval_data = eval(data_obj[:data])
-# data_obj[:data] = eval_data
-# data_obj[:type] = :response
-# send_data(data_obj)
+# puts "calling receieve data"
+# p data_obj[:data].join.size
+ eval_data = eval(data_obj[:data])
+ data_obj[:data] = eval_data
+ data_obj[:type] = :response
+ send_data(data_obj)
end
end
+
Please sign in to comment.
Something went wrong with that request. Please try again.