packet 0.1.2 → 0.1.3

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/Rakefile CHANGED
@@ -16,7 +16,7 @@ NAME = "packet"
16
16
  $LOAD_PATH.unshift __DIR__+'/lib'
17
17
  require 'packet'
18
18
 
19
- CLEAN.include ['**/.*.sw?', '*.gem', '.config']
19
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config','*.rbc']
20
20
 
21
21
 
22
22
  @windows = (PLATFORM =~ /win32/)
data/TODO CHANGED
@@ -3,6 +3,8 @@
3
3
  ** TODO Remove class and class instance attributes from core classes.
4
4
  ** TODO Cleanup callback mechanism
5
5
  ** TODO Implement a sample worker, which provides capabilities to execute mysql statements async.
6
+ ** TODO Implement more cleaner write thingies.
7
+ ** TODO Implement more cleaner timers.
6
8
 
7
9
 
8
10
 
Binary file
@@ -0,0 +1,41 @@
1
+ require "socket"
2
+ require "thread"
3
+
4
+ # sock = TCPSocket.open("localhost",11007)
5
+ #data = File.open("netbeans.jpg").read
6
+ data = File.open("nginx.dat").read
7
+ # p data.length
8
+
9
+ threads = []
10
+ 500.times do
11
+ # sock.write(data)
12
+ # select([sock],nil,nil,nil)
13
+ # read_data = ""
14
+
15
+ # loop do
16
+ # begin
17
+ # while(read_data << sock.read_nonblock(1023)); end
18
+ # rescue Errno::EAGAIN
19
+ # break
20
+ # rescue
21
+ # break
22
+ # end
23
+ # end
24
+
25
+ threads << Thread.new do
26
+ sock = TCPSocket.open("localhost",11007)
27
+ # p read_data.length
28
+ written_length = sock.write(data)
29
+ p "Write Length: #{written_length}"
30
+ read_length = sock.read(written_length)
31
+ p "Read length: #{read_length.length}"
32
+ end
33
+
34
+ # # p read_data.length
35
+ # written_length = sock.write(data)
36
+ # #p "Write Length: #{written_length}"
37
+ # read_length = sock.read(written_length)
38
+ # #p "Read length: #{read_length.length}"
39
+ end
40
+
41
+ threads.each { |x| x.join }
@@ -1,37 +1,30 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
1
4
  require "socket"
2
5
  require "yaml"
3
6
  require "forwardable"
4
7
  require "ostruct"
5
8
  require "thread"
6
9
 
7
- require "bin_parser"
8
-
9
-
10
- require "packet_guid"
11
- require "class_helpers"
12
- require "thread_pool"
13
- require "double_keyed_hash"
14
- require "event"
15
-
16
- require "periodic_event"
17
- require "disconnect_error"
18
- require "callback"
19
-
20
- require "nbio"
21
- require "pimp"
22
- require "meta_pimp"
23
- require "core"
24
-
25
- require "packet_master"
26
- require "connection"
27
- require "worker"
28
-
29
- # This file is just a runner of things and hence does basic initialization of thingies required for running
30
- # the application.
31
-
10
+ require "packet/packet_parser"
11
+ require "packet/packet_guid"
12
+ require "packet/packet_helper"
13
+ require "packet/double_keyed_hash"
14
+ require "packet/packet_event"
15
+ require "packet/packet_periodic_event"
16
+ require "packet/disconnect_error"
17
+ require "packet/packet_callback"
18
+ require "packet/packet_nbio"
19
+ require "packet/packet_pimp"
20
+ require "packet/packet_meta_pimp"
21
+ require "packet/packet_core"
22
+ require "packet/packet_master"
23
+ require "packet/packet_connection"
24
+ require "packet/packet_worker"
32
25
 
33
26
  PACKET_APP = File.expand_path'../' unless defined?(PACKET_APP)
34
27
 
35
28
  module Packet
36
- VERSION='0.1.2'
29
+ VERSION='0.1.3'
37
30
  end
@@ -1,8 +1,9 @@
1
1
  module Packet
2
2
  class DisconnectError < RuntimeError
3
- attr_accessor :disconnected_socket
4
- def initialize(t_sock)
3
+ attr_accessor :disconnected_socket,:data
4
+ def initialize(t_sock,data = nil)
5
5
  @disconnected_socket = t_sock
6
+ @data = data
6
7
  end
7
8
  end
8
9
  end
@@ -3,21 +3,27 @@
3
3
 
4
4
  module Packet
5
5
  module Connection
6
+ attr_accessor :outbound_data,:connection_live
7
+
6
8
  def send_data p_data
9
+ @outbound_data << p_data
7
10
  begin
