plezi 0.7.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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/CHANGELOG.md +450 -0
- data/Gemfile +4 -0
- data/KNOWN_ISSUES.md +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +341 -0
- data/Rakefile +2 -0
- data/TODO.md +19 -0
- data/bin/plezi +301 -0
- data/lib/plezi.rb +125 -0
- data/lib/plezi/base/cache.rb +77 -0
- data/lib/plezi/base/connections.rb +33 -0
- data/lib/plezi/base/dsl.rb +177 -0
- data/lib/plezi/base/engine.rb +85 -0
- data/lib/plezi/base/events.rb +84 -0
- data/lib/plezi/base/io_reactor.rb +41 -0
- data/lib/plezi/base/logging.rb +62 -0
- data/lib/plezi/base/rack_app.rb +89 -0
- data/lib/plezi/base/services.rb +57 -0
- data/lib/plezi/base/timers.rb +71 -0
- data/lib/plezi/handlers/controller_magic.rb +383 -0
- data/lib/plezi/handlers/http_echo.rb +27 -0
- data/lib/plezi/handlers/http_host.rb +215 -0
- data/lib/plezi/handlers/http_router.rb +69 -0
- data/lib/plezi/handlers/magic_helpers.rb +43 -0
- data/lib/plezi/handlers/route.rb +272 -0
- data/lib/plezi/handlers/stubs.rb +143 -0
- data/lib/plezi/server/README.md +33 -0
- data/lib/plezi/server/helpers/http.rb +169 -0
- data/lib/plezi/server/helpers/mime_types.rb +999 -0
- data/lib/plezi/server/protocols/http_protocol.rb +318 -0
- data/lib/plezi/server/protocols/http_request.rb +133 -0
- data/lib/plezi/server/protocols/http_response.rb +294 -0
- data/lib/plezi/server/protocols/websocket.rb +208 -0
- data/lib/plezi/server/protocols/ws_response.rb +92 -0
- data/lib/plezi/server/services/basic_service.rb +224 -0
- data/lib/plezi/server/services/no_service.rb +196 -0
- data/lib/plezi/server/services/ssl_service.rb +193 -0
- data/lib/plezi/version.rb +3 -0
- data/plezi.gemspec +26 -0
- data/resources/404.erb +68 -0
- data/resources/404.haml +64 -0
- data/resources/404.html +67 -0
- data/resources/404.slim +63 -0
- data/resources/500.erb +68 -0
- data/resources/500.haml +63 -0
- data/resources/500.html +67 -0
- data/resources/500.slim +63 -0
- data/resources/Gemfile +85 -0
- data/resources/anorexic_gray.png +0 -0
- data/resources/anorexic_websockets.html +47 -0
- data/resources/code.rb +8 -0
- data/resources/config.ru +39 -0
- data/resources/controller.rb +139 -0
- data/resources/db_ac_config.rb +58 -0
- data/resources/db_dm_config.rb +51 -0
- data/resources/db_sequel_config.rb +42 -0
- data/resources/en.yml +204 -0
- data/resources/environment.rb +41 -0
- data/resources/haml_config.rb +6 -0
- data/resources/i18n_config.rb +14 -0
- data/resources/rakefile.rb +22 -0
- data/resources/redis_config.rb +35 -0
- data/resources/routes.rb +26 -0
- data/resources/welcome_page.html +72 -0
- data/websocket chatroom.md +639 -0
- metadata +141 -0
data/lib/plezi.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
### Ruby core extentions
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'pathname'
|
5
|
+
require 'logger'
|
6
|
+
require 'socket'
|
7
|
+
require 'openssl'
|
8
|
+
require 'strscan'
|
9
|
+
require 'base64'
|
10
|
+
require 'digest/sha1'
|
11
|
+
require 'securerandom'
|
12
|
+
require 'time'
|
13
|
+
require 'json'
|
14
|
+
|
15
|
+
### version
|
16
|
+
|
17
|
+
require "plezi/version"
|
18
|
+
|
19
|
+
|
20
|
+
### Server requirements
|
21
|
+
|
22
|
+
require "plezi/server/services/basic_service"
|
23
|
+
require "plezi/server/services/ssl_service"
|
24
|
+
require "plezi/server/services/no_service"
|
25
|
+
|
26
|
+
require "plezi/server/protocols/http_protocol"
|
27
|
+
require 'plezi/server/protocols/http_request'
|
28
|
+
require 'plezi/server/protocols/http_response'
|
29
|
+
|
30
|
+
require "plezi/server/helpers/http"
|
31
|
+
require "plezi/server/helpers/mime_types"
|
32
|
+
|
33
|
+
require "plezi/server/protocols/websocket"
|
34
|
+
require 'plezi/server/protocols/ws_response'
|
35
|
+
|
36
|
+
## Server-Framework Bridges
|
37
|
+
require "plezi/handlers/http_echo"
|
38
|
+
require "plezi/handlers/http_host"
|
39
|
+
require "plezi/handlers/http_router"
|
40
|
+
|
41
|
+
require "plezi/handlers/controller_magic"
|
42
|
+
require "plezi/handlers/magic_helpers"
|
43
|
+
require "plezi/handlers/route"
|
44
|
+
|
45
|
+
require "plezi/handlers/stubs"
|
46
|
+
|
47
|
+
### Framework requirements
|
48
|
+
require "plezi/base/events"
|
49
|
+
require "plezi/base/timers"
|
50
|
+
require "plezi/base/services"
|
51
|
+
require "plezi/base/connections"
|
52
|
+
require "plezi/base/logging"
|
53
|
+
require "plezi/base/io_reactor"
|
54
|
+
require "plezi/base/cache"
|
55
|
+
require "plezi/base/engine"
|
56
|
+
|
57
|
+
### DSL requirements
|
58
|
+
require "plezi/base/dsl"
|
59
|
+
|
60
|
+
### optional Rack
|
61
|
+
require "plezi/base/rack_app"
|
62
|
+
|
63
|
+
## erb templating
|
64
|
+
begin
|
65
|
+
require 'erb'
|
66
|
+
rescue Exception => e
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
##############################################################################
|
73
|
+
# To make something new, we leap to the unknown.
|
74
|
+
##############################################################################
|
75
|
+
# Plezi is a stand alone web services app, which supports RESTful HTTP, HTTP Streaming and WebSockets.
|
76
|
+
#
|
77
|
+
# Plezi is a wonderful alternative to Socket.io which makes writing the server using Ruby a breeze.
|
78
|
+
#
|
79
|
+
# Plezi routes accept Regexp's (regular exceptions) for route paths. for example:
|
80
|
+
#
|
81
|
+
# require 'plezi'
|
82
|
+
# listen
|
83
|
+
# route(/[.]*/) {|request, response| response << "Your request, master: #{request.path}."}
|
84
|
+
#
|
85
|
+
# The catch-all route (/[.]*/) has a shortcut '*', so it's possible to write:
|
86
|
+
#
|
87
|
+
# require 'plezi'
|
88
|
+
# listen
|
89
|
+
# route('*') {|request, response| response << "Your request, master: #{request.path}."}
|
90
|
+
#
|
91
|
+
#
|
92
|
+
# Plezi accepts an optional class object that can be passed using the `route` command. Passing a class object is especially useful for RESTful and WebSocket applications.
|
93
|
+
# read more at the Plezi::StubWSCtrl and Plezi::StubRESTCtrl documentation, which are stub classes used for testing routes.
|
94
|
+
#
|
95
|
+
# require 'plezi'
|
96
|
+
# listen
|
97
|
+
# route "*", Plezi::StubRESTCtrl
|
98
|
+
#
|
99
|
+
# class routes that have a specific path (including root, but not a catch-all or Regexp path)
|
100
|
+
# accept an implied `params[:id]` variable. the following path ('/'):
|
101
|
+
#
|
102
|
+
# require 'plezi'
|
103
|
+
# listen
|
104
|
+
# route "/", Plezi::StubRESTCtrl
|
105
|
+
# # client requests: /1
|
106
|
+
# # => Plezi::StubRESTCtrl.new.show() # where params[:id] == 1
|
107
|
+
#
|
108
|
+
# it is possible to use "magic" routes (i.e. `/resource/:type/(:id)/(:date){/[0-9]{8}}/:foo`) and it is also possible to set the appropriate paramaters within the `before` method of the Conltroller.
|
109
|
+
#
|
110
|
+
# Routes are handled in the order they are created. If overlapping routes exist, the first will execute first:
|
111
|
+
#
|
112
|
+
# require 'plezi'
|
113
|
+
# listen
|
114
|
+
# route('*') do |request, response|
|
115
|
+
# response << "Your request, master: #{request.path}." unless request.path.match /cats/
|
116
|
+
# end
|
117
|
+
# route('*') {|request, response| response.body << "Ahhh... I love cats!"}
|
118
|
+
#
|
119
|
+
# all the examples above shuold be good to run from irb. updated examples can be found at the Readme file in the Github project: https://github.com/boazsegev/plezi
|
120
|
+
#
|
121
|
+
# thanks to Russ Olsen for his ideas for a DSL and his blog post at:
|
122
|
+
# http://www.jroller.com/rolsen/entry/building_a_dsl_in_ruby1
|
123
|
+
##############################################################################
|
124
|
+
module Plezi
|
125
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
module Plezi
|
3
|
+
|
4
|
+
# File and Object Caching for Plezi
|
5
|
+
module_function
|
6
|
+
# contains the cached data, in the format: CACHE_STORE["filename"] = CacheObject
|
7
|
+
CACHE_STORE = {}
|
8
|
+
LOCK = Mutex.new
|
9
|
+
CACHABLE = %w{cache object slim haml css map js html scss sass coffee txt xml json yaml rb}
|
10
|
+
|
11
|
+
@cache_to_disk = true
|
12
|
+
|
13
|
+
# this class holds cached objects (data and modification times)
|
14
|
+
class CacheObject
|
15
|
+
# Cached attributes
|
16
|
+
attr_accessor :data, :mtime
|
17
|
+
|
18
|
+
# initialize a Cached object
|
19
|
+
def initialize d = nil, t = Time.now
|
20
|
+
@data, @mtime = d, t
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# load the file from the cache (if exists) or the file system (if it doesn't)
|
25
|
+
def load_file filename
|
26
|
+
cached?(filename) ? get_cached(filename) : reload_file(filename)
|
27
|
+
end
|
28
|
+
# review a file's modification time
|
29
|
+
def file_mtime filename
|
30
|
+
return CACHE_STORE[filename].mtime if cached?(filename)
|
31
|
+
File.mtime(filename)
|
32
|
+
end
|
33
|
+
|
34
|
+
# force a file onto the cache (only if it is cachable - otherwise will load the file but will not cache it).
|
35
|
+
def reload_file filename
|
36
|
+
if CACHABLE.include? filename.match(/\.([^\.]+)$/)[1]
|
37
|
+
return cache_data filename, IO.read(filename), File.mtime(filename)
|
38
|
+
else
|
39
|
+
return IO.read(filename)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
# places data into the cache, and attempts to save the data to a file name.
|
43
|
+
def save_file filename, data, save_to_disk = false
|
44
|
+
cache_data filename, data if CACHABLE.include? filename.match(/\.([^\.]+)$/)[1]
|
45
|
+
begin
|
46
|
+
IO.write filename, data if save_to_disk
|
47
|
+
rescue Exception => e
|
48
|
+
Plezi.warn("File couldn't be written (#{filename}) - file system error?")
|
49
|
+
end
|
50
|
+
data
|
51
|
+
end
|
52
|
+
# places data into the cache, under an identifier ( file name ).
|
53
|
+
def cache_data filename, data, mtime = Time.now
|
54
|
+
LOCK.synchronize { CACHE_STORE[filename] = CacheObject.new( data, mtime ) }
|
55
|
+
data
|
56
|
+
end
|
57
|
+
# Get data from the cache. will throw an exception if there is no data in the cache.
|
58
|
+
def get_cached filename
|
59
|
+
CACHE_STORE[filename].data # if CACHE_STORE[filename]
|
60
|
+
end
|
61
|
+
|
62
|
+
# returns true if the filename is cached.
|
63
|
+
def cached? filename
|
64
|
+
!CACHE_STORE[filename].nil?
|
65
|
+
end
|
66
|
+
|
67
|
+
# returns true if the file exists on disk or in the cache.
|
68
|
+
def file_exists? filename
|
69
|
+
(CACHE_STORE[filename] || File.exists?(filename)) ? true : false
|
70
|
+
end
|
71
|
+
|
72
|
+
# returns true if the file has been update since data was last cached.
|
73
|
+
def cache_needs_update? filename
|
74
|
+
return true if CACHE_STORE[filename].nil? || CACHE_STORE[filename].mtime < File.mtime(filename)
|
75
|
+
false
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
module Plezi
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# DANGER ZONE - Plezi Engine. the connections store
|
7
|
+
IO_CONNECTION_DIC = {}
|
8
|
+
# DANGER ZONE - Plezi Engine. the connections mutex
|
9
|
+
C_LOCKER = Mutex.new
|
10
|
+
|
11
|
+
# Plezi Engine, DO NOT CALL. disconnectes all active connections
|
12
|
+
def stop_connections
|
13
|
+
log 'Stopping connections'
|
14
|
+
C_LOCKER.synchronize {IO_CONNECTION_DIC.values.each {|c| c.timeout = -1; callback c, :on_disconnect unless c.disconnected?} ; IO_CONNECTION_DIC.clear}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Plezi Engine, DO NOT CALL. adds a new connection to the connection stack
|
18
|
+
def add_connection io, params
|
19
|
+
connection = params[:service_type].new(io, params)
|
20
|
+
C_LOCKER.synchronize {IO_CONNECTION_DIC[connection.socket] = connection} if connection
|
21
|
+
callback(connection, :on_message)
|
22
|
+
end
|
23
|
+
# Plezi Engine, DO NOT CALL. removes a connection from the connection stack
|
24
|
+
def remove_connection connection
|
25
|
+
C_LOCKER.synchronize { IO_CONNECTION_DIC.delete connection.socket }
|
26
|
+
end
|
27
|
+
|
28
|
+
# clears closed connections from the stack
|
29
|
+
def clear_connections
|
30
|
+
C_LOCKER.synchronize { IO_CONNECTION_DIC.values.each {|c| callback c, :on_disconnect if c.disconnected? || c.timedout? } }
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
|
2
|
+
module Plezi
|
3
|
+
|
4
|
+
# this module contains the methods that are used as a DSL and sets up easy access to the Plezi framework.
|
5
|
+
#
|
6
|
+
# use the`listen`, `host` and `route` functions rather then accessing this object.
|
7
|
+
#
|
8
|
+
module DSL
|
9
|
+
module_function
|
10
|
+
|
11
|
+
@servers = {}
|
12
|
+
@active_router = nil
|
13
|
+
|
14
|
+
# adds a server (performs the action required by the listen method).
|
15
|
+
#
|
16
|
+
# accepts:
|
17
|
+
# port:: (optional) the port number for the service. if not defined, defaultes to the -p runtime argument (i.e. `./app.rb -p 8080`) or to 3000 if argument is missing.
|
18
|
+
# params:: any parameter accepted by the Plezi.add_service method. defaults to: `:protocol=>Plezi::HTTPProtocol, :handler => HTTPRouter.new`
|
19
|
+
def listen(port, params = {})
|
20
|
+
# set port and arguments
|
21
|
+
if port.is_a?(Hash)
|
22
|
+
params = port
|
23
|
+
port = nil
|
24
|
+
end
|
25
|
+
if !port && defined? ARGV
|
26
|
+
if ARGV.find_index('-p')
|
27
|
+
port_index = ARGV.find_index('-p') + 1
|
28
|
+
port ||= ARGV[port_index].to_i
|
29
|
+
ARGV[port_index] = (port + 1).to_s
|
30
|
+
else
|
31
|
+
ARGV << '-p'
|
32
|
+
ARGV << '3000'
|
33
|
+
return listen nil, params
|
34
|
+
end
|
35
|
+
end
|
36
|
+
port ||= 3000
|
37
|
+
|
38
|
+
# create new service or choose existing
|
39
|
+
if @servers[port]
|
40
|
+
puts "WARNING: port aleady in use! returning existing service and attemptin to add host (maybe multiple hosts? use `host` instead)." unless params[:host]
|
41
|
+
@active_router = @servers[port][:handler]
|
42
|
+
@active_router.add_host params[:host], params
|
43
|
+
return @active_router
|
44
|
+
end
|
45
|
+
params[:protocol] ||= HTTPProtocol
|
46
|
+
@active_router = params[:handler] ||= HTTPRouter.new # HTTPEcho #
|
47
|
+
@active_router.add_host params[:host], params
|
48
|
+
return false unless Plezi.add_service(port, params)
|
49
|
+
@servers[port] = params
|
50
|
+
@active_router
|
51
|
+
end
|
52
|
+
|
53
|
+
# adds a route to the last server created
|
54
|
+
def route(path, controller = nil, &block)
|
55
|
+
@active_router.add_route path, controller, &block
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# adds a shared route to all existing services and hosts.
|
60
|
+
def shared_route(path, controller = nil, &block)
|
61
|
+
@servers.values.each {|p| p[:handler].add_shared_route path, controller, &block }
|
62
|
+
end
|
63
|
+
|
64
|
+
# adds a host to the last server created
|
65
|
+
#
|
66
|
+
# accepts the same parameter(s) as the `listen` command (see Plezi.add_service), except :protocol and :handler are ignored:
|
67
|
+
# alias:: a String or an Array of Strings which represent alternative host names (i.e. `alias: ["admin.google.com", "admin.gmail.com"]`).
|
68
|
+
def host(host_name, params)
|
69
|
+
@active_router.add_host host_name, params
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Encoding.default_internal = 'utf-8'
|
75
|
+
Encoding.default_external = 'utf-8'
|
76
|
+
|
77
|
+
# Set a shortcut for the Plezi module.
|
78
|
+
PL = Plezi
|
79
|
+
|
80
|
+
# creates a server object and waits for routes to be set.
|
81
|
+
#
|
82
|
+
# port:: the port to listen to. the first port defaults to 3000 and increments by 1 with every `listen` call. it's possible to set the first port number by running the app with the -p paramater.
|
83
|
+
# params:: a Hash of serever paramaters, as listed in the Plezi#add_service documentation.
|
84
|
+
#
|
85
|
+
# The different keys in the params hash control the server's behaviour, as follows:
|
86
|
+
#
|
87
|
+
# host:: the host name. defaults to any host not explicitly defined (a catch-all).
|
88
|
+
# alias:: a String or an Array of Strings which represent alternative host names (i.e. `alias: ["admin.google.com", "admin.gmail.com"]`).
|
89
|
+
# root:: the public root folder. if this is defined, static files will be served from the location.
|
90
|
+
# 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).
|
91
|
+
# 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.
|
92
|
+
# 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`.
|
93
|
+
# save_assets:: saves the rendered assets to the filesystem, under the public folder. defaults to false.
|
94
|
+
# templates:: the templates root folder. defaults to nil (no template support). templates can be rendered by a Controller class, using the `render` method.
|
95
|
+
# 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.
|
96
|
+
# ssl_key:: the public key for the SSL service.
|
97
|
+
# ssl_cert:: the certificate for the SSL service.
|
98
|
+
#
|
99
|
+
def listen(port = nil, params = {})
|
100
|
+
Plezi::DSL.listen port, params
|
101
|
+
end
|
102
|
+
|
103
|
+
# adds a virtul host to the current service (the last `listen` call) or switches to an existing host within the active service.
|
104
|
+
#
|
105
|
+
# accepts:
|
106
|
+
# host_name: a String with the full host name (i.e. "www.google.com" / "mail.google.com")
|
107
|
+
# params:: any of the parameters accepted by the `listen` command, except `protocol`, `handler`, and `ssl` parameters.
|
108
|
+
def host(host_name = false, params = {})
|
109
|
+
Plezi::DSL.host host_name, params
|
110
|
+
end
|
111
|
+
|
112
|
+
# adds a route to the last server object
|
113
|
+
#
|
114
|
+
# path:: the path for the route
|
115
|
+
# controller:: The controller class which will accept the route.
|
116
|
+
#
|
117
|
+
# `path` paramaters has a few options:
|
118
|
+
#
|
119
|
+
# * `path` can be a Regexp object, forcing the all the logic into controller (typically using the before method).
|
120
|
+
#
|
121
|
+
# * simple String paths are assumed to be basic RESTful paths:
|
122
|
+
#
|
123
|
+
# route "/users", Controller => route "/users/(:id)", Controller
|
124
|
+
#
|
125
|
+
# * routes can define their own parameters, for their own logic:
|
126
|
+
#
|
127
|
+
# route "/path/:required_paramater/:required_paramater{with_format}/(:optional_paramater)/(:optional){with_format}"
|
128
|
+
#
|
129
|
+
# * routes can define optional or required routes with regular expressions in them:
|
130
|
+
#
|
131
|
+
# route "(:locale){en|ru}/path"
|
132
|
+
#
|
133
|
+
# * routes which use the special '/' charecter within a parameter's format, must escape this charecter using the '\' charecter. **Notice the single quotes** in the following example:
|
134
|
+
#
|
135
|
+
# route '(:math){[\d\+\-\*\^\%\.\/]}'
|
136
|
+
#
|
137
|
+
# * or, with double quotes:
|
138
|
+
#
|
139
|
+
# route "(:math){[\\d\\+\\-\\*\\^\\%\\.\\/]}"
|
140
|
+
#
|
141
|
+
# magic routes make for difficult debugging - the smarter the routes, the more difficult the debugging.
|
142
|
+
# use with care and avoid complex routes when possible. RESTful routes are recommended when possible.
|
143
|
+
# json serving apps are advised to use required paramaters, empty sections indicating missing required paramaters (i.e. /path///foo/bar///).
|
144
|
+
#
|
145
|
+
def route(path, controller = nil, &block)
|
146
|
+
Plezi::DSL.route(path, controller, &block)
|
147
|
+
end
|
148
|
+
|
149
|
+
# adds a route to the all the existing servers and hosts.
|
150
|
+
#
|
151
|
+
# accepts same options as route.
|
152
|
+
def shared_route(path, controller = nil, &block)
|
153
|
+
Plezi::DSL.shared_route(path, controller, &block)
|
154
|
+
end
|
155
|
+
|
156
|
+
# finishes setup of the servers and starts them up. This will hange the proceess.
|
157
|
+
#
|
158
|
+
# this method is called automatically by the Plezi framework.
|
159
|
+
#
|
160
|
+
# it is recommended that you DO NOT CALL this method.
|
161
|
+
# if any post shut-down actions need to be performed, use Plezi.on_shutdown instead.
|
162
|
+
def start_services
|
163
|
+
return 0 if ( defined?(NO_PLEZI_AUTO_START) || defined?(BUILDING_PLEZI_TEMPLATE) || defined?(PLEZI_ON_RACK) )
|
164
|
+
Object.const_set "NO_PLEZI_AUTO_START", true
|
165
|
+
undef listen
|
166
|
+
undef host
|
167
|
+
undef route
|
168
|
+
undef shared_route
|
169
|
+
undef start_services
|
170
|
+
Plezi.start_services
|
171
|
+
end
|
172
|
+
|
173
|
+
# sets to start the services once dsl script is finished loading.
|
174
|
+
at_exit { start_services } unless ( defined?(NO_PLEZI_AUTO_START) || defined?(BUILDING_PLEZI_TEMPLATE) || defined?(PLEZI_ON_RACK) )
|
175
|
+
|
176
|
+
# sets a name for the process (on some systems).
|
177
|
+
$0="Plezi (Ruby)"
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
module Plezi
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Plezi event cycle settings: gets how many worker threads Plezi will run.
|
7
|
+
def max_threads
|
8
|
+
@max_threads ||= 16
|
9
|
+
end
|
10
|
+
# Plezi event cycle settings: sets how many worker threads Plezi will run.
|
11
|
+
def max_threads= value
|
12
|
+
@max_threads = value
|
13
|
+
end
|
14
|
+
|
15
|
+
# Plezi event cycle settings: how long to wait for IO activity before forcing another cycle.
|
16
|
+
#
|
17
|
+
# No timing methods will be called during this interval.
|
18
|
+
#
|
19
|
+
# get the current idle setting
|
20
|
+
def idle_sleep
|
21
|
+
@idle_sleep ||= 0.1
|
22
|
+
end
|
23
|
+
# Plezi event cycle settings: how long to wait for IO activity before forcing another cycle.
|
24
|
+
#
|
25
|
+
# No timing methods will be called during this interval.
|
26
|
+
#
|
27
|
+
# set the current idle setting
|
28
|
+
def idle_sleep= value
|
29
|
+
@idle_sleep = value
|
30
|
+
end
|
31
|
+
|
32
|
+
# Plezi Engine, DO NOT CALL. creates the thread pool and starts cycling through the events.
|
33
|
+
def start_services
|
34
|
+
# prepare threads
|
35
|
+
exit_flag = false
|
36
|
+
threads = []
|
37
|
+
run_every(5 , Plezi.method(:clear_connections)) #{info "Cleared inactive Connections"}
|
38
|
+
run_every 3600 , GC.method(:start)
|
39
|
+
# 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)." })
|
40
|
+
(max_threads).times { Thread.new { thread_cycle until exit_flag } }
|
41
|
+
|
42
|
+
# Thread.new { check_connections until SERVICES.empty? }
|
43
|
+
#...
|
44
|
+
# set signal tarps
|
45
|
+
trap('INT'){ exit_flag = true; raise "close Plezi" }
|
46
|
+
trap('TERM'){ exit_flag = true; raise "close Plezi" }
|
47
|
+
puts 'Services running. Press ^C to stop'
|
48
|
+
# sleep until trap raises exception (cycling might cause the main thread to ignor signals and lose attention)
|
49
|
+
(sleep unless SERVICES.empty?) rescue true
|
50
|
+
# start shutdown.
|
51
|
+
exit_flag = true
|
52
|
+
# set new tarps
|
53
|
+
trap('INT'){ puts 'Forced exit.'; Kernel.exit }#rescue true}
|
54
|
+
trap('TERM'){ puts 'Forced exit.'; Kernel.exit }#rescue true }
|
55
|
+
puts 'Started shutdown process. Press ^C to force quit.'
|
56
|
+
# shut down listening sockets
|
57
|
+
stop_services
|
58
|
+
# disconnect active connections
|
59
|
+
stop_connections
|
60
|
+
# cycle down threads
|
61
|
+
info "Waiting for workers to cycle down"
|
62
|
+
threads.each {|t| t.join if t.alive?}
|
63
|
+
|
64
|
+
# rundown any active events
|
65
|
+
thread_cycle
|
66
|
+
|
67
|
+
# call shutdown callbacks
|
68
|
+
SHUTDOWN_CALLBACKS.each {|s| s[0].call(*s[1]) }
|
69
|
+
SHUTDOWN_CALLBACKS.clear
|
70
|
+
|
71
|
+
# return exit code?
|
72
|
+
0
|
73
|
+
end
|
74
|
+
|
75
|
+
# Plezi Engine, DO NOT CALL. runs one thread cycle
|
76
|
+
def self.thread_cycle flag = 0
|
77
|
+
io_reactor rescue false # stop_connections
|
78
|
+
true while fire_event
|
79
|
+
fire_timers
|
80
|
+
|
81
|
+
rescue Exception => e
|
82
|
+
|
83
|
+
error e
|
84
|
+
end
|
85
|
+
end
|