plezi 0.7.7 → 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +3 -3
- data/lib/plezi.rb +35 -36
- data/lib/plezi/common/cache.rb +94 -0
- data/lib/plezi/{base → common}/dsl.rb +87 -68
- data/lib/plezi/{base → common}/logging.rb +15 -15
- data/lib/plezi/eventmachine/connection.rb +192 -0
- data/lib/plezi/eventmachine/em.rb +95 -0
- data/lib/plezi/eventmachine/io.rb +265 -0
- data/lib/plezi/eventmachine/protocol.rb +54 -0
- data/lib/plezi/eventmachine/queue.rb +51 -0
- data/lib/plezi/eventmachine/ssl_connection.rb +138 -0
- data/lib/plezi/eventmachine/timers.rb +117 -0
- data/lib/plezi/eventmachine/workers.rb +35 -0
- data/lib/plezi/handlers/http_host.rb +4 -4
- data/lib/plezi/handlers/magic_helpers.rb +1 -21
- data/lib/plezi/handlers/route.rb +3 -3
- data/lib/plezi/server/{helpers/http.rb → http.rb} +1 -57
- data/lib/plezi/server/{protocols/http_protocol.rb → http_protocol.rb} +18 -35
- data/lib/plezi/server/{protocols/http_request.rb → http_request.rb} +1 -1
- data/lib/plezi/server/{protocols/http_response.rb → http_response.rb} +45 -22
- data/lib/plezi/server/{helpers/mime_types.rb → mime_types.rb} +0 -0
- data/lib/plezi/server/{protocols/websocket.rb → websocket.rb} +34 -37
- data/lib/plezi/server/{protocols/ws_response.rb → ws_response.rb} +37 -19
- data/lib/plezi/version.rb +1 -1
- data/plezi.gemspec +3 -3
- data/resources/config.ru +9 -11
- metadata +27 -30
- data/lib/plezi/base/cache.rb +0 -89
- data/lib/plezi/base/connections.rb +0 -33
- data/lib/plezi/base/engine.rb +0 -77
- data/lib/plezi/base/events.rb +0 -93
- data/lib/plezi/base/io_reactor.rb +0 -62
- data/lib/plezi/base/rack_app.rb +0 -89
- data/lib/plezi/base/services.rb +0 -57
- data/lib/plezi/base/timers.rb +0 -71
- data/lib/plezi/server/README.md +0 -33
- data/lib/plezi/server/services/basic_service.rb +0 -224
- data/lib/plezi/server/services/no_service.rb +0 -196
- data/lib/plezi/server/services/ssl_service.rb +0 -193
@@ -1,62 +0,0 @@
|
|
1
|
-
|
2
|
-
module Plezi
|
3
|
-
|
4
|
-
module_function
|
5
|
-
|
6
|
-
# set the default idle waiting time.
|
7
|
-
@idle_sleep = 0.1
|
8
|
-
|
9
|
-
# Plezi event cycle settings: how long to wait for IO activity before forcing another cycle.
|
10
|
-
#
|
11
|
-
# No timing methods will be called during this interval.
|
12
|
-
#
|
13
|
-
# Gets the current idle setting. The default setting is 0.1 seconds.
|
14
|
-
def idle_sleep
|
15
|
-
@idle_sleep
|
16
|
-
end
|
17
|
-
# Plezi event cycle settings: how long to wait for IO activity before forcing another cycle.
|
18
|
-
#
|
19
|
-
# No timing methods will be called during this interval (#run_after / #run_every).
|
20
|
-
#
|
21
|
-
# It's rare, but it's one of the reasons for the timeout: some connections might wait for the timeout befor being established.
|
22
|
-
#
|
23
|
-
# set the current idle setting
|
24
|
-
def idle_sleep= value
|
25
|
-
@idle_sleep = value
|
26
|
-
end
|
27
|
-
|
28
|
-
# DANGER ZONE - Plezi Engine. the io reactor mutex
|
29
|
-
IO_LOCKER = Mutex.new
|
30
|
-
|
31
|
-
# Plezi Engine, DO NOT CALL. waits on IO and pushes events. all threads hang while reactor is active (unless events are already 'in the pipe'.)
|
32
|
-
def io_reactor
|
33
|
-
IO_LOCKER.synchronize do
|
34
|
-
return false unless EVENTS.empty?
|
35
|
-
united = SERVICES.keys + IO_CONNECTION_DIC.keys
|
36
|
-
return false if united.empty?
|
37
|
-
io_r = (IO.select(united, nil, united, @idle_sleep) ) #rescue false)
|
38
|
-
if io_r
|
39
|
-
io_r[0].each do |io|
|
40
|
-
if SERVICES[io]
|
41
|
-
begin
|
42
|
-
connection = io.accept_nonblock
|
43
|
-
push_event method(:add_connection), connection, SERVICES[io]
|
44
|
-
rescue Errno::EWOULDBLOCK => e
|
45
|
-
|
46
|
-
rescue Exception => e
|
47
|
-
error e
|
48
|
-
# SERVICES.delete s if s.closed?
|
49
|
-
end
|
50
|
-
elsif IO_CONNECTION_DIC[io]
|
51
|
-
push_event IO_CONNECTION_DIC[io].method(:on_message)
|
52
|
-
else
|
53
|
-
IO_CONNECTION_DIC.delete(io)
|
54
|
-
SERVICES.delete(io)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
io_r[2].each { |io| (IO_CONNECTION_DIC.delete(io) || SERVICES.delete(io)).close rescue true }
|
58
|
-
end
|
59
|
-
end
|
60
|
-
true
|
61
|
-
end
|
62
|
-
end
|
data/lib/plezi/base/rack_app.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
|
2
|
-
module Plezi
|
3
|
-
|
4
|
-
# Rack application model support
|
5
|
-
module_function
|
6
|
-
|
7
|
-
# todo: move falsh into the special cookie class...?
|
8
|
-
|
9
|
-
|
10
|
-
# Plezi dresses up for Rack - this is a watered down version missing some features (such as flash and WebSockets).
|
11
|
-
# a full featured Plezi app, with WebSockets, requires the use of the Plezi server
|
12
|
-
# (the built-in server)
|
13
|
-
def call env
|
14
|
-
raise "No Plezi Services" unless Plezi::SERVICES[0]
|
15
|
-
Object.const_set('PLEZI_ON_RACK', true) unless defined? PLEZI_ON_RACK
|
16
|
-
|
17
|
-
# re-encode to utf-8, as it's all BINARY encoding at first
|
18
|
-
env['rack.input'].rewind
|
19
|
-
env['rack.input'] = StringIO.new env['rack.input'].read.encode('utf-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
20
|
-
env.each do |k, v|
|
21
|
-
if k.to_s.match /^[A-Z]/
|
22
|
-
if v.is_a?(String) && !v.frozen?
|
23
|
-
v.force_encoding('binary').encode!('utf-8', 'binary', invalid: :replace, undef: :replace, replace: '') unless v.force_encoding('utf-8').valid_encoding?
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
# re-key params
|
28
|
-
# new_params = {}
|
29
|
-
# env[:params].each {|k,v| HTTP.add_param_to_hash k, v, new_params}
|
30
|
-
# env[:params] = new_params
|
31
|
-
|
32
|
-
# make hashes magical
|
33
|
-
make_hash_accept_symbols(env)
|
34
|
-
|
35
|
-
# use Plezi Cookies
|
36
|
-
env['rack.request.cookie_string'] = env['HTTP_COOKIE']
|
37
|
-
env['rack.request.cookie_hash'] = Plezi::Cookies.new.update(env['rack.request.cookie_hash'] || {})
|
38
|
-
|
39
|
-
# chomp path
|
40
|
-
env['PATH_INFO'].chomp! '/'
|
41
|
-
|
42
|
-
# get response
|
43
|
-
response = Plezi::SERVICES[0][1][:handler].call env
|
44
|
-
|
45
|
-
return response if response.is_a?(Array)
|
46
|
-
|
47
|
-
response.finish
|
48
|
-
response.fix_headers
|
49
|
-
headers = response.headers
|
50
|
-
# set cookie headers
|
51
|
-
headers.delete 'transfer-encoding'
|
52
|
-
headers.delete 'connection'
|
53
|
-
unless response.cookies.empty?
|
54
|
-
headers['Set-Cookie'] = []
|
55
|
-
response.cookies.each {|k,v| headers['Set-Cookie'] << ("#{k.to_s}=#{v.to_s}")}
|
56
|
-
end
|
57
|
-
[response.status, headers, response.body]
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# # rack code to set cookie headers
|
62
|
-
# # File actionpack/lib/action_controller/vendor/rack-1.0/rack/response.rb, line 56
|
63
|
-
# def set_cookie(key, value)
|
64
|
-
# case value
|
65
|
-
# when Hash
|
66
|
-
# domain = "; domain=" + value[:domain] if value[:domain]
|
67
|
-
# path = "; path=" + value[:path] if value[:path]
|
68
|
-
# # According to RFC 2109, we need dashes here.
|
69
|
-
# # N.B.: cgi.rb uses spaces...
|
70
|
-
# expires = "; expires=" + value[:expires].clone.gmtime.
|
71
|
-
# strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
|
72
|
-
# secure = "; secure" if value[:secure]
|
73
|
-
# httponly = "; HttpOnly" if value[:httponly]
|
74
|
-
# value = value[:value]
|
75
|
-
# end
|
76
|
-
# value = [value] unless Array === value
|
77
|
-
# cookie = Utils.escape(key) + "=" +
|
78
|
-
# value.map { |v| Utils.escape v }.join("&") +
|
79
|
-
# "#{domain}#{path}#{expires}#{secure}#{httponly}"
|
80
|
-
|
81
|
-
# case self["Set-Cookie"]
|
82
|
-
# when Array
|
83
|
-
# self["Set-Cookie"] << cookie
|
84
|
-
# when String
|
85
|
-
# self["Set-Cookie"] = [self["Set-Cookie"], cookie]
|
86
|
-
# when nil
|
87
|
-
# self["Set-Cookie"] = cookie
|
88
|
-
# end
|
89
|
-
# end
|
data/lib/plezi/base/services.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
|
2
|
-
module Plezi
|
3
|
-
|
4
|
-
module_function
|
5
|
-
|
6
|
-
#######################
|
7
|
-
## Services pooling and calling
|
8
|
-
|
9
|
-
# DANGER ZONE - Plezi Engine. the services store
|
10
|
-
SERVICES = {}
|
11
|
-
# DANGER ZONE - Plezi Engine. the services mutex
|
12
|
-
S_LOCKER = Mutex.new
|
13
|
-
|
14
|
-
# public API to add a service to the framework.
|
15
|
-
# accepts:
|
16
|
-
# port:: port number
|
17
|
-
# parameters:: a hash of parameters that are passed on to the service for handling (and from there, service dependent, to the protocol and/or handler).
|
18
|
-
#
|
19
|
-
# parameters are any of the following:
|
20
|
-
# host:: the host name. defaults to any host not explicitly defined (a catch-all).
|
21
|
-
# alias:: a String or an Array of Strings which represent alternative host names (i.e. `alias: ["admin.google.com", "admin.gmail.com"]`).
|
22
|
-
# root:: the public root folder. if this is defined, static files will be served from the location.
|
23
|
-
# 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).
|
24
|
-
# 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.
|
25
|
-
# 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`.
|
26
|
-
# save_assets:: saves the rendered assets to the filesystem, under the public folder. defaults to false.
|
27
|
-
# templates:: the templates root folder. defaults to nil (no template support). templates can be rendered by a Controller class, using the `render` method.
|
28
|
-
# 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.
|
29
|
-
# ssl_key:: the public key for the SSL service.
|
30
|
-
# ssl_cert:: the certificate for the SSL service.
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# assets:
|
34
|
-
#
|
35
|
-
# assets support will render `.sass`, `.scss` and `.coffee` and save them as local files (`.css`, `.css`, and `.js` respectively) before sending them as static files. if it is impossible to write the files, they will be rendered dynamically for every request (it would be better to render them before-hand).
|
36
|
-
#
|
37
|
-
# templates:
|
38
|
-
#
|
39
|
-
# templates can be either an ERB file on a Haml file.
|
40
|
-
#
|
41
|
-
def add_service port, parameters = {}
|
42
|
-
parameters[:port] ||= port
|
43
|
-
parameters[:service_type] ||= ( parameters[:ssl] ? SSLService : BasicService)
|
44
|
-
service = nil
|
45
|
-
service = parameters[:service_type].create_service(port, parameters) unless ( defined?(BUILDING_PLEZI_TEMPLATE) || defined?(PLEZI_ON_RACK) )
|
46
|
-
S_LOCKER.synchronize {SERVICES[service] = parameters}
|
47
|
-
Plezi.callback Plezi, :info, "Started listening on port #{port}."
|
48
|
-
true
|
49
|
-
end
|
50
|
-
|
51
|
-
# Plezi Engine, DO NOT CALL. stops all services - active connection will remain open until completion.
|
52
|
-
def stop_services
|
53
|
-
info 'Stopping services'
|
54
|
-
S_LOCKER.synchronize {SERVICES.each {|s, p| s.close rescue true; info "Stoped listening on port #{p[:port]}"}; SERVICES.clear }
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
data/lib/plezi/base/timers.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
|
2
|
-
module Plezi
|
3
|
-
|
4
|
-
module_function
|
5
|
-
|
6
|
-
#######################
|
7
|
-
## Timed Events / Multi-tasking
|
8
|
-
|
9
|
-
# DANGER ZONE - Plezi Engine. an Array containing all the current events.
|
10
|
-
TIMERS = []
|
11
|
-
# DANGER ZONE - Plezi Engine. the Mutex locker for the event machine.
|
12
|
-
T_LOCKER = Mutex.new
|
13
|
-
|
14
|
-
# This class is used by Plezi to hold events and push them into the events stack when the time comes.
|
15
|
-
class TimedEvent
|
16
|
-
|
17
|
-
def initialize seconds, repeat, handler, args, block
|
18
|
-
@time = Time.now + seconds
|
19
|
-
@seconds, @repeat, @handler, @args, @block = seconds, repeat, handler, args, block
|
20
|
-
end
|
21
|
-
|
22
|
-
def done?
|
23
|
-
return false unless @time <= Time.now
|
24
|
-
Plezi.push_event @handler, *@args, &@block
|
25
|
-
return true unless @repeat
|
26
|
-
@time = Time.now + @seconds
|
27
|
-
false
|
28
|
-
end
|
29
|
-
|
30
|
-
def stop_repeat
|
31
|
-
@repeat = false
|
32
|
-
end
|
33
|
-
|
34
|
-
attr_reader :timed
|
35
|
-
end
|
36
|
-
|
37
|
-
# returns true if there are any unhandled events
|
38
|
-
def timers?
|
39
|
-
T_LOCKER.synchronize {!TIMERS.empty?}
|
40
|
-
end
|
41
|
-
|
42
|
-
# pushes a timed event to the timers's stack
|
43
|
-
#
|
44
|
-
# accepts:
|
45
|
-
# seconds:: the minimal amount of seconds to wait before calling the handler's `call` method.
|
46
|
-
# handler:: an object that answers to `call`, usually a Proc or a method.
|
47
|
-
# *arg:: any arguments that will be passed to the handler's `call` method.
|
48
|
-
#
|
49
|
-
# if a block is passed along, it will be used as a callback: the block will be called with the values returned by the handler's `call` method.
|
50
|
-
def run_after seconds, handler, *args, &block
|
51
|
-
T_LOCKER.synchronize {TIMERS << TimedEvent.new(seconds, false, handler, args, block); TIMERS.last}
|
52
|
-
end
|
53
|
-
|
54
|
-
# pushes a repeated timed event to the timers's stack
|
55
|
-
#
|
56
|
-
# accepts:
|
57
|
-
# seconds:: the minimal amount of seconds to wait before calling the handler's `call` method.
|
58
|
-
# handler:: an object that answers to `call`, usually a Proc or a method.
|
59
|
-
# *arg:: any arguments that will be passed to the handler's `call` method.
|
60
|
-
#
|
61
|
-
# if a block is passed along, it will be used as a callback: the block will be called with the values returned by the handler's `call` method.
|
62
|
-
def run_every seconds, handler, *args, &block
|
63
|
-
T_LOCKER.synchronize {TIMERS << TimedEvent.new(seconds, true, handler, args, block); TIMERS.last}
|
64
|
-
end
|
65
|
-
|
66
|
-
# DANGER ZONE - Used by the Plezi engine to review timed events and push them to the event stack
|
67
|
-
def fire_timers
|
68
|
-
return false if T_LOCKER.locked?
|
69
|
-
T_LOCKER.synchronize { TIMERS.delete_if {|t| t.done? } }
|
70
|
-
end
|
71
|
-
end
|
data/lib/plezi/server/README.md
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# server object\file structure
|
2
|
-
|
3
|
-
- services
|
4
|
-
|
5
|
-
this folder holds the modules and classes regarding the core-services classes (normal TCP/IP service and SSL service should be here).
|
6
|
-
|
7
|
-
services have one protocol that parses incoming requests and one handler that takes the parsed request and responds to it.
|
8
|
-
|
9
|
-
both protocols and handlers can be changed mid-stream, allowing a service to switch protocols (such as from HTTP to WebSockets, HTTP/1.1 to SPDY etc') or a handler.
|
10
|
-
|
11
|
-
- protocols
|
12
|
-
|
13
|
-
this folder holds the different protocols that could be run over the each socket-service (HTTP / WebSockets etc' should be here).
|
14
|
-
|
15
|
-
the protocols are devided into two different classes/object types:
|
16
|
-
|
17
|
-
1. parsing input.
|
18
|
-
2. formatting output.
|
19
|
-
|
20
|
-
- handlers
|
21
|
-
|
22
|
-
this folder holds the classes and modules used to actually handle the requests parsed by the protocol layer.
|
23
|
-
|
24
|
-
these are the classes and modules the Plezi framework users (developers) connect with when writing their web apps.
|
25
|
-
|
26
|
-
## servers, services and protocols ... what?
|
27
|
-
|
28
|
-
services are the part of the server that recieves and sends data - services run specific protocols that together make up the whole of a server.
|
29
|
-
|
30
|
-
this division allows the user to change protocols mid-stream when allowed (such as switching from HTTP to WebSockets).
|
31
|
-
|
32
|
-
this abstraction to the sockets layer allows support for future or custom protocols without any changes to the abstraction layer.
|
33
|
-
|
@@ -1,224 +0,0 @@
|
|
1
|
-
module Plezi
|
2
|
-
|
3
|
-
# this class is a basic TCP socket service.
|
4
|
-
#
|
5
|
-
# a protocol should be assigned, or the service will fall back to an echo service.
|
6
|
-
#
|
7
|
-
# a protocol should answer to: on_connect(service), on_message(service, data), on_disconnect(service) and on_exception(service, exception)
|
8
|
-
#
|
9
|
-
# the on_message method should return any data that wasn't used (to be sent again as part of the next `on_message` call, once more data is received).
|
10
|
-
#
|
11
|
-
# if the protocol is a class, these methods should be instance methods.
|
12
|
-
# a protocol class should support the initialize(service, parameters={}) method as well.
|
13
|
-
#
|
14
|
-
# to-do: fix logging
|
15
|
-
class BasicService
|
16
|
-
|
17
|
-
# create a listener (io) - will create a TCPServer socket
|
18
|
-
#
|
19
|
-
# listeners are 'server sockets' that answer to `accept` by creating a new connection socket (io).
|
20
|
-
def self.create_service port, parameters
|
21
|
-
TCPServer.new(port)
|
22
|
-
end
|
23
|
-
|
24
|
-
# instance methods
|
25
|
-
|
26
|
-
attr_reader :socket, :locker, :closed, :parameters, :out_que, :active_time
|
27
|
-
attr_accessor :protocol, :handler, :timeout
|
28
|
-
|
29
|
-
# creates a new connection wrapper object for the new socket that was recieved from the `accept_nonblock` method call.
|
30
|
-
def initialize socket, parameters = {}
|
31
|
-
@handler = parameters[:handler]
|
32
|
-
@socket = socket
|
33
|
-
# 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'
|
34
|
-
@out_que = []
|
35
|
-
@locker = Mutex.new
|
36
|
-
@parameters = parameters
|
37
|
-
@protocol = parameters[:protocol]
|
38
|
-
@protocol = protocol.new self, parameters if protocol.is_a?(Class)
|
39
|
-
@protocol.on_connect self if @protocol && @protocol.methods.include?(:on_connect)
|
40
|
-
touch
|
41
|
-
@timeout ||= 5
|
42
|
-
# Plezi.callback self, :on_message
|
43
|
-
end
|
44
|
-
|
45
|
-
# # sets a connection timeout
|
46
|
-
# def set_timeout timeout = 8
|
47
|
-
# @timeout = timeout
|
48
|
-
# end
|
49
|
-
|
50
|
-
# checks if a connection timed out
|
51
|
-
def timedout?
|
52
|
-
Time.now - @active_time > @timeout
|
53
|
-
end
|
54
|
-
|
55
|
-
# resets the timer for the connection timeout
|
56
|
-
def touch
|
57
|
-
@active_time = Time.now
|
58
|
-
end
|
59
|
-
|
60
|
-
# 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).
|
61
|
-
def io
|
62
|
-
touch
|
63
|
-
@socket
|
64
|
-
end
|
65
|
-
|
66
|
-
# sends data immidiately - forcing the data to be sent, flushing any pending messages in the que
|
67
|
-
def send data = nil
|
68
|
-
return if @out_que.empty? && data.nil?
|
69
|
-
locker.synchronize do
|
70
|
-
unless @out_que.empty?
|
71
|
-
@out_que.each { |d| _send d rescue disconnect }
|
72
|
-
@out_que.clear
|
73
|
-
end
|
74
|
-
(_send data rescue disconnect) if data
|
75
|
-
touch
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# sends data immidiately, interrupting any pending que and ignoring thread safety.
|
80
|
-
def send_unsafe_interrupt data = nil
|
81
|
-
touch
|
82
|
-
_send data rescue disconnect
|
83
|
-
end
|
84
|
-
|
85
|
-
# sends data without waiting - data might be sent in a different order then intended.
|
86
|
-
def send_nonblock data
|
87
|
-
touch
|
88
|
-
locker.synchronize {@out_que << data}
|
89
|
-
Plezi.callback(self, :send)
|
90
|
-
end
|
91
|
-
|
92
|
-
# adds data to the out buffer - but doesn't send the data until a send event is called.
|
93
|
-
def << data
|
94
|
-
touch
|
95
|
-
locker.synchronize {@out_que << data}
|
96
|
-
end
|
97
|
-
|
98
|
-
# makes sure any data in the que is send and calls `flush` on the socket, to make sure the buffer is sent.
|
99
|
-
def flush
|
100
|
-
begin
|
101
|
-
send
|
102
|
-
socket.flush
|
103
|
-
rescue Exception => e
|
104
|
-
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# event based interface for messages.
|
109
|
-
|
110
|
-
# notice: since it is all async evet base - multipart messages might be garbled up...?
|
111
|
-
# todo: protect from garbeling.
|
112
|
-
def on_message
|
113
|
-
# return false if locker.locked?
|
114
|
-
return false if locker.locked?
|
115
|
-
begin
|
116
|
-
|
117
|
-
locker.synchronize do
|
118
|
-
return disconnect if _disconnected?
|
119
|
-
protocol.on_message(self)
|
120
|
-
end
|
121
|
-
|
122
|
-
rescue Exception => e
|
123
|
-
return disconnect
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# called once a socket is disconnected or needs to be disconnected.
|
128
|
-
def on_disconnect
|
129
|
-
Plezi.callback Plezi, :remove_connection, self
|
130
|
-
locker.synchronize do
|
131
|
-
@out_que.each { |d| _send d rescue true}
|
132
|
-
@out_que.clear
|
133
|
-
end
|
134
|
-
Plezi.callback protocol, :on_disconnect, self if protocol
|
135
|
-
close
|
136
|
-
end
|
137
|
-
|
138
|
-
# status markers
|
139
|
-
|
140
|
-
# closes the connection
|
141
|
-
def close
|
142
|
-
locker.synchronize do
|
143
|
-
_close rescue true
|
144
|
-
end
|
145
|
-
end
|
146
|
-
# returns true if the service is disconnected
|
147
|
-
def disconnected?
|
148
|
-
_disconnected?
|
149
|
-
end
|
150
|
-
# disconects the service.
|
151
|
-
def disconnect
|
152
|
-
Plezi.callback self, :on_disconnect
|
153
|
-
end
|
154
|
-
# returns true if the socket has content to be read.
|
155
|
-
def has_incoming_data?
|
156
|
-
(socket.stat.size > 0) rescue false
|
157
|
-
end
|
158
|
-
|
159
|
-
|
160
|
-
# identification markers
|
161
|
-
|
162
|
-
#returns the service type - set to normal
|
163
|
-
def service_type
|
164
|
-
'normal'
|
165
|
-
end
|
166
|
-
#returns true if the service is encrypted using the OpenSSL library.
|
167
|
-
def ssl?
|
168
|
-
false
|
169
|
-
end
|
170
|
-
|
171
|
-
#################
|
172
|
-
# overide the followind methods for any child class.
|
173
|
-
|
174
|
-
# this is a public method and it should be used by child classes to implement each
|
175
|
-
# read(_nonblock) action. accepts one argument ::size for an optional buffer size to be read.
|
176
|
-
def read size = 1048576
|
177
|
-
data = @socket.recv_nonblock( size )
|
178
|
-
touch unless data.nil? || data.empty?
|
179
|
-
return data
|
180
|
-
rescue Exception => e
|
181
|
-
return ''
|
182
|
-
end
|
183
|
-
|
184
|
-
protected
|
185
|
-
|
186
|
-
# this is a protected method, it should be used by child classes to implement each
|
187
|
-
# send action.
|
188
|
-
def _send data
|
189
|
-
# data.force_encoding "binary" rescue false
|
190
|
-
len = data.bytesize
|
191
|
-
act = @socket.send data, 0
|
192
|
-
while len > act
|
193
|
-
act += @socket.send data.byteslice(act..-1) , 0
|
194
|
-
touch
|
195
|
-
end
|
196
|
-
end
|
197
|
-
# this is a protected method, it should be used by child classes to implement each
|
198
|
-
# close action. doesn't accept any arguments.
|
199
|
-
def _close
|
200
|
-
socket.flush rescue true
|
201
|
-
socket.close
|
202
|
-
end
|
203
|
-
# this is a protected method, it should be used by child classes to tell if the socket
|
204
|
-
# was closed (returns true/false).
|
205
|
-
def _disconnected?
|
206
|
-
socket.closed? rescue true # || socket.stat.mode == 0140222 rescue true # if mode is read only, it's the same as closed.
|
207
|
-
end
|
208
|
-
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
|
213
|
-
######
|
214
|
-
## example requests
|
215
|
-
|
216
|
-
# GET /parsed_request HTTP/1.1
|
217
|
-
# Host: localhost:2000
|
218
|
-
# Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
219
|
-
# Cookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w
|
220
|
-
# User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25
|
221
|
-
# Accept-Language: en-us
|
222
|
-
# Accept-Encoding: gzip, deflate
|
223
|
-
# Connection: keep-alive
|
224
|
-
# X-Forwarded-For: 127.0.0.3
|