8
- write_data(p_data,connection)
9
- rescue DisconnectError => sock_error
11
+ write_and_schedule(connection)
12
+ rescue DisconnectError => sock
10
13
  close_connection
11
14
  end
12
15
  end
13
16
 
14
17
  def invoke_init
15
18
  @initialized = true
19
+ @connection_live = true
20
+ @outbound_data = []
16
21
  post_init if respond_to?(:post_init)
17
22
  end
18
23
 
19
- def close_connection
24
+ def close_connection(sock = nil)
20
25
  unbind if respond_to?(:unbind)
26
+ reactor.cancel_write(connection)
21
27
  reactor.remove_connection(connection)
22
28
  end
23
29
 
@@ -29,5 +35,6 @@ module Packet
29
35
  def send_object p_object
30
36
  dump_object(p_object,connection)
31
37
  end
38
+
32
39
  end # end of class Connection
33
40
  end # end of module Packet
@@ -6,11 +6,11 @@ module Packet
6
6
  base_klass.instance_eval do
7
7
  @@connection_callbacks ||= {}
8
8
 
9
- iattr_accessor :thread_pool_size
10
9
  cattr_accessor :connection_callbacks
11
10
  attr_accessor :read_ios, :write_ios, :listen_sockets
12
- attr_accessor :connection_completion_awaited
13
- attr_accessor :connections, :thread_pool, :windows_flag
11
+ attr_accessor :connection_completion_awaited,:write_scheduled
12
+ attr_accessor :connections, :windows_flag
13
+ attr_accessor :internal_scheduled_write,:outbound_data,:reactor
14
14
  include CommonMethods
15
15
  end
16
16
  end
@@ -70,7 +70,6 @@ module Packet
70
70
  client_socket,client_sockaddr = sock_io.accept_nonblock
71
71
  client_socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
72
72
  rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
73
- puts "not ready yet"
74
73
  return
75
74
  end
76
75
  read_ios << client_socket
@@ -96,18 +95,12 @@ module Packet
96
95
 
97
96
  # method removes the connection and closes the socket
98
97
  def remove_connection(t_sock)
99
- @read_ios.delete(t_sock)
100
- @write_ios.delete(t_sock)
101
- connections.delete(t_sock.fileno)
102
- t_sock.close
103
- end
104
-
105
- def socket_really_connected?(t_sock)
98
+ read_ios.delete(t_sock)
99
+ write_ios.delete(t_sock)
106
100
  begin
107
- t_data = read_data(t_sock)
108
- return true
109
- rescue DisconnectError
110
- return false
101
+ connections.delete(t_sock.fileno)
102
+ t_sock.close
103
+ rescue
111
104
  end
112
105
  end
113
106
 
@@ -126,34 +119,70 @@ module Packet
126
119
  Signal.trap("INT") { shutdown }
127
120
  loop do
128
121
  check_for_timer_events
129
- user_thread_window #=> let user level threads run for a while
130
- ready_fds = select(@read_ios,@write_ios,nil,0.005)
131
- #next if ready_fds.blank?
132
-
133
- next if !ready_fds or ready_fds.empty?
134
-
135
- ready_fds = ready_fds.flatten.compact
136
- ready_fds.each do |t_sock|
137
- if(unix? && t_sock.is_a?(UNIXSocket))
138
- handle_internal_messages(t_sock)
139
- else
140
- handle_external_messages(t_sock)
141
- end
122
+ ready_read_fds,ready_write_fds,read_error_fds = select(read_ios,write_ios,nil,0.005)
123
+
124
+ if ready_read_fds && !ready_read_fds.empty?
125
+ handle_read_event(ready_read_fds)
126
+ elsif ready_write_fds && !ready_write_fds.empty?
127
+ handle_write_event(ready_write_fds)
128
+ end
129
+ end
130
+
131
+ end
132
+
133
+ def schedule_write(t_sock)
134
+ fileno = t_sock.fileno
135
+ if UNIXSocket === t_sock && internal_scheduled_write[fileno].nil?
136
+ write_ios << t_sock
137
+ internal_scheduled_write[t_sock.fileno] ||= self
138
+ elsif write_scheduled[fileno].nil?
139
+ write_ios << t_sock
140
+ write_scheduled[fileno] ||= connections[fileno].instance
141
+ end
142
+ end
143
+
144
+ def cancel_write(t_sock)
145
+ fileno = t_sock.fileno
146
+ if UNIXSocket === t_sock
147
+ internal_scheduled_write.delete(fileno)
148
+ else
149
+ write_scheduled.delete(fileno)
150
+ end
151
+ write_ios.delete(t_sock)
152
+ end
153
+
154
+ def handle_write_event(p_ready_fds)
155
+ p_ready_fds.each do |sock_fd|
156
+ fileno = sock_fd.fileno
157
+ if UNIXSocket == sock_fd && internal_scheduled_write[fileno]
158
+ write_and_schedule(sock_fd)
159
+ elsif extern_opts = connection_completion_awaited[fileno]
160
+ complete_connection(sock_fd,extern_opts)
161
+ elsif handler_instance = write_scheduled[fileno]
162
+ handler_instance.write_scheduled(sock_fd)
142
163
  end
