packet 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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