packet 0.1.0

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.
@@ -0,0 +1,19 @@
1
+ module Packet
2
+ class CPUWorker < Packet::Worker
3
+ @@worker_type = 'cpu'
4
+ cattr_accessor :worker_type
5
+ # this is the place where all the worker specific inititlization has to be done
6
+ def worker_init
7
+ @worker_started = true
8
+ end
9
+
10
+ def receive_data p_data
11
+ p p_data
12
+ end
13
+
14
+ def receive_internal_data p_data
15
+ p p_data
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,210 @@
1
+ # $Id: deferrable.rb 534 2007-09-15 23:06:15Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 Jul 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ # FIXME: Packet doesn't support timers on Deferables yet
27
+
28
+ require 'forwardable'
29
+
30
+ module Packet
31
+
32
+ module Deferrable
33
+
34
+ # Specify a block to be executed if and when the Deferrable object receives
35
+ # a status of :succeeded. See #set_deferred_status for more information.
36
+ #
37
+ # Calling this method on a Deferrable object whose status is not yet known
38
+ # will cause the callback block to be stored on an internal list.
39
+ # If you call this method on a Deferrable whose status is :succeeded, the
40
+ # block will be executed immediately, receiving the parameters given to the
41
+ # prior #set_deferred_status call.
42
+ #
43
+ #--
44
+ # If there is no status, add a callback to an internal list.
45
+ # If status is succeeded, execute the callback immediately.
46
+ # If status is failed, do nothing.
47
+ #
48
+ def callback &block
49
+ return unless block
50
+ if @deferred_status == :succeeded
51
+ block.call(*@deferred_args)
52
+ elsif @deferred_status != :failed
53
+ @callbacks ||= []
54
+ @callbacks.unshift block # << block
55
+ end
56
+ end
57
+
58
+ # Specify a block to be executed if and when the Deferrable object receives
59
+ # a status of :failed. See #set_deferred_status for more information.
60
+ #--
61
+ # If there is no status, add an errback to an internal list.
62
+ # If status is failed, execute the errback immediately.
63
+ # If status is succeeded, do nothing.
64
+ #
65
+ def errback &block
66
+ return unless block
67
+ if @deferred_status == :failed
68
+ block.call(*@deferred_args)
69
+ elsif @deferred_status != :succeeded
70
+ @errbacks ||= []
71
+ @errbacks.unshift block # << block
72
+ end
73
+ end
74
+
75
+ # Sets the "disposition" (status) of the Deferrable object. See also the large set of
76
+ # sugarings for this method.
77
+ # Note that if you call this method without arguments,
78
+ # no arguments will be passed to the callback/errback.
79
+ # If the user has coded these with arguments, then the
80
+ # user code will throw an argument exception.
81
+ # Implementors of deferrable classes <b>must</b>
82
+ # document the arguments they will supply to user callbacks.
83
+ #
84
+ # OBSERVE SOMETHING VERY SPECIAL here: you may call this method even
85
+ # on the INSIDE of a callback. This is very useful when a previously-registered
86
+ # callback wants to change the parameters that will be passed to subsequently-registered
87
+ # ones.
88
+ #
89
+ # You may give either :succeeded or :failed as the status argument.
90
+ #
91
+ # If you pass :succeeded, then all of the blocks passed to the object using the #callback
92
+ # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
93
+ # passed to the object using #errback will be discarded.
94
+ #
95
+ # If you pass :failed, then all of the blocks passed to the object using the #errback
96
+ # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
97
+ # passed to the object using # callback will be discarded.
98
+ #
99
+ # If you pass any arguments to #set_deferred_status in addition to the status argument,
100
+ # they will be passed as arguments to any callbacks or errbacks that are executed.
101
+ # It's your responsibility to ensure that the argument lists specified in your callbacks and
102
+ # errbacks match the arguments given in calls to #set_deferred_status, otherwise Ruby will raise
103
+ # an ArgumentError.
104
+ #
105
+ # --
106
+ # We're shifting callbacks off and discarding them as we execute them.
107
+ # This is valid because by definition callbacks are executed no more than
108
+ # once. It also has the magic effect of permitting recursive calls, which
109
+ # means that a callback can call #set_deferred_status and change the parameters
110
+ # that will be sent to subsequent callbacks down the chain.
111
+ #
112
+ # Changed @callbacks and @errbacks from push/shift to unshift/pop, per suggestion
113
+ # by Kirk Haines, to work around the memory leak bug that still exists in many Ruby
114
+ # versions.
115
+ #
116
+ # Changed 15Sep07: after processing callbacks or errbacks, CLEAR the other set of
117
+ # handlers. This gets us a little closer to the behavior of Twisted's "deferred,"
118
+ # which only allows status to be set once. Prior to making this change, it was possible
119
+ # to "succeed" a Deferrable (triggering its callbacks), and then immediately "fail" it,
120
+ # triggering its errbacks! That is clearly undesirable, but it's just as undesirable
121
+ # to raise an exception is status is set more than once on a Deferrable. The latter
122
+ # behavior would invalidate the idiom of resetting arguments by setting status from
123
+ # within a callback or errback, but more seriously it would cause spurious errors
124
+ # if a Deferrable was timed out and then an attempt was made to succeed it. See the
125
+ # comments under the new method #timeout.
126
+ #
127
+ def set_deferred_status status, *args
128
+ #cancel_timeout
129
+ @deferred_status = status
130
+ @deferred_args = args
131
+ case @deferred_status
132
+ when :succeeded
133
+ if @callbacks
134
+ while cb = @callbacks.pop
135
+ cb.call(*@deferred_args)
136
+ end
137
+ end
138
+ @errbacks.clear if @errbacks
139
+ when :failed
140
+ if @errbacks
141
+ while eb = @errbacks.pop
142
+ eb.call(*@deferred_args)
143
+ end
144
+ end
145
+ @callbacks.clear if @callbacks
146
+ end
147
+ end
148
+
149
+
150
+ # Setting a timeout on a Deferrable causes it to go into the failed state after
151
+ # the Timeout expires (passing no arguments to the object's errbacks).
152
+ # Setting the status at any time prior to a call to the expiration of the timeout
153
+ # will cause the timer to be cancelled.
154
+ #--
155
+ #
156
+ #
157
+ def timeout seconds
158
+ cancel_timeout
159
+ me = self
160
+ @deferred_timeout = EventMachine::Timer.new(seconds) {me.fail}
161
+ end
162
+
163
+
164
+ # Cancels an outstanding timeout if any. Undoes the action of #timeout.
165
+ #
166
+ #
167
+ def cancel_timeout
168
+ if @deferred_timeout
169
+ @deferred_timeout.cancel
170
+ @deferred_timeout = nil
171
+ end
172
+ end
173
+
174
+
175
+ # Equivalent to set_deferred_status(:succeeded, ...)
176
+ #
177
+ def set_deferred_success *args
178
+ set_deferred_status :succeeded, *args
179
+ end
180
+
181
+ # Equivalent to set_deferred_status(:failed, ...)
182
+ #
183
+ def set_deferred_failure *args
184
+ set_deferred_status :failed, *args
185
+ end
186
+
187
+ # And still more sugar
188
+ #
189
+ def succeed *args
190
+ set_deferred_success(*args)
191
+ end
192
+
193
+ # Can't get enough sugar
194
+ #
195
+ def fail *args
196
+ set_deferred_failure(*args)
197
+ end
198
+ end
199
+
200
+
201
+ # DefaultDeferrable is an otherwise empty class that includes Deferrable.
202
+ # This is very useful when you just need to return a Deferrable object
203
+ # as a way of communicating deferred status to some other part of a program.
204
+ #
205
+ class DefaultDeferrable
206
+ include Deferrable
207
+ end
208
+
209
+ end
210
+
@@ -0,0 +1,8 @@
1
+ module Packet
2
+ class DisconnectError < RuntimeError
3
+ attr_accessor :disconnected_socket
4
+ def initialize(t_sock)
5
+ @disconnected_socket = t_sock
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,19 @@
1
+ class DoubleKeyedHash
2
+ def initialize
3
+ @keys1 = {}
4
+ @internal_hash = {}
5
+ end
6
+
7
+ def []=(key1,key2,value)
8
+ @keys1[key2] = key1
9
+ @internal_hash[key1] = value
10
+ end
11
+
12
+ def [] key
13
+ @internal_hash[key] || @internal_hash[@keys1[key]]
14
+ end
15
+
16
+ def each
17
+ @internal_hash.each { |key,value| yield(key,value)}
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module Packet
2
+ class Event
3
+ attr_accessor :timer_signature, :block, :cancel_flag
4
+ def initialize(elapsed_time,&block)
5
+ @cancel_flag = false
6
+ @timer_signature = Guid.hexdigest
7
+ @block = block
8
+ @scheduled_time = Time.now + elapsed_time
9
+ end
10
+
11
+ def run_now?
12
+ return true if @scheduled_time <= Time.now
13
+ return false
14
+ end
15
+
16
+ def cancel
17
+ @cancel_flag = true
18
+ end
19
+
20
+ def run
21
+ @block.call
22
+ end
23
+ end
24
+ end
25
+ # WOW
@@ -0,0 +1,6 @@
1
+ module Packet
2
+ class IOWorker < Packet::Worker
3
+ @@worker_type = :io
4
+ cattr_accessor :worker_type
5
+ end
6
+ end
@@ -0,0 +1,66 @@
1
+ # Class acts as a pimp for workers, which doesn't have a manually created pimp
2
+ # The idea behind a manually added pimp is to let client handle low level messaging
3
+ # beween workers. A meta pimp, does it for you.
4
+ class Packet::MetaPimp < Packet::Pimp
5
+ # initializer of pimp
6
+ attr_accessor :callback_hash
7
+ attr_accessor :worker_status
8
+ def pimp_init
9
+ @callback_hash ||= {}
10
+ @worker_status = nil
11
+ @tokenizer = BinParser.new
12
+ end
13
+
14
+ # will be invoked whenever there is a response from the worker
15
+ # Possible bug with reading large responses.
16
+ # response would be binary but base64 encoded and must be decoded and then loaded
17
+ def receive_data p_data
18
+ @tokenizer.extract(p_data) do |b_data|
19
+ t_data = Marshal.load(b_data)
20
+ handle_object(t_data)
21
+ end
22
+ end
23
+
24
+ def handle_object data_options = {}
25
+ case data_options[:type]
26
+ when :request
27
+ process_request(data_options)
28
+ when :response
29
+ process_response(data_options)
30
+ when :status
31
+ save_worker_status(data_options)
32
+ end
33
+ end
34
+
35
+ def save_worker_status(data_options = { })
36
+ @worker_status = data_options[:data]
37
+ end
38
+
39
+ def process_request(data_options = {})
40
+ if requested_worker = data_options[:requested_worker]
41
+ reactor.live_workers[requested_worker].send_request(data_options)
42
+ end
43
+ end
44
+
45
+ def process_response(data_options = {})
46
+ if callback_signature = data_options[:callback_signature]
47
+ callback = callback_hash[callback_signature]
48
+ callback.call(data_options)
49
+ elsif client_signature = data_options[:client_signature]
50
+ reactor.connections[client_signature].instance.worker_receive(data_options)
51
+ end
52
+ end
53
+
54
+ # can be used to send request to correspoding worker
55
+ def send_request(data_options = { })
56
+ if callback = data_options[:callback]
57
+ callback_hash[callback.signature] = callback
58
+ data_options.delete(:callback)
59
+ data_options[:callback_signature] = callback.signature
60
+ send_data(data_options)
61
+ else
62
+ send_data(data_options)
63
+ end
64
+ end
65
+ end
66
+
@@ -0,0 +1,81 @@
1
+ module Packet
2
+ module NbioHelper
3
+ # nonblocking method of reading data
4
+ # when method returns nil it probably means that client diconnected
5
+ def read_data(t_sock)
6
+ sock_data = ""
7
+ begin
8
+ while(sock_data << t_sock.read_nonblock(1023)); end
9
+ rescue Errno::EAGAIN
10
+ return sock_data
11
+ rescue
12
+ raise DisconnectError.new(t_sock)
13
+ end
14
+ end
15
+
16
+ def write_data(p_data,p_sock)
17
+ return unless p_data
18
+ if p_data.is_a? Fixnum
19
+ t_data = p_data.to_s
20
+ else
21
+ t_data = p_data.dup.to_s
22
+ end
23
+ t_length = t_data.length
24
+ begin
25
+ p_sock.write_nonblock(t_data)
26
+ rescue Errno::EAGAIN
27
+ return
28
+ end
29
+
30
+ # loop do
31
+ # begin
32
+ # written_length = p_sock.write_nonblock(t_data)
33
+ # rescue Errno::EAGAIN
34
+ # break
35
+ # end
36
+ # break if written_length >= t_length
37
+ # t_data = t_data[written_length..-1]
38
+ # break if t_data.empty?
39
+ # t_length = t_data.length
40
+ # end
41
+ end
42
+
43
+ # method writes data to socket in a non blocking manner, but doesn't care if there is a error writing data
44
+ def write_once(p_data,p_sock)
45
+ t_data = p_data.dup.to_s
46
+ begin
47
+ p_sock.write_nonblock(t_data)
48
+ rescue Errno::EAGAIN
49
+ return
50
+ end
51
+ end
52
+
53
+ # method dumps the object in a protocol format which can be easily picked by a recursive descent parser
54
+ def dump_object(p_data,p_sock)
55
+ object_dump = Marshal.dump(p_data)
56
+ dump_length = object_dump.length.to_s
57
+ length_str = dump_length.rjust(9,'0')
58
+ final_data = length_str + object_dump
59
+
60
+ # total_length = final_data.length
61
+ # loop do
62
+ # begin
63
+ # written_length = p_sock.write_nonblock(final_data)
64
+ # rescue Errno::EAGAIN
65
+ # break
66
+ # end
67
+ # break if written_length >= total_length
68
+ # final_data = final_data[written_length..-1]
69
+ # break if final_data.empty?
70
+ # total_length = final_data.length
71
+ # end
72
+
73
+ begin
74
+ p_sock.write_nonblock(final_data)
75
+ rescue Errno::EAGAIN
76
+ return
77
+ end
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,37 @@
1
+ require "socket"
2
+ require "yaml"
3
+ require "forwardable"
4
+ require "attribute_accessors"
5
+ require "buftok"
6
+ require "bin_parser"
7
+
8
+ require "ostruct"
9
+ require "socket"
10
+
11
+ require "packet_guid"
12
+ require "ruby_hacks"
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
+
32
+
33
+ PACKET_APP = File.expand_path'../' unless defined?(PACKET_APP)
34
+
35
+ module Packet
36
+ VERSION='0.1.0'
37
+ end