143
164
  end
144
165
  end
145
166
 
146
- def user_thread_window
147
- # run_user_threads if respond_to?(:run_user_threads)
148
- @thread_pool.exclusive_run
167
+ def handle_read_event(p_ready_fds)
168
+ ready_fds = p_ready_fds.flatten.compact
169
+ ready_fds.each do |t_sock|
170
+ if(unix? && t_sock.is_a?(UNIXSocket))
171
+ handle_internal_messages(t_sock)
172
+ else
173
+ handle_external_messages(t_sock)
174
+ end
175
+ end
149
176
  end
150
177
 
151
178
  def terminate_me
152
179
  # FIXME: close the open sockets
180
+ # @thread_pool.kill_all
153
181
  exit
154
182
  end
155
183
 
156
184
  def shutdown
185
+ # @thread_pool.kill_all
157
186
  # FIXME: close the open sockets
158
187
  exit
159
188
  end
@@ -166,8 +195,6 @@ module Packet
166
195
  sock_fd = t_sock.fileno
167
196
  if sock_opts = listen_sockets[sock_fd]
168
197
  accept_connection(sock_opts)
169
- elsif extern_opts = connection_completion_awaited[sock_fd]
170
- complete_connection(t_sock,extern_opts)
171
198
  else
172
199
  read_external_socket(t_sock)
173
200
  end
@@ -179,9 +206,7 @@ module Packet
179
206
  t_data = read_data(t_sock)
180
207
  handler_instance.receive_data(t_data) if handler_instance.respond_to?(:receive_data)
181
208
  rescue DisconnectError => sock_error
182
- handler_instance.unbind if handler_instance.respond_to?(:unbind)
183
- connections.delete(t_sock.fileno)
184
- read_ios.delete(t_sock)
209
+ handler_instance.close_connection
185
210
  end
186
211
  end
187
212
 
@@ -202,17 +227,28 @@ module Packet
202
227
  @timer_hash.delete(t_timer.timer_signature)
203
228
  end
204
229
 
230
+ def binding_str
231
+ @binding += 1
232
+ "BIND_#{@binding}"
233
+ end
234
+
205
235
  def initialize
206
236
  @read_ios ||= []
207
237
  @write_ios ||= []
208
238
  @connection_completion_awaited ||= {}
239
+ @write_scheduled ||= {}
240
+ @internal_scheduled_write ||= {}
241
+ # internal outbound data
242
+ @outbound_data = []
209
243
  @connections ||= {}
210
244
  @listen_sockets ||= {}
245
+ @binding = 0
211
246
 
212
247
  # @timer_hash = Packet::TimerStore
213
248
  @timer_hash ||= {}
214
- @thread_pool = ThreadPool.new(thread_pool_size || 20)
249
+ # @thread_pool = ThreadPool.new(thread_pool_size || 20)
215
250
  @windows_flag = windows?
251
+ @reactor = self
216
252
  end
217
253
 
218
254
  def windows?
@@ -233,6 +269,15 @@ module Packet
233
269
  end
234
270
  end
235
271
  end
272
+
273
+ # close the connection with internal specified socket
274
+ def close_connection(sock = nil)
275
+ begin
276
+ read_ios.delete(sock.fileno)
277
+ write_ios.delete(sock.fileno)
278
+ sock.close
279
+ rescue; end
280
+ end
236
281
 
237
282
  def initialize_handler(p_module)
238
283
  return p_module if(!p_module.is_a?(Class) and !p_module.is_a?(Module))
@@ -253,10 +298,9 @@ module Packet
253
298
  handler_instance.unbind if handler_instance.respond_to?(:unbind)
254
299
  return
255
300
  end
256
- t_signature = Guid.hexdigest
257
- handler_instance.signature = t_signature
301
+ handler_instance.signature = binding_str
258
302
  connections[t_socket.fileno] =
259
- OpenStruct.new(:socket => t_socket, :instance => handler_instance, :signature => t_signature,:sock_addr => sock_addr)
303
+ OpenStruct.new(:socket => t_socket, :instance => handler_instance, :signature => handler_instance.signature,:sock_addr => sock_addr)
260
304
  block.call(handler_instance) if block
