plezi 0.9.2 → 0.10.1

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/README.md +44 -31
  4. data/bin/plezi +3 -3
  5. data/lib/plezi.rb +21 -43
  6. data/lib/plezi/common/defer.rb +21 -0
  7. data/lib/plezi/common/dsl.rb +115 -91
  8. data/lib/plezi/common/redis.rb +44 -0
  9. data/lib/plezi/common/settings.rb +58 -0
  10. data/lib/plezi/handlers/controller_core.rb +132 -0
  11. data/lib/plezi/handlers/controller_magic.rb +85 -259
  12. data/lib/plezi/handlers/http_router.rb +139 -60
  13. data/lib/plezi/handlers/route.rb +9 -178
  14. data/lib/plezi/handlers/stubs.rb +2 -2
  15. data/lib/plezi/helpers/http_sender.rb +72 -0
  16. data/lib/plezi/helpers/magic_helpers.rb +12 -0
  17. data/lib/plezi/{server → helpers}/mime_types.rb +0 -0
  18. data/lib/plezi/version.rb +1 -1
  19. data/plezi.gemspec +3 -11
  20. data/resources/Gemfile +20 -21
  21. data/resources/controller.rb +2 -2
  22. data/resources/oauth_config.rb +1 -1
  23. data/resources/redis_config.rb +2 -0
  24. data/test/plezi_tests.rb +39 -46
  25. metadata +24 -33
  26. data/lib/plezi/common/logging.rb +0 -60
  27. data/lib/plezi/eventmachine/connection.rb +0 -190
  28. data/lib/plezi/eventmachine/em.rb +0 -98
  29. data/lib/plezi/eventmachine/io.rb +0 -272
  30. data/lib/plezi/eventmachine/protocol.rb +0 -54
  31. data/lib/plezi/eventmachine/queue.rb +0 -51
  32. data/lib/plezi/eventmachine/ssl_connection.rb +0 -144
  33. data/lib/plezi/eventmachine/timers.rb +0 -117
  34. data/lib/plezi/eventmachine/workers.rb +0 -33
  35. data/lib/plezi/handlers/http_echo.rb +0 -27
  36. data/lib/plezi/handlers/http_host.rb +0 -214
  37. data/lib/plezi/handlers/magic_helpers.rb +0 -32
  38. data/lib/plezi/server/http.rb +0 -129
  39. data/lib/plezi/server/http_protocol.rb +0 -319
  40. data/lib/plezi/server/http_request.rb +0 -146
  41. data/lib/plezi/server/http_response.rb +0 -319
  42. data/lib/plezi/server/websocket.rb +0 -251
  43. data/lib/plezi/server/websocket_client.rb +0 -178
  44. data/lib/plezi/server/ws_response.rb +0 -161
