plezi 0.12.22 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/LICENSE.txt +17 -18
- data/README.md +54 -698
- data/Rakefile +7 -4
- data/bin/config.ru +22 -0
- data/{test → bin}/console +4 -6
- data/bin/hello_world +52 -0
- data/bin/setup +8 -0
- data/exe/plezi +145 -0
- data/lib/plezi.rb +24 -137
- data/lib/plezi/activation.rb +28 -0
- data/lib/plezi/api.rb +62 -0
- data/lib/plezi/controller/controller.rb +259 -0
- data/lib/plezi/controller/controller_class.rb +176 -0
- data/lib/plezi/controller/cookies.rb +40 -0
- data/lib/plezi/helpers.rb +60 -0
- data/lib/plezi/rake.rb +2 -24
- data/lib/plezi/render/erb.rb +34 -0
- data/lib/plezi/render/has_cache.rb +36 -0
- data/lib/plezi/render/markdown.rb +63 -0
- data/lib/plezi/render/render.rb +49 -0
- data/lib/plezi/render/sass.rb +55 -0
- data/lib/plezi/render/slim.rb +33 -0
- data/lib/plezi/router/adclient.rb +23 -0
- data/lib/plezi/router/assets.rb +67 -0
- data/lib/plezi/router/errors.rb +29 -0
- data/lib/plezi/router/route.rb +112 -0
- data/lib/plezi/router/router.rb +120 -0
- data/lib/plezi/version.rb +1 -1
- data/lib/plezi/websockets/message_dispatch.rb +91 -0
- data/lib/plezi/websockets/redis.rb +55 -0
- data/plezi.gemspec +25 -16
- data/resources/404.erb +5 -4
- data/resources/500.erb +5 -4
- data/resources/{500.html → 503.html} +8 -9
- data/resources/client.js +253 -0
- data/resources/config.ru +5 -36
- data/resources/ctrlr.rb +34 -0
- data/resources/gemfile +4 -0
- data/resources/mini_app.rb +28 -82
- data/resources/mini_exec +7 -0
- data/resources/mini_welcome_page.html +0 -0
- data/resources/procfile +3 -0
- data/resources/rakefile +4 -8
- data/resources/routes.rb +9 -26
- data/resources/{websockets.js → simple-client.js} +3 -3
- metadata +60 -85
- data/bin/plezi +0 -104
- data/docs/async_helpers.md +0 -245
- data/docs/controllers.md +0 -27
- data/docs/logging.md +0 -49
- data/docs/routes.md +0 -209
- data/docs/websockets.md +0 -213
- data/lib/plezi/builders/ac_model.rb +0 -59
- data/lib/plezi/builders/app_builder.rb +0 -137
- data/lib/plezi/builders/builder.rb +0 -43
- data/lib/plezi/builders/form_builder.rb +0 -27
- data/lib/plezi/common/api.rb +0 -92
- data/lib/plezi/common/cache.rb +0 -122
- data/lib/plezi/common/defer.rb +0 -21
- data/lib/plezi/common/dsl.rb +0 -94
- data/lib/plezi/common/redis.rb +0 -65
- data/lib/plezi/common/renderer.rb +0 -141
- data/lib/plezi/common/settings.rb +0 -52
- data/lib/plezi/handlers/controller_core.rb +0 -106
- data/lib/plezi/handlers/controller_magic.rb +0 -284
- data/lib/plezi/handlers/http_router.rb +0 -205
- data/lib/plezi/handlers/placebo.rb +0 -112
- data/lib/plezi/handlers/route.rb +0 -216
- data/lib/plezi/handlers/session.rb +0 -109
- data/lib/plezi/handlers/stubs.rb +0 -156
- data/lib/plezi/handlers/ws_identity.rb +0 -253
- data/lib/plezi/handlers/ws_object.rb +0 -308
- data/lib/plezi/helpers/http_sender.rb +0 -84
- data/lib/plezi/helpers/magic_helpers.rb +0 -104
- data/lib/plezi/helpers/mime_types.rb +0 -1995
- data/lib/plezi/oauth.rb +0 -5
- data/lib/plezi/oauth/auth_controller.rb +0 -229
- data/logo/dark.png +0 -0
- data/logo/light.png +0 -0
- data/logo/sign.png +0 -0
- data/resources/404.haml +0 -121
- data/resources/404.html +0 -124
- data/resources/404.slim +0 -120
- data/resources/500.haml +0 -120
- data/resources/500.slim +0 -120
- data/resources/Gemfile +0 -86
- data/resources/code.rb +0 -8
- data/resources/controller.rb +0 -142
- data/resources/database.yml +0 -33
- data/resources/db_ac_config.rb +0 -59
- data/resources/db_dm_config.rb +0 -51
- data/resources/db_sequel_config.rb +0 -33
- data/resources/en.yml +0 -204
- data/resources/haml_config.rb +0 -6
- data/resources/i18n_config.rb +0 -14
- data/resources/initialize.rb +0 -49
- data/resources/mini_exec.rb +0 -7
- data/resources/oauth_config.rb +0 -24
- data/resources/plezi_client.js +0 -198
- data/resources/plezi_websockets.html +0 -47
- data/resources/redis_config.rb +0 -42
- data/resources/slim_config.rb +0 -11
- data/resources/welcome_page.html +0 -272
- data/test/dispatch +0 -58
- data/test/hello_world +0 -13
- data/test/plezi_tests.rb +0 -581
data/resources/mini_exec
ADDED
File without changes
|
data/resources/procfile
ADDED
data/resources/rakefile
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
# load all application code and gems
|
2
|
-
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.require(:default, ENV['ENV'].to_s.to_sym)
|
3
4
|
# set Plezi to rake mode and load it's tasks (if relevant).
|
4
|
-
|
5
|
+
Plezi.no_autostart
|
5
6
|
|
6
|
-
#
|
7
|
-
desc "The default task will simply remind you to call 'rake -T'."
|
8
|
-
task :default do
|
9
|
-
puts "I don't know what to do. Please choose a task..."
|
10
|
-
puts "You can print a list of all avaiulable tasks using: rake -T"
|
11
|
-
end
|
7
|
+
# Add your tasks
|
data/resources/routes.rb
CHANGED
@@ -1,31 +1,14 @@
|
|
1
|
-
|
2
|
-
#
|
1
|
+
################
|
2
|
+
# # Place your application routes here.
|
3
|
+
# #
|
4
|
+
# # Add your routes and controllers by order of priority.
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
## This file holds the routes for your application
|
7
|
-
##
|
8
|
-
## use the `host`, `route` and `shared_route` functions
|
9
|
-
##
|
6
|
+
# # I18n re-write, i.e.: `/en/home` will be rewriten as `/home`, while setting params['locale'] to "en"
|
7
|
+
# Plezi.route "/:locale" , /^(#{I18n.available_locales.join "|"})$/ if defined? I18n
|
10
8
|
|
11
|
-
|
12
|
-
# This is an optional re-write route for I18n.
|
13
|
-
# i.e.: `/en/home` will be rewriten as `/home`, while setting params[:locale] to "en"
|
14
|
-
route "/:locale{#{I18n.available_locales.join "|"}}/*" , false if defined? I18n
|
15
|
-
|
16
|
-
# # This is an optional re-write route response formats.
|
17
9
|
# # Response format re-write, i.e.: `/xml/home` will use .xml templates automatically
|
18
10
|
# # with :locale a request might look like `/en/json/...`
|
19
|
-
# route "/:format
|
20
|
-
|
21
|
-
###
|
22
|
-
# add your routes here:
|
23
|
-
|
24
|
-
|
25
|
-
# remove this demo route and the SampleController once you want to feed Plezi your code.
|
26
|
-
route '/', SampleController
|
27
|
-
|
11
|
+
# Plezi.route "/:format" , /^(html|json|xml)$/
|
28
12
|
|
29
|
-
#
|
30
|
-
|
31
|
-
# route '*', Plezi::StubRESTCtrl
|
13
|
+
# The root Controller
|
14
|
+
Plezi.route '/', RootController
|
@@ -7,8 +7,8 @@
|
|
7
7
|
|
8
8
|
// Your websocket URI should be an absolute path. The following sets the base URI.
|
9
9
|
// remember to update to the specific controller's path to your websocket URI.
|
10
|
-
var ws_controller_path =
|
11
|
-
var ws_uri = (
|
10
|
+
var ws_controller_path = windselfow.location.pathname; // change to '/controller/path'
|
11
|
+
var ws_uri = (self.location.protocol.match(/https/) ? 'wss' : 'ws') + '://' + self.document.location.host + ws_controller_path
|
12
12
|
// websocket variable.
|
13
13
|
var websocket = NaN
|
14
14
|
// count failed attempts
|
@@ -55,4 +55,4 @@ function init_websocket()
|
|
55
55
|
};
|
56
56
|
}
|
57
57
|
// setup the websocket connection once the page is done loading
|
58
|
-
|
58
|
+
self.addEventListener("load", init_websocket, false);
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plezi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: iodine
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.2.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.2.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.12'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.12'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,10 +52,23 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '10.0'
|
55
|
-
|
56
|
-
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.0'
|
69
|
+
description: The Plezi.io Ruby Framework for real time web applications.
|
57
70
|
email:
|
58
|
-
-
|
71
|
+
- bo@plezi.io
|
59
72
|
executables:
|
60
73
|
- plezi
|
61
74
|
extensions: []
|
@@ -68,86 +81,54 @@ files:
|
|
68
81
|
- LICENSE.txt
|
69
82
|
- README.md
|
70
83
|
- Rakefile
|
71
|
-
- bin/
|
72
|
-
-
|
73
|
-
-
|
74
|
-
-
|
75
|
-
-
|
76
|
-
- docs/websockets.md
|
84
|
+
- bin/config.ru
|
85
|
+
- bin/console
|
86
|
+
- bin/hello_world
|
87
|
+
- bin/setup
|
88
|
+
- exe/plezi
|
77
89
|
- lib/plezi.rb
|
78
|
-
- lib/plezi/
|
79
|
-
- lib/plezi/
|
80
|
-
- lib/plezi/
|
81
|
-
- lib/plezi/
|
82
|
-
- lib/plezi/
|
83
|
-
- lib/plezi/
|
84
|
-
- lib/plezi/common/defer.rb
|
85
|
-
- lib/plezi/common/dsl.rb
|
86
|
-
- lib/plezi/common/redis.rb
|
87
|
-
- lib/plezi/common/renderer.rb
|
88
|
-
- lib/plezi/common/settings.rb
|
89
|
-
- lib/plezi/handlers/controller_core.rb
|
90
|
-
- lib/plezi/handlers/controller_magic.rb
|
91
|
-
- lib/plezi/handlers/http_router.rb
|
92
|
-
- lib/plezi/handlers/placebo.rb
|
93
|
-
- lib/plezi/handlers/route.rb
|
94
|
-
- lib/plezi/handlers/session.rb
|
95
|
-
- lib/plezi/handlers/stubs.rb
|
96
|
-
- lib/plezi/handlers/ws_identity.rb
|
97
|
-
- lib/plezi/handlers/ws_object.rb
|
98
|
-
- lib/plezi/helpers/http_sender.rb
|
99
|
-
- lib/plezi/helpers/magic_helpers.rb
|
100
|
-
- lib/plezi/helpers/mime_types.rb
|
101
|
-
- lib/plezi/oauth.rb
|
102
|
-
- lib/plezi/oauth/auth_controller.rb
|
90
|
+
- lib/plezi/activation.rb
|
91
|
+
- lib/plezi/api.rb
|
92
|
+
- lib/plezi/controller/controller.rb
|
93
|
+
- lib/plezi/controller/controller_class.rb
|
94
|
+
- lib/plezi/controller/cookies.rb
|
95
|
+
- lib/plezi/helpers.rb
|
103
96
|
- lib/plezi/rake.rb
|
97
|
+
- lib/plezi/render/erb.rb
|
98
|
+
- lib/plezi/render/has_cache.rb
|
99
|
+
- lib/plezi/render/markdown.rb
|
100
|
+
- lib/plezi/render/render.rb
|
101
|
+
- lib/plezi/render/sass.rb
|
102
|
+
- lib/plezi/render/slim.rb
|
103
|
+
- lib/plezi/router/adclient.rb
|
104
|
+
- lib/plezi/router/assets.rb
|
105
|
+
- lib/plezi/router/errors.rb
|
106
|
+
- lib/plezi/router/route.rb
|
107
|
+
- lib/plezi/router/router.rb
|
104
108
|
- lib/plezi/version.rb
|
105
|
-
-
|
106
|
-
-
|
107
|
-
- logo/sign.png
|
109
|
+
- lib/plezi/websockets/message_dispatch.rb
|
110
|
+
- lib/plezi/websockets/redis.rb
|
108
111
|
- plezi.gemspec
|
109
112
|
- resources/404.erb
|
110
|
-
- resources/404.haml
|
111
|
-
- resources/404.html
|
112
|
-
- resources/404.slim
|
113
113
|
- resources/500.erb
|
114
|
-
- resources/
|
115
|
-
- resources/
|
116
|
-
- resources/500.slim
|
117
|
-
- resources/Gemfile
|
118
|
-
- resources/code.rb
|
114
|
+
- resources/503.html
|
115
|
+
- resources/client.js
|
119
116
|
- resources/config.ru
|
120
|
-
- resources/
|
121
|
-
- resources/
|
122
|
-
- resources/db_ac_config.rb
|
123
|
-
- resources/db_dm_config.rb
|
124
|
-
- resources/db_sequel_config.rb
|
125
|
-
- resources/en.yml
|
126
|
-
- resources/haml_config.rb
|
127
|
-
- resources/i18n_config.rb
|
128
|
-
- resources/initialize.rb
|
117
|
+
- resources/ctrlr.rb
|
118
|
+
- resources/gemfile
|
129
119
|
- resources/mini_app.rb
|
130
|
-
- resources/mini_exec
|
120
|
+
- resources/mini_exec
|
131
121
|
- resources/mini_welcome_page.html
|
132
|
-
- resources/
|
133
|
-
- resources/plezi_client.js
|
134
|
-
- resources/plezi_websockets.html
|
122
|
+
- resources/procfile
|
135
123
|
- resources/rakefile
|
136
|
-
- resources/redis_config.rb
|
137
124
|
- resources/routes.rb
|
138
|
-
- resources/
|
139
|
-
|
140
|
-
- resources/welcome_page.html
|
141
|
-
- test/console
|
142
|
-
- test/dispatch
|
143
|
-
- test/hello_world
|
144
|
-
- test/plezi_tests.rb
|
145
|
-
homepage: http://www.plezi.io/
|
125
|
+
- resources/simple-client.js
|
126
|
+
homepage: http://plezi.io
|
146
127
|
licenses:
|
147
128
|
- MIT
|
148
|
-
metadata:
|
149
|
-
|
150
|
-
|
129
|
+
metadata:
|
130
|
+
allowed_push_host: https://rubygems.org
|
131
|
+
post_install_message:
|
151
132
|
rdoc_options: []
|
152
133
|
require_paths:
|
153
134
|
- lib
|
@@ -166,11 +147,5 @@ rubyforge_project:
|
|
166
147
|
rubygems_version: 2.5.1
|
167
148
|
signing_key:
|
168
149
|
specification_version: 4
|
169
|
-
summary: Plezi
|
170
|
-
|
171
|
-
test_files:
|
172
|
-
- test/console
|
173
|
-
- test/dispatch
|
174
|
-
- test/hello_world
|
175
|
-
- test/plezi_tests.rb
|
176
|
-
has_rdoc:
|
150
|
+
summary: The Plezi.io Ruby Framework for real time web applications.
|
151
|
+
test_files: []
|
data/bin/plezi
DELETED
@@ -1,104 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
$0="Plezi Builder"
|
3
|
-
# count lines of code with: ^[ \t]*[\w\d\"\(\{\@\[\]\}\)\:\'\.\*\&]+.*$
|
4
|
-
|
5
|
-
require 'irb'
|
6
|
-
require 'benchmark'
|
7
|
-
require 'securerandom'
|
8
|
-
require 'plezi/builders/builder'
|
9
|
-
require 'plezi/builders/app_builder'
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
######################################################################
|
14
|
-
# tweek the string class for termial coloring options
|
15
|
-
class String
|
16
|
-
# colorization
|
17
|
-
def colorize(color_code)
|
18
|
-
"\e[#{color_code}m#{self}\e[0m"
|
19
|
-
end
|
20
|
-
|
21
|
-
def red
|
22
|
-
colorize(31)
|
23
|
-
end
|
24
|
-
|
25
|
-
def green
|
26
|
-
colorize(32)
|
27
|
-
end
|
28
|
-
|
29
|
-
def yellow
|
30
|
-
colorize(33)
|
31
|
-
end
|
32
|
-
|
33
|
-
def pink
|
34
|
-
colorize(35)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
######################################################################
|
39
|
-
######################################################################
|
40
|
-
##
|
41
|
-
## Start the Build script
|
42
|
-
##
|
43
|
-
######################################################################
|
44
|
-
######################################################################
|
45
|
-
|
46
|
-
# update with http://ruby-doc.org/stdlib-2.2.0/libdoc/optparse/rdoc/OptionParser.html
|
47
|
-
|
48
|
-
# require 'optparser'
|
49
|
-
|
50
|
-
if ARGV[0] == 'new' || ARGV[0] == 'n' || ARGV[0] == "force" || ARGV[0] == 'mini' || ARGV[0] == 'm'
|
51
|
-
#########
|
52
|
-
## set up building environment
|
53
|
-
ARGV[1] = ARGV[1].gsub /[^a-zA-Z0-9]/, '_'
|
54
|
-
if Dir.exists?(ARGV[1]) && ARGV[0] != "force"
|
55
|
-
puts ""
|
56
|
-
puts "WARNING: app/folder alread exists, use `plezi fource #{ARGV[1]}` to attempt rebuild (no files will be overwritten).".red
|
57
|
-
puts ""
|
58
|
-
exit
|
59
|
-
end
|
60
|
-
if Dir.exists?(ARGV[1]) && ARGV[0] == "force"
|
61
|
-
Dir.chdir ARGV[1]
|
62
|
-
require ::File.expand_path(::Dir["."][0], ( ARGV[1] + ".rb") )
|
63
|
-
Dir.chdir '..'
|
64
|
-
end
|
65
|
-
|
66
|
-
# building
|
67
|
-
template = Plezi::Base::AppBuilder.new
|
68
|
-
(ARGV[0] == 'mini' || ARGV[0] == 'm' ) ? template.build_mini(ARGV[1]) : template.build(ARGV[1])
|
69
|
-
elsif ARGV[0] == 'server' || ARGV[0] == 'start' || ARGV[0] == 's'
|
70
|
-
ARGV.shift
|
71
|
-
load File.expand_path(Dir["."][0], (File.expand_path(Dir["."][0]).split(/[\\\/]/).last) ) rescue load( File.expand_path(Dir["."][0], (File.expand_path(Dir["."][0]).split(/[\\\/]/).last ) ) )
|
72
|
-
elsif ARGV[0] == 'console' || ARGV[0] == 'c'
|
73
|
-
load File.expand_path(Dir["."][0], (File.expand_path(Dir["."][0]).split(/[\\\/]/).last) ) rescue load( File.expand_path(Dir["."][0], (File.expand_path(Dir["."][0]).split(/[\\\/]/).last) ) )
|
74
|
-
ARGV.clear
|
75
|
-
Iodine.protocol = nil
|
76
|
-
IRB.start
|
77
|
-
else
|
78
|
-
puts ""
|
79
|
-
puts "Plezi fast web app starter.".pink
|
80
|
-
puts "use: plezi new appname"
|
81
|
-
puts "or: plezi new appname with template-gem-to-put-in another-template-gem-to-put"
|
82
|
-
puts "==============================".green
|
83
|
-
puts "new app options:".pink
|
84
|
-
puts "option description".yellow
|
85
|
-
puts "new <appname> creates a new application called <appname>."
|
86
|
-
puts "n alias for new."
|
87
|
-
puts "mini <appname> creates a new mini-application called <appname>."
|
88
|
-
puts "m alias for mini."
|
89
|
-
puts "starting up an app:".pink
|
90
|
-
puts "start attempts to run the app. accepts any parameters the app supports."
|
91
|
-
puts "s alias for start/server."
|
92
|
-
puts "start console innsead of services:".pink
|
93
|
-
puts "console runs the app. accepts any parameters the app supports."
|
94
|
-
puts "c alias for start/server."
|
95
|
-
puts "==============================".green
|
96
|
-
puts ""
|
97
|
-
puts "Run the app using the app's script with an optional: -p {port number}. i.e."
|
98
|
-
puts " cd ./appname".pink
|
99
|
-
puts " ./appname -p 8080".pink
|
100
|
-
puts ""
|
101
|
-
end
|
102
|
-
|
103
|
-
|
104
|
-
|
data/docs/async_helpers.md
DELETED
@@ -1,245 +0,0 @@
|
|
1
|
-
# Plezi's Asynchronous Engine
|
2
|
-
|
3
|
-
(todo: write documentation)
|
4
|
-
|
5
|
-
Inside Plezi's core code is a pure Ruby IO reactor called [Iodine](https://github.com/boazsegev/iodine), a wonderful Asynchronous Workflow Engine that allows us to enjoy both Multi-Threading and Multi-Processing.
|
6
|
-
|
7
|
-
Although multi-threading is highly regarded, it should be pointed out that using the [Iodine](https://github.com/boazsegev/iodine) with just one thread is both faster and more efficient. But, since some tasks that take more time (blocking tasks) can't be broken down into smaller tasks, using a number of threads (and/or processes) is a better practice.
|
8
|
-
|
9
|
-
You can read more about [Iodine](https://github.com/boazsegev/iodine) and it's amazing features in it's [documentation](http://www.rubydoc.info/github/boazsegev/iodine/master).
|
10
|
-
|
11
|
-
Here we will discuss the methods used for asynchronous processing of different tasks that allow us to break big heavy tasks into smaller bits, allowing our application to 'flow' and stay responsive even while under heavy loads.
|
12
|
-
|
13
|
-
## Asynchronous HTTP responses
|
14
|
-
|
15
|
-
Inside Plezi's core code is a pure Ruby Http and Websocket Server (and client) that comes with [Iodine](https://github.com/boazsegev/iodine) and allows for native Http/1.1 streaming using `chunked` encoding or native Http/2 streaming (built-in to the protocol).
|
16
|
-
|
17
|
-
Asynchronous Http method calls can be nested, but shouldn't be called one after the other.
|
18
|
-
|
19
|
-
i.e.:
|
20
|
-
|
21
|
-
```ruby
|
22
|
-
# right
|
23
|
-
response.stream_async { response.stream_async {'do after'}; 'do first' }
|
24
|
-
# wrong
|
25
|
-
response.stream_async { "who's first?" }
|
26
|
-
response.stream_async { "I don't know..." }
|
27
|
-
```
|
28
|
-
|
29
|
-
Since streaming is done asynchronously, and since Plezi is multi-threaded by default (this can be changed to single threaded, but is less recomended unless you know your code doesn't block - see `Plezi::Settings.max_threads = number`), Asynchronous HTTP method nesting makes sure that the code doesn't conflict and that race conditions don't occure within the same HTTP response.
|
30
|
-
|
31
|
-
|
32
|
-
#### Iodines's `response.stream_async &block`
|
33
|
-
|
34
|
-
Iodines's response object, which is accessed by the controller using the `response` method (or the `@response` object), allows easy access to HTTP streaming.
|
35
|
-
|
36
|
-
For example (run this in the terminal using `irb`):
|
37
|
-
|
38
|
-
```ruby
|
39
|
-
require `plezi`
|
40
|
-
|
41
|
-
class MyController
|
42
|
-
def index
|
43
|
-
response.stream_async do
|
44
|
-
response << "This will stream.\n"
|
45
|
-
response.stream_async do
|
46
|
-
response << "Streaming can be nested."
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
route '/', MyController
|
53
|
-
|
54
|
-
exit
|
55
|
-
```
|
56
|
-
|
57
|
-
As noted above, `response.stream_async` calls should always be nested and never called in 'parallel'.
|
58
|
-
|
59
|
-
Calling `response.stream_async`
|
60
|
-
|
61
|
-
#### Iodines's `response.stream_array enum, &block`
|
62
|
-
|
63
|
-
To make nesting easier, Iodines's response object provides the `response.stream_array enum, &block` method.
|
64
|
-
|
65
|
-
Here's our modified example:
|
66
|
-
|
67
|
-
```ruby
|
68
|
-
require 'plezi'
|
69
|
-
|
70
|
-
class MyController
|
71
|
-
def index
|
72
|
-
data = ["This will stream.\n", "Streaming can be nested."]
|
73
|
-
response.stream_array(data) {|s| response << s}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
route '/', MyController
|
78
|
-
|
79
|
-
exit
|
80
|
-
```
|
81
|
-
|
82
|
-
You can also add data to the array while 'looping', which allows you to use the array as a 'flag' for looped streaming. The following is a very limited example, which could be used for "lazy loading" data from a database, in order to save on system resources or send large table data using JSON "packets".
|
83
|
-
|
84
|
-
```ruby
|
85
|
-
require 'plezi'
|
86
|
-
|
87
|
-
class MyController
|
88
|
-
def index
|
89
|
-
data = ["This will stream.\n", "Streaming can be nested."]
|
90
|
-
flag = [true]
|
91
|
-
response.stream_array(flag) do
|
92
|
-
response << data.shift
|
93
|
-
flag << true unless data.empty?
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
route '/', MyController
|
99
|
-
|
100
|
-
exit
|
101
|
-
```
|
102
|
-
|
103
|
-
## Asynchronous code execution
|
104
|
-
|
105
|
-
[Iodine](https://github.com/boazsegev/iodine) has a very powerful Asynchronous Workflow Engine which offers a very intuitve and simplified way to use API both for queuing code snippets (blocks / methods) and for schedualing non-persistent timed events (future timed events are discarded during shutdown and need to be re-initiated).
|
106
|
-
|
107
|
-
### The Asynchronous "Queue"
|
108
|
-
|
109
|
-
`Iodine`'s core is built with simplicity in mind, making the programmer happy. With this in mind, Iodine offers a single and simple method that allow us to easily queue code execution.
|
110
|
-
|
111
|
-
|
112
|
-
#### `Iodine.run(arg1, arg2, arg3...) {block}`
|
113
|
-
|
114
|
-
`Iodine.run` takes arguments to be passed to a block of code prior to execution. This allows us to seperate the `Proc` object creation fron the data handling and possibly (but not always) optimize our code.
|
115
|
-
|
116
|
-
For example:
|
117
|
-
|
118
|
-
```ruby
|
119
|
-
require 'plezi'
|
120
|
-
|
121
|
-
class MyController
|
122
|
-
def index
|
123
|
-
# Plezi.run automatically defers to Iodine.run
|
124
|
-
Plezi.run(Time.now) {|t| puts "Someone poked me at: #{t}" } # maybe send an email?
|
125
|
-
"Hello World"
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
route '/', MyController
|
131
|
-
|
132
|
-
exit
|
133
|
-
```
|
134
|
-
|
135
|
-
This might be optimized like so:
|
136
|
-
|
137
|
-
```ruby
|
138
|
-
require 'plezi'
|
139
|
-
|
140
|
-
class MyController
|
141
|
-
def index
|
142
|
-
Iodine.run Time.now, &self.class.action_proc
|
143
|
-
"Hello World"
|
144
|
-
end
|
145
|
-
|
146
|
-
protected
|
147
|
-
|
148
|
-
def self.action_proc
|
149
|
-
@proc ||= Proc.new {|t| puts "Someone poked me at: #{t}" } # maybe send an email?
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
route '/', MyController
|
154
|
-
|
155
|
-
exit
|
156
|
-
```
|
157
|
-
|
158
|
-
### Timed events
|
159
|
-
|
160
|
-
Sometimes we want to schedule something to be done in a while, ormaybe we want a task to repeat every certain intevral...
|
161
|
-
|
162
|
-
In come Iodine's TimedEvents: `Iodine.run_after` and `Iodine.run_every`
|
163
|
-
|
164
|
-
#### `Iodine.run_every(seconds, arg1, arg2...) {|arg1, arg2..., timed_event| block }`
|
165
|
-
|
166
|
-
`Iodine.run_every` is very similar to the `Iodine.run`, except it automatically injects an argument to our block, the timed even itself, as the last (optional) parameter. This allows us to stop the repeating event should the need arise.
|
167
|
-
|
168
|
-
```ruby
|
169
|
-
require 'plezi'
|
170
|
-
|
171
|
-
class MyController
|
172
|
-
def index
|
173
|
-
counter = 0
|
174
|
-
# Plezi.run_every automatically defers to Iodine.run_every
|
175
|
-
Plezi.run_every(1, "Counting: %i") do |str, timer|
|
176
|
-
counter +=1
|
177
|
-
puts(str % counter)
|
178
|
-
timer.stop! if counter >= 3
|
179
|
-
end
|
180
|
-
"Hello World"
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
|
185
|
-
route '/', MyController
|
186
|
-
|
187
|
-
exit
|
188
|
-
```
|
189
|
-
|
190
|
-
A similar approach could have been accomplished by setting a repeat limit:
|
191
|
-
|
192
|
-
```ruby
|
193
|
-
require 'plezi'
|
194
|
-
|
195
|
-
class MyController
|
196
|
-
def index
|
197
|
-
timer = Iodine.run_every(1, "Counting down: %i") do |str, timer|
|
198
|
-
puts(str % timer.repeat_limit)
|
199
|
-
end
|
200
|
-
timer.repeat_limit = 3
|
201
|
-
"Hello World"
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
|
206
|
-
route '/', MyController
|
207
|
-
|
208
|
-
exit
|
209
|
-
```
|
210
|
-
|
211
|
-
#### `Iodine.run_after(seconds, arg1, arg2...) {|arg1, arg2..., timed_event| block}`
|
212
|
-
|
213
|
-
`Iodine.run_after` is very similar to the `Iodine.run_every`, except it is designed to "self destruct" after only only execution.
|
214
|
-
|
215
|
-
The timed event allows us to create a new event with the same job, if we wish to.
|
216
|
-
|
217
|
-
```ruby
|
218
|
-
require 'plezi'
|
219
|
-
|
220
|
-
class MyController
|
221
|
-
def index
|
222
|
-
counter = 0
|
223
|
-
# Plezi.run_after automatically defers to Iodine.run_after
|
224
|
-
Iodine.run_after(1, "Counting: %i") do |str, timer|
|
225
|
-
counter +=1
|
226
|
-
puts(str % counter)
|
227
|
-
Iodine.run_after(1, str, &timer.job) if counter < 3
|
228
|
-
end
|
229
|
-
"Hello World"
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
|
234
|
-
route '/', MyController
|
235
|
-
|
236
|
-
exit
|
237
|
-
```
|
238
|
-
|
239
|
-
/// To Do: complete doc.
|
240
|
-
|
241
|
-
## The Graceful Shutdown
|
242
|
-
|
243
|
-
Enter `Iodine.on_shutdown` - a reverse shutdown task queue (LIFO).
|
244
|
-
|
245
|
-
/// To Do: complete doc.
|