261
305
  handler_instance.connection_completed if handler_instance.respond_to?(:connection_completed)
262
306
  end
@@ -1,6 +1,6 @@
1
1
  module Packet
2
2
  class Event
3
- attr_accessor :timer_signature, :block, :cancel_flag
3
+ attr_accessor :timer_signature, :block, :cancel_flag, :scheduled_time
4
4
  def initialize(elapsed_time,&block)
5
5
  @cancel_flag = false
6
6
  @timer_signature = Guid.hexdigest
@@ -14,7 +14,7 @@ module Packet
14
14
 
15
15
  def self.run
16
16
  master_reactor_instance = new
17
- # master_reactor_instance.result_hash = {}
17
+ master_reactor_instance.result_hash = {}
18
18
  master_reactor_instance.live_workers = DoubleKeyedHash.new
19
19
  yield(master_reactor_instance)
20
20
  master_reactor_instance.load_workers
@@ -34,7 +34,6 @@ module Packet
34
34
  class << handler_instance
35
35
  extend Forwardable
36
36
  attr_accessor :workers,:connection,:reactor, :initialized,:signature
37
- attr_accessor :thread_pool
38
37
  include NbioHelper
39
38
  include Connection
40
39
  def ask_worker(*args)
@@ -52,7 +51,6 @@ module Packet
52
51
  handler_instance.workers = @live_workers
53
52
  handler_instance.connection = t_sock
54
53
  handler_instance.reactor = self
55
- handler_instance.thread_pool = @thread_pool
56
54
  end
57
55
 
58
56
  # FIXME: right now, each worker is tied to its connection and this can be problematic
@@ -65,10 +63,16 @@ module Packet
65
63
  # t_data = Marshal.load(raw_data)
66
64
  worker_instance.receive_data(raw_data) if worker_instance.respond_to?(:receive_data)
67
65
  rescue DisconnectError => sock_error
68
- read_ios.delete(t_sock)
66
+ remove_worker(t_sock)
69
67
  end
70
68
  end
69
+
71
70
 
71
+ def remove_worker(t_sock)
72
+ @live_workers.delete(t_sock.fileno)
73
+ read_ios.delete(t_sock)
74
+ end
75
+
72
76
  def delete_worker(worker_options = {})
73
77
  worker_name = worker_options[:worker]
74
78
  worker_name_key = gen_worker_key(worker_name,worker_options[:job_key])
@@ -100,10 +104,14 @@ module Packet
100
104
  worker_options.delete(:worker)
101
105
  begin
102
106
  require worker_name
107
+ worker_klass = Object.const_get(packet_classify(worker_name))
108
+ fork_and_load(worker_klass,worker_options)
103
109
  rescue LoadError
110
+ puts "no such worker #{worker_name}"
111
+ rescue MissingSourceFile
112
+ puts "no such worker #{worker_name}"
113
+ return
104
114
  end
105
- worker_klass = Object.const_get(packet_classify(worker_name))
106
- fork_and_load(worker_klass,worker_options)
107
115
  end
108
116
 
109
117
  # method forks given worker file in a new process
@@ -116,14 +124,14 @@ module Packet
116
124
  master_read_end,worker_write_end = UNIXSocket.pair(Socket::SOCK_STREAM)
117
125
  # socket to which master process is going to write
118
126
  worker_read_end,master_write_end = UNIXSocket.pair(Socket::SOCK_STREAM)
119
- worker_read_fd,master_write_fd = UNIXSocket.pair
127
+ # worker_read_fd,master_write_fd = UNIXSocket.pair
120
128
 
121
129
  if((pid = fork()).nil?)
122
130
  $0 = "ruby #{worker_klass.worker_name}"
123
- [master_write_end,master_read_end,master_write_fd].each { |x| x.close }
131
+ [master_write_end,master_read_end].each { |x| x.close }
124
132
 
125
133
  worker_klass.start_worker(:write_end => worker_write_end,:read_end => worker_read_end,\
126
- :read_fd => worker_read_fd,:options => worker_options)
134
+ :options => worker_options)
127
135
  end
128
136
  Process.detach(pid)
129
137
 
@@ -136,12 +144,12 @@ module Packet
136
144
  else
137
145
  t_pimp = Packet::MetaPimp.new(master_write_end,pid,self)
138
146
  t_pimp.worker_key = worker_name_key
147
+ t_pimp.worker_name = t_worker_name
139
148
  @live_workers[worker_name_key,master_read_end.fileno] = t_pimp
140
149
  end
141
150
 
142
151
  worker_read_end.close
143
152
  worker_write_end.close
144
- worker_read_fd.close
145
153
  read_ios << master_read_end
146
154
  end # end of fork_and_load method
147
155
  end # end of Reactor class