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