@@ -1,60 +0,0 @@
1
-
2
- module Plezi
3
-
4
- #######################
5
- ## Logging
6
- module_function
7
-
8
- # the logger object
9
- @logger = ::Logger.new(STDOUT)
10
-
11
- # gets the active logger
12
- def logger
13
- @logger
14
- end
15
- # gets the active STDOUT copy, if exists
16
- def logger_copy
17
- @copy_to_stdout
18
- end
19
-
20
- # create and set the logger object. accepts:
21
- # log_file:: a log file name to be used for logging
22
- # copy_to_stdout:: if false, log will only log to file. defaults to true.
23
- def create_logger log_file = STDOUT, copy_to_stdout = false
24
- @copy_to_stdout = ( copy_to_stdout ? (::Logger.new(STDOUT)) : false )
25
- @logger = ::Logger.new(log_file)
26
- end
27
- alias :set_logger :create_logger
28
-
29
- # writes a raw line to the log\
30
- def log_raw line
31
- @logger << line
32
- @copy_to_stdout << line if @copy_to_stdout
33
- end
34
-
35
- # logs info
36
- def log data
37
- @logger.info data
38
- @copy_to_stdout.info data if @copy_to_stdout
39
- end
40
- # logs info
41
- def info data
42
- @logger.info data
43
- @copy_to_stdout.info data if @copy_to_stdout
44
- end
45
- # logs warning
46
- def warn data
47
- @logger.warn data
48
- @copy_to_stdout.warn data if @copy_to_stdout
49
- end
50
- # logs errors
51
- def error data
52
- @logger.error data
53
- @copy_to_stdout.error data if @copy_to_stdout
54
- end
55
- # logs a fatal error
56
- def fatal data
57
- @logger.fatal data
58
- @copy_to_stdout.fatal data if @copy_to_stdout
59
- end
60
- end
@@ -1,190 +0,0 @@
1
- # encoding: UTF-8
2
-
3
-
4
-
5
- module Plezi
6
-
7
- module EventMachine
8
-
9
- class Connection
10
- attr_reader :socket, :params, :active_time, :out_que, :locker
11
- attr_accessor :protocol, :handler, :timeout
12
-
13
- # initializes the connection and it's settings.
14
- def initialize socket, params
15
- @socket, @params, @handler = socket, params, params[:handler]
16
- # socket.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, "\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #== [10 sec 0 usec].pack '1_2'
17
- @out_que, @locker = [], Mutex.new
18
- @protocol = params[:protocol].is_a?(Class) ? (params[:protocol].new self, params) : params[:protocol]
19
- @protocol.on_connect if @protocol.is_a?(Protocol)
20
- touch
21
- @timeout ||= 5
22
- end
23
-
24
- # used by the EM when the connection should handle data.
25
- def call
26
- # don't let competing threads do the same job.
27
- return false if @locker.locked?
28
- begin
29
- @locker.synchronize do
30
- return disconnect if disconnected?
31
- protocol.on_message
32
- end
33
-
34
- rescue Exception => e
35
- PL.error e
36
- return disconnect
37
- end
38
- end
39
-
40
- def clear?
41
- return false unless timedout? || disconnected?
42
- close
43
- true
44
- end
45
-
46
- # checks if a connection timed out
47
- def timedout?
48
- Time.now - @active_time > @timeout.to_i
49
- end
50
-
51
- # resets the timer for the connection timeout
52
- def touch
53
- @active_time = Time.now
54
- end
55
-
56
- # returns an IO-like object used for reading/writing (unlike the original IO object, this can be an SSL layer or any other wrapper object).
57
- def io
58
- @socket
59
- end
60
-
61
- # the proc used to remove the connection from the IO stack.
62
- REMOVE_CONNECTION_PROC = Proc.new {|old_io| EventMachine.remove_io old_io }
63
- # sends data immidiately - forcing the data to be sent, flushing any pending messages in the que
64
- def send data = nil
65
- return false unless @out_que.any? || data
66
- begin
67
- @locker.synchronize do
68
- unless @out_que.empty?
69
- @out_que.each { |d| _send d }
70
- @out_que.clear
71
- end
72
- (_send data rescue disconnect) if data
73
- end
74
- rescue => e
75
- EventMachine.queue( [@socket], REMOVE_CONNECTION_PROC)
76
- end
77
- true
78
- end
79
-
80
- # the non-blocking proc used for send_nonblock
81
- SEND_COMPLETE_PROC = Proc.new {|c| c.send }
82
-
83
- # sends data without waiting - data might be sent in a different order then intended.
84
- def send_nonblock data
85
- touch
86
- @locker.synchronize {@out_que << data}
87
- EventMachine.queue [self], SEND_COMPLETE_PROC
88
- end
89
-
90
- # adds data to the out buffer - but doesn't send the data until a send event is called.
91
- def << data
92
- touch
93
- @locker.synchronize {@out_que << data}
94
- end
95
-
96
- # makes sure any data in the que is send and calls `flush` on the socket, to make sure the buffer is sent.
97
- def flush
98
- send
99
- io.flush rescue true
100
- end
101
-
102
- # called once the connection is closed.
103
- #
104
- def on_disconnect
105
- @locker.synchronize do
106
- EventMachine.queue [], protocol.method(:on_disconnect) if protocol && !protocol.is_a?(Class)
107
- @protocol = false
108
- end
109
- end
110
-
111
- # the non-blocking proc used for send_nonblock
112
- FLUSH_AND_CLOSE_PROC = Proc.new {|c| c.flush; EventMachine.remove_io c.socket}
113
-
114
- # Closes the connection. This is always asynchronous and will return immidiately.
115
- def close
116
- EventMachine.queue [self], FLUSH_AND_CLOSE_PROC
117
- end
118
- alias :disconnect :close
119
-
120
- # status markers
121
-
122
- # returns true if the service is disconnected
123
- def disconnected?
124
- (@socket.closed? || socket.stat.mode != 0140666) rescue true # if mode is read only, it's the same as closed.
125
- end
126
-
127
- # returns true if the socket has content to be read.
128
- def has_incoming_data?
129
- (@socket.stat.size > 0) rescue false
130
- end
131
-
132
-
133
- # identification markers
134
-
135
- #returns the service type - set to normal
136
- def service_type
137
- 'normal'
138
- end
139
- #returns true if the service is encrypted using the OpenSSL library.
140
- def ssl?
141
- false
142
- end
143
-
144
- #################
145
- # overide the followind methods for any child class.
146
-
147
- # this is a public method and it should be used by child classes to implement each
148
- # read(_nonblock) action. accepts one argument ::size for an optional buffer size to be read.
149
- def read size = 1048576
150
- begin
151
- data = @socket.recv_nonblock( size )
152
- return nil if data.to_s.empty?
153
- touch
154
- data
155
- rescue Exception => e
156
-
157
- end
158
- end
159
- # # this is a public method and it should be used by child classes to implement each
160
- # # read(_nonblock) action. accepts one argument ::size for an optional buffer size to be read.
161
- # def read_line
162
- # data = @line_data ||= ''
163
- # begin
164
- # data << @socket.recv_nonblock( 1 ).to_s until data[-1] == "\n"
165
- # @line_data = ''
166
- # return data
167
- # rescue => e
168
- # return false
169
- # ensure
170
- # touch
171
- # end
172
- # end
173
-
174
- protected
175
-
176
- # this is a protected method, it should be used by child classes to implement each
177
- # send action.
178
- def _send data
179
- @active_time += 7200
180
- len = data.bytesize
181
- i = act = @socket.send data, 0
182
- while len > act && i!=0
183
- act += (i = @socket.send data.byteslice(act..-1) , 0)
184
- end
185
- touch
186
- end
187
-
188
- end
189
- end
190
- end
@@ -1,98 +0,0 @@
1
- module Plezi
2
-
3
- # This module holds the events, timers and IO logic and workflow (asynchronous workflow).
4
- #
5
- # Timed events are approximated and their exact time of execution is dependant on the workload and continues uptime of the process (timed events AREN'T persistant)
6
- module EventMachine
7
-
8
- module_function
9
-
10
- # sets the amount of worker threads cycling the event machine and starts (or re-starts) the event machine.
11
- def start count=12
12
- @workers ||= []
13
- @workers_lock ||= Mutex.new
14
- stop unless @workers.count <= count
15
- (count - @workers.count).times {@workers << Worker.new}
16
- end
17
-
18
- # runs through all existing events and one idle cycle
19
- def run wait = 0.1
20
- begin
21
- fire_timers
22
- do_job while do_job
23
- # replace with io
24
- review_io || sleep(wait)
25
- rescue => e
26
- Plezi.error e
27
- end
28
- end
29
-
30
- def stop_and_wait
31
- @workers.each {|w| w.stop }
32
- @workers.each {|w| w.join }
33
- @workers_lock.synchronize { @workers.clear }
34
- end
35
-
36
- def stop
37
- @workers.each {|w| w.stop }
38
- @workers_lock.synchronize { @workers.clear;}
39
- end
40
-
41
- def running?
42
- @workers && @workers.any?
43
- end
44
- def count_living_workers
45
- (@workers_lock.synchronize { @workers.select {|w| w.alive? } } ).count
46
- end
47
- def workers_status
48
- @workers_lock.synchronize { @workers.map {|w| w.status } }
49
- end
50
-
51
- SHUTDOWN_CALLBACKS = []
52
- # runs the shutdown queue
53
- def shutdown
54
- old_timeout = io_timeout
55
- io_timeout = 0.001
56
- stop_and_wait rescue false
57
- run
58
- io_timeout = old_timeout
59
- do_job while do_job
60
- stop_connections
61
- do_job while do_job
62
- QUEUE_LOCKER.synchronize do
63
- SHUTDOWN_CALLBACKS.each { |s_job| s_job[0].call(*s_job[1]) }
64
- SHUTDOWN_CALLBACKS.clear
65
- end
66
- true
67
- end
68
- # Adds a callback to be called once the services were shut down. see: callback for more info.
69
- def on_shutdown object=nil, method=nil, *args, &block
70
- if block && !object && !method
71
- QUEUE_LOCKER.synchronize {SHUTDOWN_CALLBACKS << [block, args]}
72
- elsif block
73
- QUEUE_LOCKER.synchronize {SHUTDOWN_CALLBACKS << [(Proc.new {|*a| block.call(object.method(method).call(*a))} ), args]}
74
- elsif object && method
75
- QUEUE_LOCKER.synchronize {SHUTDOWN_CALLBACKS << [object.method(method), args]}
76
- end
77
- end
78
-
79
- end
80
-
81
- module_function
82
-
83
- # Plezi event cycle settings: gets how many worker threads Plezi will initially run.
84
- def max_threads
85
- @max_threads ||= 16
86
- end
87
- # Plezi event cycle settings: sets how many worker threads Plezi will initially run.
88
- def max_threads= value
89
- raise "Plezi will hang and do nothing if there isn't at least one (1) working thread. Cannot set Plezi.max_threads = #{value}" if value.to_i <= 0
90
- @max_threads = value.to_i
91
- start @max_threads if EventMachine.running?
92
- end
93
-
94
- # Adds a callback to be called once the services were shut down. see: callback for more info.
95
- def on_shutdown object=nil, method=nil, *args, &block
96
- EventMachine.on_shutdown object, method, *args, &block
97
- end
98
- end
@@ -1,272 +0,0 @@
1
- module Plezi
2
- module EventMachine
3
-
4
- # a basic IO listening socket wrapper.
5
- class BasicIO
6
-
7
- # attribute readers
8
- attr_reader :io, :params, :protocol
9
- # initialize the listener with the actual socket and the properties.
10
- def initialize io, params
11
- @io, @params, @protocol = io, params, false
12
- end
13
- # returns true if the socket is closed and the object can be cleared.
14
- def clear?
15
- @io.closed?
16
- end
17
- # accepts a new connection, adding it to the IO stack, so that it will be reviewed.
18
- def call
19
- begin
20
- socket = io.accept_nonblock
21
- handler = (@params[:ssl] ? SSLConnection : Connection).new socket, @params
22
- EventMachine.add_io socket, handler
23
- rescue Errno::EWOULDBLOCK => e
24
-
25
- rescue OpenSSL::SSL::SSLError => e
26
- Plezi.info "Due to an SSL issue, the connection was refused (maybe untrusted certificate)?"
27
-
28
- rescue => e
29
- Plezi.error e
30
- end
31
- end
32
- def on_disconnect
33
- true
34
- end
35
- def close
36
- false
37
- end
38
- alias :disconnect :close
39
- end
40
- module_function
41
-
42
- # the IO stack.
43
- EM_IO = {}
44
- # the IO Mutex
45
- IO_LOCKER = Mutex.new
46
-
47
- # Adds an io object to the Plezi event machine.
48
- #
49
- # accepts:
50
- # io:: an actual IO object (i.e. socket) that can be passed on to IO.select.
51
- # job:: an object that answers to #call. job#call will be called whenever the IO object is flagged by IO.select.
52
- #
53
- def add_io io, job
54
- IO_LOCKER.synchronize { EM_IO[io] = job }
55
- end
56
-
57
- # the proc for async IO removal, in case of IO exceptions raised by unexpectedly closed sockets.
58
- IO_CLEAR_ASYNC_PROC = Proc.new {|c| c.on_disconnect rescue false }
59
- # removes an IO from the event machine.
60
- def remove_io io
61
- IO_LOCKER.synchronize { queue [(EM_IO.delete io)], IO_CLEAR_ASYNC_PROC; (io.close unless io.closed? rescue true); }
62
- end
63
-
64
- # deletes any connections that are closed or timed out.
65
- def clear_connections
66
- IO_LOCKER.synchronize { EM_IO.delete_if { |io, c| c.clear? } }
67
- end
68
-
69
- # forces the event machine to forget all the existing connections (they will not be reviewed any longer).
70
- def forget_connections
71
- IO_LOCKER.synchronize { EM_IO.clear }
72
- end
73
-
74
- # stops all the connections without stopping the lisntener IO's.
75
- def stop_connections
76
- IO_LOCKER.synchronize { EM_IO.each { |io, c| c.close } }
77
- end
78
-
79
- # set the default idle waiting time.
80
- @io_timeout = 0.1
81
-
82
- # Plezi event cycle settings: how long to wait for IO activity before forcing another cycle.
83
- #
84
- # No timing methods will be called during this interval.
85
- #
86
- # Gets the current idle setting. The default setting is 0.1 seconds.
87
- def io_timeout
88
- @io_timeout
89
- end
90
- # Plezi event cycle settings: how long to wait for IO activity before forcing another cycle.
91
- #
92
- # No timing methods will be called during this interval (#run_after / #run_every).
93
- #
94
- # It's rare, but it's one of the reasons for the timeout: some connections might wait for the timeout befor being established.
95
- #
96
- # set the current idle setting
97
- def io_timeout= value
98
- @io_timeout = value
99
- end
100
-
101
- # hangs for IO data or io_timeout
102
- def review_io
103
- return false if IO_LOCKER.locked?
104
- IO_LOCKER.synchronize do
105
- return false unless queue_empty? && EM_IO.any?
106
- io_array = EM_IO.keys
107
- begin
108
- io_r = ::IO.select(io_array, nil, io_array, @io_timeout)
109
- return false unless io_r
110
- io_r[0].each {|io| queue [], EM_IO[io] }
111
- io_r[2].each { |io| EM_IO.delete io }
112
- rescue Errno::EWOULDBLOCK => e
113
-
114
- rescue => e
115
- EM_IO.keys.each {|io| EventMachine.queue [EM_IO.delete(io)], IO_CLEAR_ASYNC_PROC if io.closed?}
116
- raise e
117
- end
118
- true
119
- end
120
- end
121
-
122
- end
123
-
124
- module DSL
125
- module_function
126
-
127
- # public API to add a service to the framework.
128
- # accepts a Hash object with any of the following options (Hash keys):
129
- # port:: port number. defaults to 3000 or the port specified when the script was called.
130
- # host:: the host name. defaults to any host not explicitly defined (a catch-all).
131
- # alias:: a String or an Array of Strings which represent alternative host names (i.e. `alias: ["admin.google.com", "admin.gmail.com"]`).
132
- # root:: the public root folder. if this is defined, static files will be served from the location.
133
- # assets:: the assets root folder. defaults to nil (no assets support). if the path is defined, assets will be served from `/assets/...` (or the public_asset path defined) before any static files. assets will not be served if the file in the /public/assets folder if up to date (a rendering attempt will be made for systems that allow file writing).
134
- # assets_public:: the assets public uri location (uri format, NOT a file path). defaults to `/assets`. assets will be saved (or rendered) to the assets public folder and served as static files.
135
- # assets_callback:: a method that accepts one parameters: `request` and renders any custom assets. the method should return `false` unless it has created a response object (`response = Plezi::HTTPResponse.new(request)`) and sent a response to the client using `response.finish`.
136
- # save_assets:: saves the rendered assets to the filesystem, under the public folder. defaults to false.
137
- # templates:: the templates root folder. defaults to nil (no template support). templates can be rendered by a Controller class, using the `render` method.
138
- # ssl:: if true, an SSL service will be attempted. if no certificate is defined, an attempt will be made to create a self signed certificate.
139
- # ssl_key:: the public key for the SSL service.
140
- # ssl_cert:: the certificate for the SSL service.
141
- #
142
- # some further options, which are unstable and might be removed in future versions, are:
143
- # protocol:: the protocol objects (usually a class, but any object answering `#call` will do).
144
- # handler:: an optional handling object, to be called upon by the protocol (i.e. #on_message, #on_connect, etc'). this option is used to allow easy protocol switching, such as from HTTP to Websockets.
145
- #
146
- # Duringn normal Plezi behavior, the optional `handler` object will be returned if `listen` is called more than once for the same port.
147
- #
148
- # assets:
149
- #
150
- # assets support will render `.sass`, `.scss` and `.coffee` and save them as local files (`.css`, `.css`, and `.js` respectively)
151
- # before sending them as static files.
152
- #
153
- # templates:
154
- #
155
- # ERB, Slim and Haml are natively supported.
156
- #
157
- def listen parameters = {}
158
- # update default values
159
- parameters = {assets_public: '/assets'}.update(parameters)
160
-
161
- # set port if undefined
162
- if !parameters[:port] && defined? ARGV
163
- if ARGV.find_index('-p')
164
- port_index = ARGV.find_index('-p') + 1
165
- parameters[:port] ||= ARGV[port_index].to_i
166
- ARGV[port_index] = (parameters[:port] + 1).to_s
167
- else
168
- ARGV << '-p'
169
- ARGV << '3001'
170
- parameters[:port] ||= 3000
171
- end
172
- end
173
-
174
- #keeps information of past ports.
175
- @listeners ||= {}
176
- @listeners_locker = Mutex.new
177
-
178
- # check if the port is used twice.
179
- if @listeners[parameters[:port]]
180
- puts "WARNING: port aleady in use! returning existing service and attemptin to add host (maybe multiple hosts? use `host` instead)." unless parameters[:host]
181
- @active_router = @listeners[parameters[:port]].params[:handler] || @listeners[parameters[:port]].params[:protocol]
182
- @active_router.add_host parameters[:host], parameters if @active_router.is_a?(HTTPRouter)
183
- return @active_router
184
- end
185
-
186
- # make sure the protocol exists.
187
- unless parameters[:protocol]
188
- parameters[:protocol] = HTTPProtocol
189
- parameters[:handler] ||= HTTPRouter.new
190
- end
191
-
192
- # create the EventMachine IO object.
193
- io = defined?(PLEZI_ON_RACK) ? parameters : EventMachine::BasicIO.new( TCPServer.new(parameters[:port]), parameters)
194
- EventMachine.add_io io.io, io unless defined? PLEZI_ON_RACK
195
- @listeners_locker.synchronize { @listeners[parameters[:port]] = io }
196
- # set the active router to the handler or the protocol.
197
- @active_router = (parameters[:handler] || parameters[:protocol])
198
- @active_router.add_host(parameters[:host], parameters) if @active_router.is_a?(HTTPRouter)
199
-
200
- Plezi.run_async { Plezi.info "Started listening on port #{parameters[:port]}." } unless defined?(PLEZI_ON_RACK)
201
-
202
- # return the current handler or the protocol..
203
- @active_router
204
- end
205
-
206
- # Plezi Engine, DO NOT CALL. creates the thread pool and starts cycling through the events.
207
- def start_services
208
- if @listeners && @listeners.any?
209
- # prepare threads
210
- exit_flag = false
211
- threads = []
212
- Plezi.run_every(5, &EventMachine.method(:clear_connections))
213
- Plezi.run_every(3_600) {GC.start; Plezi.info "Refreshing worker threads."; EventMachine.stop; EventMachine.start Plezi.max_threads}
214
- # run_every( 1 , Proc.new() { Plezi.info "#{IO_CONNECTION_DIC.length} active connections ( #{ IO_CONNECTION_DIC.select{|k,v| v.protocol.is_a?(WSProtocol)} .length } websockets)." })
215
- # run_every 10 , -> {Plezi.info "Cache report: #{CACHE_STORE.length} objects cached." }
216
- # puts "** Deprecation Warning:\n- The current code for default error pages will be changed in version 0.9.0.\n- Default error pages will follow a different naming and location conventions.\n- The updated design will be part of the updated `plezi` helper script.\nPlease review your code before upgrading to the 0.9.0 version.\n"
217
- puts "Services running Plezi version #{Plezi::VERSION}. Press ^C to stop"
218
- EventMachine.start Plezi.max_threads
219
-
220
- # set signal tarps
221
- trap('INT'){ exit_flag = true; raise "close Plezi" }
222
- trap('TERM'){ exit_flag = true; raise "close Plezi" }
223
- # sleep until trap raises exception (cycling might cause the main thread to ignor signals and lose attention)
224
- sleep rescue true
225
- # avoid refreshing the working threads and stop all timed events.
226
- EventMachine.clear_timers
227
- # start shutdown.
228
- exit_flag = true
229
- # set new tarps
230
- trap('INT'){ puts 'Forced exit.'; Kernel.exit } #rescue true}
231
- trap('TERM'){ puts 'Forced exit.'; Kernel.exit } #rescue true }
232
- puts 'Started shutdown process. Press ^C to force quit.'
233
- # shut down listening sockets
234
- stop_services
235
- # cycle down threads
236
- Plezi.info "Finishing up and running shutdown tasks."
237
- end
238
- EventMachine.shutdown
239
- Plezi.info "Plezi shutdown as requested."
240
- puts "Since we're resting, why not practice Tai Chi?"
241
- # return exit code?
242
- 0
243
- end
244
- # Closes and removes listening IO's registered by Plezi using #listen
245
- def stop_services
246
- Plezi.info 'Stopping services'
247
- @listeners_locker.synchronize { @listeners.each {|port, io| EventMachine.remove_io(io.io); Plezi.info "Stoped listening on port #{port}" } ; @listeners.clear } if @listeners
248
- true
249
- end
250
- end
251
-
252
- module_function
253
-
254
- # Plezi event cycle settings: how long to wait for IO activity before forcing another cycle.
255
- #
256
- # No timing methods will be called during this interval.
257
- #
258
- # Gets the current idle setting. The default setting is 0.1 seconds.
259
- def idle_sleep
260
- EventMachine.io_timeout
261
- end
262
- # Plezi event cycle settings: how long to wait for IO activity before forcing another cycle.
263
- #
264
- # No timing methods will be called during this interval (#run_after / #run_every).
265
- #
266
- # It's rare, but it's one of the reasons for the timeout: some connections might wait for the timeout befor being established.
267
- #
268
- # set the current idle setting
269
- def idle_sleep= value
270
- EventMachine.io_timeout = value
271
- end
272
- end