rsence 2.0.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/INSTALL.rdoc +295 -0
- data/LICENSE +622 -0
- data/README.rdoc +24 -0
- data/VERSION +1 -0
- data/bin/build_client.rb +254 -0
- data/bin/help +6 -0
- data/bin/launch.rb +120 -0
- data/bin/rdoc.sh +2 -0
- data/bin/restart +6 -0
- data/bin/rsence +120 -0
- data/bin/run +6 -0
- data/bin/run.rb +6 -0
- data/bin/save +6 -0
- data/bin/start +6 -0
- data/bin/status +6 -0
- data/bin/stop +6 -0
- data/conf/config.ru +5 -0
- data/conf/default_conf.yaml +337 -0
- data/conf/default_strings.yaml +77 -0
- data/conf/local_conf.yaml +14 -0
- data/conf/unicorn.conf +78 -0
- data/js/comm/comm/autosync/autosync.js +18 -0
- data/js/comm/comm/autosync/js.inc +0 -0
- data/js/comm/comm/comm.js +195 -0
- data/js/comm/comm/js.inc +0 -0
- data/js/comm/comm/queue/js.inc +0 -0
- data/js/comm/comm/queue/queue.js +183 -0
- data/js/comm/comm/session/js.inc +0 -0
- data/js/comm/comm/session/session.js +51 -0
- data/js/comm/comm/sessionwatcher/js.inc +0 -0
- data/js/comm/comm/sessionwatcher/sessionwatcher.js +43 -0
- data/js/comm/comm/transporter/js.inc +0 -0
- data/js/comm/comm/transporter/transporter.js +257 -0
- data/js/comm/comm/urlresponder/js.inc +0 -0
- data/js/comm/comm/urlresponder/urlresponder.js +148 -0
- data/js/comm/comm/values/js.inc +0 -0
- data/js/comm/comm/values/values.js +432 -0
- data/js/comm/jsloader/js.inc +0 -0
- data/js/comm/jsloader/jsloader.js +114 -0
- data/js/comm/reloadapp/js.inc +0 -0
- data/js/comm/reloadapp/reloadapp.js +150 -0
- data/js/comm/reloadapp/themes/default/reloadapp_warning-ie6.gif +0 -0
- data/js/comm/reloadapp/themes/default/reloadapp_warning.png +0 -0
- data/js/comm/sha/js.inc +0 -0
- data/js/comm/sha/sha.js +432 -0
- data/js/comm/values/value/js.inc +0 -0
- data/js/comm/values/value/value.js +182 -0
- data/js/comm/values/valuematrix/js.inc +0 -0
- data/js/comm/values/valuematrix/valuematrix.js +138 -0
- data/js/controls/button/button.js +57 -0
- data/js/controls/button/js.inc +0 -0
- data/js/controls/button/themes/bright/button.css +89 -0
- data/js/controls/button/themes/bright/button.html +7 -0
- data/js/controls/button/themes/bright/button_parts1-ie6.gif +0 -0
- data/js/controls/button/themes/bright/button_parts1.png +0 -0
- data/js/controls/button/themes/default/button.css +89 -0
- data/js/controls/button/themes/default/button.html +7 -0
- data/js/controls/button/themes/default/button_parts1-ie6.gif +0 -0
- data/js/controls/button/themes/default/button_parts1.png +0 -0
- data/js/controls/checkbox/checkbox.js +47 -0
- data/js/controls/checkbox/js.inc +0 -0
- data/js/controls/checkbox/themes/default/checkbox.css +69 -0
- data/js/controls/checkbox/themes/default/checkbox.html +5 -0
- data/js/controls/checkbox/themes/default/checkbox_parts1-ie6.gif +0 -0
- data/js/controls/checkbox/themes/default/checkbox_parts1.png +0 -0
- data/js/controls/datetime/calendar/calendar.js +197 -0
- data/js/controls/datetime/calendar/js.inc +0 -0
- data/js/controls/datetime/calendar/themes/default/calendar.css +108 -0
- data/js/controls/datetime/calendar/themes/default/calendar.html +9 -0
- data/js/controls/datetime/calendar/themes/default/calendar_arrows-ie6.gif +0 -0
- data/js/controls/datetime/calendar/themes/default/calendar_arrows.png +0 -0
- data/js/controls/datetime/datetimevalue/datetimevalue.js +246 -0
- data/js/controls/datetime/datetimevalue/js.inc +0 -0
- data/js/controls/datetime/timesheet/js.inc +0 -0
- data/js/controls/datetime/timesheet/themes/default/timesheet.css +30 -0
- data/js/controls/datetime/timesheet/themes/default/timesheet.html +2 -0
- data/js/controls/datetime/timesheet/timesheet.js +182 -0
- data/js/controls/datetime/timesheet_item/js.inc +0 -0
- data/js/controls/datetime/timesheet_item/themes/default/timesheet_item.css +42 -0
- data/js/controls/datetime/timesheet_item/themes/default/timesheet_item.html +8 -0
- data/js/controls/datetime/timesheet_item/timesheet_item.js +247 -0
- data/js/controls/datetime/timesheet_item_edit/js.inc +0 -0
- data/js/controls/datetime/timesheet_item_edit/timesheet_item_edit.js +274 -0
- data/js/controls/dialogs/alert_sheet/alert_sheet.js +62 -0
- data/js/controls/dialogs/alert_sheet/js.inc +0 -0
- data/js/controls/dialogs/confirm_sheet/confirm_sheet.js +36 -0
- data/js/controls/dialogs/confirm_sheet/js.inc +0 -0
- data/js/controls/dialogs/sheet/js.inc +0 -0
- data/js/controls/dialogs/sheet/sheet.js +83 -0
- data/js/controls/dialogs/sheet/themes/default/sheet.css +64 -0
- data/js/controls/dialogs/sheet/themes/default/sheet.html +14 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_bg-ie6.gif +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_bg.png +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_dim-ie6.gif +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_dim.png +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_parts1-ie6.gif +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_parts1.png +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_parts2-ie6.gif +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_parts2.png +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_warning-ie6.gif +0 -0
- data/js/controls/dialogs/sheet/themes/default/sheet_warning.png +0 -0
- data/js/controls/imageview/imageview.js +108 -0
- data/js/controls/imageview/js.inc +0 -0
- data/js/controls/imageview/themes/default/blank.gif +0 -0
- data/js/controls/lists/checkboxlist/checkboxlist.js +170 -0
- data/js/controls/lists/checkboxlist/js.inc +0 -0
- data/js/controls/lists/listitems/js.inc +0 -0
- data/js/controls/lists/listitems/listitems.js +65 -0
- data/js/controls/lists/radiobuttonlist/js.inc +0 -0
- data/js/controls/lists/radiobuttonlist/radiobuttonlist.js +126 -0
- data/js/controls/passwordcontrol/js.inc +0 -0
- data/js/controls/passwordcontrol/passwordcontrol.js +22 -0
- data/js/controls/passwordcontrol/themes/default/passwordcontrol.css +0 -0
- data/js/controls/passwordcontrol/themes/default/passwordcontrol.html +18 -0
- data/js/controls/progress/progressbar/js.inc +0 -0
- data/js/controls/progress/progressbar/progressbar.js +36 -0
- data/js/controls/progress/progressbar/themes/default/progressbar.css +16 -0
- data/js/controls/progress/progressbar/themes/default/progressbar.html +2 -0
- data/js/controls/progress/progressindicator/js.inc +0 -0
- data/js/controls/progress/progressindicator/progressindicator.js +43 -0
- data/js/controls/radiobutton/js.inc +0 -0
- data/js/controls/radiobutton/radiobutton.js +41 -0
- data/js/controls/radiobutton/themes/default/radiobutton.css +69 -0
- data/js/controls/radiobutton/themes/default/radiobutton.html +5 -0
- data/js/controls/radiobutton/themes/default/radiobutton_parts1-ie6.gif +0 -0
- data/js/controls/radiobutton/themes/default/radiobutton_parts1.png +0 -0
- data/js/controls/sliders/slider/js.inc +0 -0
- data/js/controls/sliders/slider/slider.js +356 -0
- data/js/controls/sliders/slider/themes/default/hslider_tracks-ie6.gif +0 -0
- data/js/controls/sliders/slider/themes/default/hslider_tracks.png +0 -0
- data/js/controls/sliders/slider/themes/default/slider.css +108 -0
- data/js/controls/sliders/slider/themes/default/slider.html +5 -0
- data/js/controls/sliders/slider/themes/default/slider_thumbs-ie6.gif +0 -0
- data/js/controls/sliders/slider/themes/default/slider_thumbs.png +0 -0
- data/js/controls/sliders/vslider/js.inc +0 -0
- data/js/controls/sliders/vslider/themes/default/vslider.css +52 -0
- data/js/controls/sliders/vslider/themes/default/vslider.html +5 -0
- data/js/controls/sliders/vslider/themes/default/vslider_tracks-ie6.gif +0 -0
- data/js/controls/sliders/vslider/themes/default/vslider_tracks.png +0 -0
- data/js/controls/sliders/vslider/vslider.js +40 -0
- data/js/controls/stepper/js.inc +0 -0
- data/js/controls/stepper/stepper.js +212 -0
- data/js/controls/stepper/themes/default/stepper-ie6.gif +0 -0
- data/js/controls/stepper/themes/default/stepper.css +14 -0
- data/js/controls/stepper/themes/default/stepper.html +2 -0
- data/js/controls/stepper/themes/default/stepper.png +0 -0
- data/js/controls/stringview/js.inc +0 -0
- data/js/controls/stringview/stringview.js +49 -0
- data/js/controls/stringview/themes/default/stringview.css +8 -0
- data/js/controls/stringview/themes/default/stringview.html +1 -0
- data/js/controls/tab/js.inc +0 -0
- data/js/controls/tab/tab.js +276 -0
- data/js/controls/tab/themes/bright/tab.css +76 -0
- data/js/controls/tab/themes/bright/tab.html +6 -0
- data/js/controls/tab/themes/bright/tab_bg_color-ie6.gif +0 -0
- data/js/controls/tab/themes/bright/tab_bg_color.png +0 -0
- data/js/controls/tab/themes/bright/tab_border_pattern-ie6.gif +0 -0
- data/js/controls/tab/themes/bright/tab_border_pattern.png +0 -0
- data/js/controls/tab/themes/bright/tab_parts1-ie6.gif +0 -0
- data/js/controls/tab/themes/bright/tab_parts1.png +0 -0
- data/js/controls/tab/themes/default/tab.css +77 -0
- data/js/controls/tab/themes/default/tab.html +6 -0
- data/js/controls/tab/themes/default/tab_bg_color-ie6.gif +0 -0
- data/js/controls/tab/themes/default/tab_bg_color.png +0 -0
- data/js/controls/tab/themes/default/tab_border_pattern-ie6.gif +0 -0
- data/js/controls/tab/themes/default/tab_border_pattern.png +0 -0
- data/js/controls/tab/themes/default/tab_parts1-ie6.gif +0 -0
- data/js/controls/tab/themes/default/tab_parts1.png +0 -0
- data/js/controls/textarea/js.inc +0 -0
- data/js/controls/textarea/textarea.js +23 -0
- data/js/controls/textarea/themes/default/textarea.css +21 -0
- data/js/controls/textarea/themes/default/textarea.html +18 -0
- data/js/controls/textcontrol/js.inc +0 -0
- data/js/controls/textcontrol/textcontrol.js +372 -0
- data/js/controls/textcontrol/themes/default/textcontrol.css +107 -0
- data/js/controls/textcontrol/themes/default/textcontrol.html +18 -0
- data/js/controls/textcontrol/themes/default/textcontrol_parts1-ie6.gif +0 -0
- data/js/controls/textcontrol/themes/default/textcontrol_parts1.png +0 -0
- data/js/controls/textcontrol/themes/default/textcontrol_parts2-ie6.gif +0 -0
- data/js/controls/textcontrol/themes/default/textcontrol_parts2.png +0 -0
- data/js/controls/textcontrol/themes/default/textcontrol_parts3-ie6.gif +0 -0
- data/js/controls/textcontrol/themes/default/textcontrol_parts3.png +0 -0
- data/js/controls/uploader/js.inc +0 -0
- data/js/controls/uploader/themes/default/upload_progress.gif +0 -0
- data/js/controls/uploader/themes/default/uploader.css +108 -0
- data/js/controls/uploader/themes/default/uploader.html +27 -0
- data/js/controls/uploader/uploader.js +153 -0
- data/js/controls/validatorview/js.inc +0 -0
- data/js/controls/validatorview/themes/default/validator-ie6.gif +0 -0
- data/js/controls/validatorview/themes/default/validator.png +0 -0
- data/js/controls/validatorview/themes/default/validatorview.css +0 -0
- data/js/controls/validatorview/themes/default/validatorview.html +0 -0
- data/js/controls/validatorview/validatorview.js +55 -0
- data/js/controls/window/js.inc +0 -0
- data/js/controls/window/themes/default/window.css +219 -0
- data/js/controls/window/themes/default/window.html +17 -0
- data/js/controls/window/themes/default/window_bg_active-ie6.gif +0 -0
- data/js/controls/window/themes/default/window_bg_active.png +0 -0
- data/js/controls/window/themes/default/window_bg_inactive-ie6.gif +0 -0
- data/js/controls/window/themes/default/window_bg_inactive.png +0 -0
- data/js/controls/window/themes/default/window_buttons-ie6.gif +0 -0
- data/js/controls/window/themes/default/window_buttons.png +0 -0
- data/js/controls/window/themes/default/window_parts1-ie6.gif +0 -0
- data/js/controls/window/themes/default/window_parts1.png +0 -0
- data/js/controls/window/themes/default/window_parts2-ie6.gif +0 -0
- data/js/controls/window/themes/default/window_parts2.png +0 -0
- data/js/controls/window/window.js +284 -0
- data/js/core/class/class.js +317 -0
- data/js/core/class/js.inc +0 -0
- data/js/core/elem/elem.js +1376 -0
- data/js/core/elem/js.inc +0 -0
- data/js/core/event/event.js +1021 -0
- data/js/core/event/js.inc +0 -0
- data/js/core/iefix/ie_css_element.htc +5 -0
- data/js/core/iefix/ie_css_style.htc +5 -0
- data/js/core/iefix/iefix.js +359 -0
- data/js/core/iefix/js.inc +0 -0
- data/js/debugg/debugg.js +43 -0
- data/js/debugg/js.inc +0 -0
- data/js/foundation/application/application.js +209 -0
- data/js/foundation/application/js.inc +0 -0
- data/js/foundation/control/control.js +342 -0
- data/js/foundation/control/controldefaults/controldefaults.js +59 -0
- data/js/foundation/control/controldefaults/js.inc +0 -0
- data/js/foundation/control/dummyvalue/dummyvalue.js +50 -0
- data/js/foundation/control/dummyvalue/js.inc +0 -0
- data/js/foundation/control/dyncontrol/dyncontrol.js +494 -0
- data/js/foundation/control/dyncontrol/js.inc +0 -0
- data/js/foundation/control/dyncontrol/themes/default/dyncontrol.css +0 -0
- data/js/foundation/control/dyncontrol/themes/default/dyncontrol.html +0 -0
- data/js/foundation/control/eventresponder/eventresponder.js +713 -0
- data/js/foundation/control/eventresponder/js.inc +0 -0
- data/js/foundation/control/js.inc +0 -0
- data/js/foundation/control/valueresponder/js.inc +0 -0
- data/js/foundation/control/valueresponder/valueresponder.js +77 -0
- data/js/foundation/geom/point/js.inc +0 -0
- data/js/foundation/geom/point/point.js +202 -0
- data/js/foundation/geom/rect/js.inc +0 -0
- data/js/foundation/geom/rect/rect.js +610 -0
- data/js/foundation/json_renderer/js.inc +0 -0
- data/js/foundation/json_renderer/json_renderer.js +231 -0
- data/js/foundation/system/js.inc +0 -0
- data/js/foundation/system/system.js +369 -0
- data/js/foundation/thememanager/js.inc +0 -0
- data/js/foundation/thememanager/thememanager.js +387 -0
- data/js/foundation/view/js.inc +0 -0
- data/js/foundation/view/markupview/js.inc +0 -0
- data/js/foundation/view/markupview/markupview.js +113 -0
- data/js/foundation/view/morphanimation/js.inc +0 -0
- data/js/foundation/view/morphanimation/morphanimation.js +236 -0
- data/js/foundation/view/view.js +1804 -0
- data/js/foundation/view/viewdefaults/js.inc +0 -0
- data/js/foundation/view/viewdefaults/viewdefaults.js +25 -0
- data/js/views/centerview/centerview.js +45 -0
- data/js/views/centerview/js.inc +0 -0
- data/js/views/inlineview/inlineview.js +14 -0
- data/js/views/inlineview/js.inc +0 -0
- data/js/views/scrollview/js.inc +0 -0
- data/js/views/scrollview/scrollview.js +39 -0
- data/lib/conf/default.rb +220 -0
- data/lib/conf/wizard.rb +303 -0
- data/lib/daemon/daemon.rb +293 -0
- data/lib/http/broker.rb +102 -0
- data/lib/http/rackup.rb +88 -0
- data/lib/http/request.rb +69 -0
- data/lib/http/response.rb +63 -0
- data/lib/plugins/gui_plugin.rb +129 -0
- data/lib/plugins/guiparser.rb +114 -0
- data/lib/plugins/plugin.rb +652 -0
- data/lib/plugins/plugin_plugins.rb +47 -0
- data/lib/plugins/plugin_sqlite_db.rb +72 -0
- data/lib/plugins/plugin_util.rb +96 -0
- data/lib/plugins/pluginmanager.rb +517 -0
- data/lib/plugins/servlet.rb +69 -0
- data/lib/session/msg.rb +291 -0
- data/lib/session/sessionmanager.rb +491 -0
- data/lib/session/sessionstorage.rb +314 -0
- data/lib/transporter/transporter.rb +254 -0
- data/lib/util/gzstring.rb +5 -0
- data/lib/values/hvalue.rb +323 -0
- data/lib/values/valuemanager.rb +152 -0
- data/plugins/client_pkg/client_pkg.rb +186 -0
- data/plugins/client_pkg/info.yaml +25 -0
- data/plugins/client_pkg/lib/client_pkg_build.rb +569 -0
- data/plugins/client_pkg/lib/client_pkg_cache.rb +50 -0
- data/plugins/client_pkg/lib/client_pkg_serve.rb +210 -0
- data/plugins/client_pkg/log/build_log +0 -0
- data/plugins/index_html/img/loading.gif +0 -0
- data/plugins/index_html/img/riassence.gif +0 -0
- data/plugins/index_html/index_html.rb +150 -0
- data/plugins/index_html/tmpl/index.html +22 -0
- data/plugins/index_html/tmpl/startup_index.html +29 -0
- data/plugins/legacy/disabled +0 -0
- data/plugins/legacy/disabled- +0 -0
- data/plugins/legacy/info.yaml +22 -0
- data/plugins/legacy/legacy.rb +15 -0
- data/plugins/main/js/riassence_ns.js +87 -0
- data/plugins/main/main.rb +234 -0
- data/plugins/main/values.yaml +8 -0
- data/plugins/ticketservices/lib/common.rb +300 -0
- data/plugins/ticketservices/lib/favicon.rb +38 -0
- data/plugins/ticketservices/lib/file.rb +58 -0
- data/plugins/ticketservices/lib/img.rb +50 -0
- data/plugins/ticketservices/lib/objblob.rb +66 -0
- data/plugins/ticketservices/lib/rsrc.rb +34 -0
- data/plugins/ticketservices/lib/upload.rb +206 -0
- data/plugins/ticketservices/ticketservices.rb +268 -0
- data/var/db/.git_include +0 -0
- data/var/log/.git_include +0 -0
- data/var/run/.git_include +0 -0
- metadata +390 -0
data/lib/http/request.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#--
|
2
|
+
## Riassence Framework
|
3
|
+
# Copyright 2008 Riassence Inc.
|
4
|
+
# http://riassence.com/
|
5
|
+
#
|
6
|
+
# You should have received a copy of the GNU General Public License along
|
7
|
+
# with this software package. If not, contact licensing@riassence.com
|
8
|
+
##
|
9
|
+
#++
|
10
|
+
|
11
|
+
|
12
|
+
require 'rubygems'
|
13
|
+
require 'rack'
|
14
|
+
|
15
|
+
module RSence
|
16
|
+
|
17
|
+
class Request < Rack::Request
|
18
|
+
attr_reader :header, :path, :query
|
19
|
+
def initialize(env)
|
20
|
+
@header = {
|
21
|
+
|
22
|
+
}
|
23
|
+
super
|
24
|
+
env2header()
|
25
|
+
@path = path_info()
|
26
|
+
@query = params()
|
27
|
+
end
|
28
|
+
def unparsed_uri
|
29
|
+
return @header['request-uri']
|
30
|
+
end
|
31
|
+
def env2header
|
32
|
+
[ ['SERVER_NAME', 'server-name'],
|
33
|
+
['HTTP_USER_AGENT', 'user-agent'],
|
34
|
+
['HTTP_ACCEPT_ENCODING', 'accept-encoding'],
|
35
|
+
['PATH_INFO', 'path-info'],
|
36
|
+
['HTTP_HOST', 'host'],
|
37
|
+
['HTTP_ACCEPT_LANGUAGE', 'accept-language'],
|
38
|
+
['SERVER_PROTOCOL', 'server-protocol'],
|
39
|
+
['REQUEST_PATH', 'request-path'],
|
40
|
+
['HTTP_KEEP_ALIVE', 'keep-alive'],
|
41
|
+
['SERVER_SOFTWARE', 'server-software'],
|
42
|
+
['REMOTE_ADDR', 'remote-addr'],
|
43
|
+
['HTTP_REFERER', 'referer'],
|
44
|
+
['HTTP_VERSION', 'version'],
|
45
|
+
['HTTP_ACCEPT_CHARSET', 'accept-charset'],
|
46
|
+
['REQUEST_URI', 'request-uri'],
|
47
|
+
['SERVER_PORT', 'server-port'],
|
48
|
+
['QUERY_STRING', 'query-string'],
|
49
|
+
['HTTP_ACCEPT', 'accept'],
|
50
|
+
['REQUEST_METHOD', 'request-method'],
|
51
|
+
['HTTP_CONNECTION', 'connection'],
|
52
|
+
['HTTP_SOAPACTION', 'soapaction'],
|
53
|
+
['HTTP_FORWARDED_HOST', 'forwarded-host']
|
54
|
+
].each do |env_key,header_key|
|
55
|
+
if @env.has_key?(env_key)
|
56
|
+
@header[header_key] = @env[env_key]
|
57
|
+
end
|
58
|
+
if env_key.start_with?( 'HTTP_' )
|
59
|
+
x_env_key = "HTTP_X#{env_key[4..-1]}"
|
60
|
+
if @env.has_key?( x_env_key )
|
61
|
+
@header["x-#{header_key}"] = @env[ x_env_key ]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#--
|
2
|
+
## Riassence Framework
|
3
|
+
# Copyright 2008 Riassence Inc.
|
4
|
+
# http://riassence.com/
|
5
|
+
#
|
6
|
+
# You should have received a copy of the GNU General Public License along
|
7
|
+
# with this software package. If not, contact licensing@riassence.com
|
8
|
+
##
|
9
|
+
#++
|
10
|
+
|
11
|
+
|
12
|
+
module RSence
|
13
|
+
|
14
|
+
class ResponseBody < Array
|
15
|
+
def +(body_data)
|
16
|
+
self.push(body_data)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
## Minimally WEBrick -compatible Response object.
|
21
|
+
## Implements only the methods used by the framework.
|
22
|
+
class Response
|
23
|
+
def initialize
|
24
|
+
@body = ResponseBody.new(1)
|
25
|
+
@body[0] = ''
|
26
|
+
@status = 200
|
27
|
+
@header = {
|
28
|
+
'Content-Type' => 'text/plain',
|
29
|
+
'Server' => 'Riassence Framework'
|
30
|
+
}
|
31
|
+
end
|
32
|
+
def body=(body_data)
|
33
|
+
@body = ResponseBody.new(1)
|
34
|
+
@body[0] = body_data
|
35
|
+
end
|
36
|
+
def body
|
37
|
+
@body.join
|
38
|
+
end
|
39
|
+
def content_type=(new_content_type)
|
40
|
+
@header['Content-Type'] = new_content_type
|
41
|
+
end
|
42
|
+
def content_type
|
43
|
+
@header['Content-Type']
|
44
|
+
end
|
45
|
+
def camelize( header_key )
|
46
|
+
header_key.capitalize.gsub(/\-([a-z])/) { '-'+$1.upcase }
|
47
|
+
end
|
48
|
+
def []=(header_key,header_val)
|
49
|
+
@header[camelize( header_key )] = header_val.to_s
|
50
|
+
end
|
51
|
+
def status=(new_val)
|
52
|
+
@status = new_val.to_i
|
53
|
+
end
|
54
|
+
def status
|
55
|
+
@status
|
56
|
+
end
|
57
|
+
def header
|
58
|
+
@header
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,129 @@
|
|
1
|
+
## Riassence Framework
|
2
|
+
# Copyright 2009 Riassence Inc.
|
3
|
+
# http://riassence.com/
|
4
|
+
#
|
5
|
+
# You should have received a copy of the GNU General Public License along
|
6
|
+
# with this software package. If not, contact licensing@riassence.com
|
7
|
+
##
|
8
|
+
|
9
|
+
## The GUIPlugin extends Plugin by automatically initializing an GUIParser
|
10
|
+
## instance as @gui
|
11
|
+
## It makes the include_js method public to enable automatic dependency
|
12
|
+
## loading based on the dependencies item in the YAML gui declaration.
|
13
|
+
## It also makes the @path public.
|
14
|
+
## It inits the gui automatically.
|
15
|
+
## Extend the gui_params method to define your own params for the gui data.
|
16
|
+
##
|
17
|
+
## HValues can be defined inside values.yaml at the root directory of
|
18
|
+
## plugin. The HValues may be linked directly with methods on the values.yaml
|
19
|
+
## as well.
|
20
|
+
##
|
21
|
+
## == Values.yaml
|
22
|
+
## :valuename: # name of the HValue
|
23
|
+
## :value: 2.56 # defined value
|
24
|
+
## :responders: # methods responding to the value on ruby code upon change
|
25
|
+
## - :method: validate_convert_factor
|
26
|
+
##
|
27
|
+
##
|
28
|
+
##
|
29
|
+
class GUIPlugin < Plugin
|
30
|
+
|
31
|
+
@@default_yaml_src = %{
|
32
|
+
type: GUITree
|
33
|
+
version: 0.5
|
34
|
+
|
35
|
+
class: HApplication
|
36
|
+
options:
|
37
|
+
label: "Dummy Application"
|
38
|
+
}
|
39
|
+
|
40
|
+
# Automatically initializes an GUIParser instance as @gui
|
41
|
+
def init
|
42
|
+
super
|
43
|
+
yaml_src = file_read( "gui/#{@name}.yaml" )
|
44
|
+
yaml_src = file_read( "gui/main.yaml" ) unless yaml_src
|
45
|
+
yaml_src = @@default_yaml_src unless yaml_src
|
46
|
+
@gui = GUIParser.new( self, yaml_src )
|
47
|
+
@client_pkgs = false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Extend this method to return custom params to GUIParser#init.
|
51
|
+
# Called from init_ui.
|
52
|
+
# By default assigns the session values as :values to use for
|
53
|
+
# valueObjId: ":values.my_value_name" in the YAML GUI file.
|
54
|
+
def gui_params( msg )
|
55
|
+
return {
|
56
|
+
:values => @gui.values( get_ses( msg ) )
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def install_client_pkgs
|
61
|
+
if @client_pkgs
|
62
|
+
warn "install_client_pkgs: called with @client_pkgs defined; returning"
|
63
|
+
return
|
64
|
+
end
|
65
|
+
@client_pkgs = yaml_read( 'client_pkgs.yaml' )
|
66
|
+
if @client_pkgs
|
67
|
+
if @client_pkgs.has_key?(:src_dirs)
|
68
|
+
@client_pkgs[:src_dirs].each do |src_dir|
|
69
|
+
src_dir = bundle_path( src_dir[2..-1] ) if src_dir.start_with?('./')
|
70
|
+
@plugins.client_pkg.add_src_dir( src_dir )
|
71
|
+
end
|
72
|
+
end
|
73
|
+
@plugins.client_pkg.add_packages( @client_pkgs[:packages ] ) if @client_pkgs.has_key?(:packages )
|
74
|
+
@plugins.client_pkg.add_themes( @client_pkgs[:theme_names ] ) if @client_pkgs.has_key?(:theme_names )
|
75
|
+
@plugins.client_pkg.add_gfx_formats( @client_pkgs[:gfx_formats ] ) if @client_pkgs.has_key?(:gfx_formats )
|
76
|
+
@plugins.client_pkg.add_reserved_names( @client_pkgs[:reserved_names] ) if @client_pkgs.has_key?(:reserved_names)
|
77
|
+
@plugins.client_pkg.rebuild_client
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def uninstall_client_pkgs
|
82
|
+
if not @client_pkgs
|
83
|
+
warn "uninstall_client_pkgs: called without @client_pkgs defined"
|
84
|
+
else
|
85
|
+
if @client_pkgs.has_key?(:src_dirs)
|
86
|
+
@client_pkgs[:src_dirs].each do |src_dir|
|
87
|
+
src_dir = bundle_path( src_dir[2..-1] ) if src_dir.start_with?('./')
|
88
|
+
@plugins.client_pkg.del_src_dir( src_dir )
|
89
|
+
end
|
90
|
+
end
|
91
|
+
@plugins.client_pkg.del_reserved_names( @client_pkgs[:reserved_names] ) if @client_pkgs.has_key?(:reserved_names)
|
92
|
+
@plugins.client_pkg.del_gfx_formats( @client_pkgs[:gfx_formats ] ) if @client_pkgs.has_key?(:gfx_formats )
|
93
|
+
@plugins.client_pkg.del_themes( @client_pkgs[:theme_names ] ) if @client_pkgs.has_key?(:theme_names )
|
94
|
+
@plugins.client_pkg.del_packages( @client_pkgs[:packages].keys ) if @client_pkgs.has_key?(:packages )
|
95
|
+
@plugins.client_pkg.rebuild_client
|
96
|
+
end
|
97
|
+
@client_pkgs = false
|
98
|
+
end
|
99
|
+
|
100
|
+
def open
|
101
|
+
super
|
102
|
+
install_client_pkgs if File.exist? bundle_path( 'client_pkgs.yaml' )
|
103
|
+
end
|
104
|
+
|
105
|
+
def close
|
106
|
+
super
|
107
|
+
uninstall_client_pkgs if @client_pkgs
|
108
|
+
end
|
109
|
+
|
110
|
+
# Sends gui specification to the main plugin
|
111
|
+
def spec_ui( msg )
|
112
|
+
# TODO
|
113
|
+
end
|
114
|
+
|
115
|
+
# Automatically inits the UI using GUIParser#init.
|
116
|
+
# Passes on the return value of gui_params.
|
117
|
+
def init_ui( msg ); @gui.init( msg, gui_params( msg ) ); end
|
118
|
+
|
119
|
+
# Automatically kills the UI using GUIParser#kill
|
120
|
+
def kill_ui( msg ); @gui.kill( msg ); end
|
121
|
+
|
122
|
+
# Makes include_js public to enable calls to it from GUIParser
|
123
|
+
public :include_js, :read_js_once
|
124
|
+
|
125
|
+
attr_reader :plugins
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
|
@@ -0,0 +1,114 @@
|
|
1
|
+
## Riassence Framework
|
2
|
+
# Copyright 2009 Riassence Inc.
|
3
|
+
# http://riassence.com/
|
4
|
+
#
|
5
|
+
# You should have received a copy of the GNU General Public License along
|
6
|
+
# with this software package. If not, contact licensing@riassence.com
|
7
|
+
##
|
8
|
+
|
9
|
+
# This class automatically loads a YAML file from "gui" subdirectory of a plugin.
|
10
|
+
# Extend your plugin from the GUIPlugin class instead of the Plugin class to make
|
11
|
+
# this work automatically.
|
12
|
+
# = Usage:
|
13
|
+
# Initialize like this from inside a plugin method. This will load the "gui/my_gui.yaml" file.
|
14
|
+
# @gui = GUIParser.new( self, 'my_gui' )
|
15
|
+
# To make the client render the contents of the yaml do this:
|
16
|
+
# ses = get_ses( msg )
|
17
|
+
# params = { :values => @gui.values( ses ) }
|
18
|
+
# @gui.init( msg, params )
|
19
|
+
class GUIParser
|
20
|
+
|
21
|
+
include ::RSence
|
22
|
+
|
23
|
+
# Use this method to send the client all commands required to construct the GUI Tree using JSONRenderer.
|
24
|
+
# = Parameters
|
25
|
+
# +msg+:: The +Message+ instance +msg+ used all over the place.
|
26
|
+
# +params+:: An hash containing all parameters referred from the YAML file.
|
27
|
+
def init( msg, params )
|
28
|
+
gui_data = YAML.load( @yaml_src )
|
29
|
+
parse_gui( gui_data, params )
|
30
|
+
if gui_data.has_key?('dependencies')
|
31
|
+
@parent.include_js( msg, gui_data['dependencies'] )
|
32
|
+
gui_data.delete('dependencies')
|
33
|
+
end
|
34
|
+
if gui_data.has_key?('include')
|
35
|
+
gui_data['include'].each do | js_file |
|
36
|
+
js_src = @parent.read_js_once( msg, js_file )
|
37
|
+
msg.reply( js_src )
|
38
|
+
end
|
39
|
+
end
|
40
|
+
gui_name = @parent.name
|
41
|
+
msg.reply( "JSONRenderer.nu(#{gui_data.to_json});", true )
|
42
|
+
end
|
43
|
+
|
44
|
+
# Use this method to extract all the value id's of the +ses+ hash.
|
45
|
+
def values( ses )
|
46
|
+
ids = {}
|
47
|
+
ses.each do | key, value |
|
48
|
+
if value.class == HValue
|
49
|
+
ids[ key ] = value.val_id
|
50
|
+
end
|
51
|
+
end
|
52
|
+
return ids
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def json_fun( value )
|
58
|
+
JSON.parse( "[#{value}]" ).first
|
59
|
+
end
|
60
|
+
|
61
|
+
# Parses the gui data using params. Called from +init+.
|
62
|
+
def parse_gui( gui_data, params )
|
63
|
+
data_class = gui_data.class
|
64
|
+
if data_class == Array
|
65
|
+
gui_data.each_with_index do | item, i |
|
66
|
+
gui_data[i] = parse_gui( item, params )
|
67
|
+
end
|
68
|
+
elsif data_class == Hash
|
69
|
+
gui_data.each do | key, value |
|
70
|
+
gui_data[key] = parse_gui( value, params )
|
71
|
+
end
|
72
|
+
elsif data_class == Symbol
|
73
|
+
sym_str = gui_data.to_s
|
74
|
+
if sym_str.include? '.'
|
75
|
+
sym_arr = sym_str.split('.')
|
76
|
+
else
|
77
|
+
sym_arr = [ sym_str ]
|
78
|
+
end
|
79
|
+
return get_params( sym_arr, params )
|
80
|
+
elsif data_class == String and gui_data.strip.start_with?('function(')
|
81
|
+
return @parent.plugins[:client_pkg].squeeze( "a="+json_fun( gui_data.to_json ) )[2..-1]
|
82
|
+
end
|
83
|
+
return gui_data
|
84
|
+
end
|
85
|
+
|
86
|
+
# Searches the params hash for parameters whenever encountered a Symbol in the YAML.
|
87
|
+
def get_params( params_path, params )
|
88
|
+
item = params_path.shift
|
89
|
+
if params.class == Hash
|
90
|
+
has_str = params.has_key?( item )
|
91
|
+
has_sym = params.has_key?( item.to_sym )
|
92
|
+
item = item.to_sym if has_sym
|
93
|
+
if has_str or has_sym
|
94
|
+
if params_path.size == 0
|
95
|
+
return params[item]
|
96
|
+
else
|
97
|
+
return get_params( params_path, params[ item ] )
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
return ''
|
102
|
+
end
|
103
|
+
|
104
|
+
# Loads the YAML file.
|
105
|
+
# = Parameters
|
106
|
+
# +parent+:: The Plugin instance called from, use +self+ when constructing in a Plugin method.
|
107
|
+
# +yaml_src+:: The YAML source template for the GUI
|
108
|
+
def initialize( parent, yaml_src )
|
109
|
+
@parent = parent
|
110
|
+
@yaml_src = yaml_src
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
@@ -0,0 +1,652 @@
|
|
1
|
+
## Riassence Framework
|
2
|
+
# Copyright 2006 Riassence Inc.
|
3
|
+
# http://riassence.com/
|
4
|
+
#
|
5
|
+
# You should have received a copy of the GNU General Public License along
|
6
|
+
# with this software package. If not, contact licensing@riassence.com
|
7
|
+
##
|
8
|
+
|
9
|
+
## = Abstract
|
10
|
+
## The Plugin class is the base class for extending server logic.
|
11
|
+
## A single Plugin instance serves the requests of all sessions,
|
12
|
+
## which makes them very cpu and memory efficient compared to systems,
|
13
|
+
## where the server classes are constructed and destructed for each
|
14
|
+
## request.
|
15
|
+
##
|
16
|
+
## Plugins are designed to be contained in a plugin directory bundle and
|
17
|
+
## to be loaded by the +PluginManager+, which is also responsible for
|
18
|
+
## delegating the events and other calls throughout the system.
|
19
|
+
##
|
20
|
+
## == Anatomy of a plugin bundle
|
21
|
+
## The plugin bundle contains all data needed to run the plugin. Design
|
22
|
+
## your plugin without any hard-coded paths, remember that it's intended
|
23
|
+
## to be deployed by "dropping" the whole plugin into one of the server's
|
24
|
+
## plugins directories.
|
25
|
+
##
|
26
|
+
## The +PluginManager+ looks for such bundles and evaluates them into an
|
27
|
+
## anonymous +Module+ namespace. The content of the ruby source file
|
28
|
+
## is then responsible for including its libraries, constructing an
|
29
|
+
## instance of itself and registering itself as a part of the system.
|
30
|
+
##
|
31
|
+
## It's advised to use the +GUIPlugin+ class for plugins that handle
|
32
|
+
## user interfaces. Usage of the +Plugin+ bundle is advised to use
|
33
|
+
## for plugins that provide extra functionality, value responders
|
34
|
+
## and other utilities that supplement the user interface.
|
35
|
+
##
|
36
|
+
## You must call the +#register+ method after the class is constructed.
|
37
|
+
## Otherwise, the class is not connected to the system and just discarded
|
38
|
+
## and then garbage collected.
|
39
|
+
##
|
40
|
+
## == Messages
|
41
|
+
## As a side effect of having single instances of plugins serve the requests
|
42
|
+
## of all sessions, the request/response/session messaging is implemented
|
43
|
+
## as messaging objects. These objects contain or delegate all the necessary
|
44
|
+
## hooks required by the complete request/response cycle.
|
45
|
+
##
|
46
|
+
## The naming convention of the +Message+ instance is +msg+ and it's
|
47
|
+
## given as the first parameter of methods needing it.
|
48
|
+
##
|
49
|
+
## Use +msg.ses_id+ to identify the session's serial number and +msg.user_id+
|
50
|
+
## to identify the user's identity.
|
51
|
+
##
|
52
|
+
## Use the +msg.session+ +Hash+ to store any persistent data
|
53
|
+
## associated with the user's session, preferably using the name of the
|
54
|
+
## plugin or its registered name as the primary key entry in the Hash.
|
55
|
+
## The session data is persistent; it's stored in the session database
|
56
|
+
## by +SessionStorage+ automatically.
|
57
|
+
##
|
58
|
+
## The +msg+ instance also provides access to the +Request+ and +Response+
|
59
|
+
## objects as +msg.request+ and +msg.response+, respectively.
|
60
|
+
##
|
61
|
+
## Use the +msg.run+ method to call other plugins.
|
62
|
+
##
|
63
|
+
## To append js source code to be evaluated in the client, use the +msg.reply+
|
64
|
+
## call. The +msg.console+ call appends messages to the browser's js console.
|
65
|
+
##
|
66
|
+
##
|
67
|
+
## == Session -related event methods
|
68
|
+
## The +#get_ses+ method returns (or creates and returns) the entry in
|
69
|
+
## the session based on the name your plugin is registered as. It's advised
|
70
|
+
## to use this call instead of manually managing +msg.session+ in most cases.
|
71
|
+
##
|
72
|
+
## The +#idle+ method is called each time a client performs a data
|
73
|
+
## synchronization or "idle poll" request.
|
74
|
+
##
|
75
|
+
## The +#init_ses+ method is called once in the same request a new session
|
76
|
+
## is created. A new session is created, when a user enters accesses the
|
77
|
+
## server the first time, or the first time after the previous session is
|
78
|
+
## expired.
|
79
|
+
##
|
80
|
+
## The +#init_ui+ method is called by the "main" plugin after the client has
|
81
|
+
## booted successfully. The +GUIPlugin+ class extends this method to
|
82
|
+
## automatically load and initialize the user interface from a data structure.
|
83
|
+
##
|
84
|
+
## The +#restore_ses+ method is called once in the same request an old
|
85
|
+
## session is restored. A session is restored, when the user returns to
|
86
|
+
## the page or reloads the page before the session is expired.
|
87
|
+
##
|
88
|
+
## === When the server is configured to restore previous sessions (default):
|
89
|
+
## If the user accesses the same page using the same browser (in different
|
90
|
+
## tabs or windows), only the most recently restored one is valid, while
|
91
|
+
## the previous ones are immediately invalidated.
|
92
|
+
## If your application is intended to support several sessions per browser,
|
93
|
+
## enable session cloning in the configuration file.
|
94
|
+
##
|
95
|
+
## === When the server is configured to restore and clone previous sessions:
|
96
|
+
## When sessions are cloned, the previous session is not invalidated and
|
97
|
+
## exists until timing out as a result of the web browser window being closed
|
98
|
+
## or client computer losing network connectivity for a certain (configurable)
|
99
|
+
## time frame.
|
100
|
+
##
|
101
|
+
## The +#cloned_target+ method is like +#restore_ses+, but called when
|
102
|
+
## the session is a clone of a previous session.
|
103
|
+
##
|
104
|
+
## The +#cloned_source+ method is called on the next request of the previous
|
105
|
+
## session after it has been cloned.
|
106
|
+
##
|
107
|
+
## == Server event methods
|
108
|
+
## Extend the +#init+ method to invoke constructor functionality that
|
109
|
+
## depends on the plugin to be constructed and registered as a part of
|
110
|
+
## the system.
|
111
|
+
##
|
112
|
+
## Extend the +#open+, +#flush+ and +#close+ methods to open, flush and close
|
113
|
+
## streams or other similar functionality.
|
114
|
+
##
|
115
|
+
## == Data handling
|
116
|
+
## The data exchange system exists to support bi-directional
|
117
|
+
## data synchronization between the browser and the plugin. The values
|
118
|
+
## are stored in the session as +HValue+ instances.
|
119
|
+
##
|
120
|
+
## Values support Hashes, Arrays, Strings, Numbers, Booleans and
|
121
|
+
## combinations of them. The data is automatically converted between
|
122
|
+
## ruby objects (server) and json objects (client).
|
123
|
+
##
|
124
|
+
## Each instance may be bound to plugin methods that are used as
|
125
|
+
## value change notification responders.
|
126
|
+
##
|
127
|
+
## When a method is bound to the value, the method is called as an
|
128
|
+
## event notification whenever the client has changed the value and
|
129
|
+
## synchronizes it to the server. The responders act as validators
|
130
|
+
## by default.
|
131
|
+
##
|
132
|
+
## Values are also bound in the client to classes implementing the
|
133
|
+
## HValueResponder interface, like any derivate of HControl. See the
|
134
|
+
## client documentation for instructions about using them.
|
135
|
+
##
|
136
|
+
## To define a value responder method, it needs to respond to exactly
|
137
|
+
## two parameters: the +Message+ instance +msg+ and the HValue object
|
138
|
+
## (in that order). The method's return value must be either +true+
|
139
|
+
## or +false+. When the method returns +false+, the change is discarded
|
140
|
+
## and the previously server-set value is sent back to the client.
|
141
|
+
##
|
142
|
+
## A minimal value responder method is defined like this:
|
143
|
+
##
|
144
|
+
## def my_value_responder( msg, my_value )
|
145
|
+
## return true
|
146
|
+
## end
|
147
|
+
##
|
148
|
+
## To access the content of the value, use the +HValue#data+ attribute.
|
149
|
+
##
|
150
|
+
## def int_between_100_and_200( msg, value )
|
151
|
+
## data = value.data.to_i
|
152
|
+
## return ( data >= 100 and data <= 200 )
|
153
|
+
## end
|
154
|
+
##
|
155
|
+
## To change the content of the value, use the +HValue#set+ method.
|
156
|
+
##
|
157
|
+
## def int_between_100_and_200( msg, value )
|
158
|
+
## data = value.data.to_i
|
159
|
+
## value.set( msg, 100 ) if data < 100
|
160
|
+
## value.set( msg, 200 ) if data > 200
|
161
|
+
## return true
|
162
|
+
## end
|
163
|
+
##
|
164
|
+
## == Defining values
|
165
|
+
## The simplest and recommended way of defining the values is to define
|
166
|
+
## the value configuration file +values.yaml+. Its configuration is then
|
167
|
+
## applied to sessions automatically.
|
168
|
+
##
|
169
|
+
##
|
170
|
+
## === Syntax reference of the contents of a +values.yaml+ file:
|
171
|
+
##
|
172
|
+
## # The name of the value (:value_name).
|
173
|
+
## # A hash key in the yaml syntax
|
174
|
+
## :value_name:
|
175
|
+
##
|
176
|
+
## # All of these keys are optional!
|
177
|
+
##
|
178
|
+
## # Default value, a string "Foo" here.
|
179
|
+
## # Defaults to 0
|
180
|
+
## :value: Foo
|
181
|
+
##
|
182
|
+
## # A plugin method to call to define the default value
|
183
|
+
## # instead of the one defined in :value
|
184
|
+
## :value_call:
|
185
|
+
## :plugin: plugin_name # defaults to the plugin where defined
|
186
|
+
##
|
187
|
+
## # Mandatory; name of the method to call
|
188
|
+
## :method: method_name
|
189
|
+
##
|
190
|
+
## # Optional, list of parameter values for the :method
|
191
|
+
## :args:
|
192
|
+
## # three parameters: 1, 'foo', 3
|
193
|
+
## - 1
|
194
|
+
## - foo
|
195
|
+
## - 3
|
196
|
+
##
|
197
|
+
## # When false, doesn't pass the msg as the first parameter.
|
198
|
+
## # Defaults to true
|
199
|
+
## :uses_msg: true
|
200
|
+
##
|
201
|
+
## # Restore the default, when the session is restored; defaults to false
|
202
|
+
## :restore_default: false
|
203
|
+
##
|
204
|
+
## # List of value responder methods to bind.
|
205
|
+
## :responders:
|
206
|
+
## -
|
207
|
+
## # name of plugin to call, defaults to the plugin where defined:
|
208
|
+
## :plugin: plugin_name
|
209
|
+
##
|
210
|
+
## # mandatory, name of the method to call
|
211
|
+
## :method: method_name
|
212
|
+
##
|
213
|
+
## # Another responder, this one using the same plugin where defined:
|
214
|
+
## - :method: another_method
|
215
|
+
##
|
216
|
+
## # Another value, this one just defining the defaults
|
217
|
+
## # by supplying an empty Hash:
|
218
|
+
## # (value: 0, default restored, no responders or calls)
|
219
|
+
## :value_with_defaults: {}
|
220
|
+
##
|
221
|
+
## # This value defines a Number (123) and doesn't restore
|
222
|
+
## # the default, when restoring the session.
|
223
|
+
## :one_two_three:
|
224
|
+
## :value: 123
|
225
|
+
## :restore_default: false
|
226
|
+
##
|
227
|
+
## # This value gets a random string and specifies a responder,
|
228
|
+
## # that ensures it's unique, if changed in the client.
|
229
|
+
## :random_unique_string:
|
230
|
+
## :value_call:
|
231
|
+
## :method: get_unique_random_string
|
232
|
+
## :uses_msg: false
|
233
|
+
## :responders:
|
234
|
+
## - :method: ensure_unique_random_string
|
235
|
+
##
|
236
|
+
## = Examples
|
237
|
+
## More examples are available in the repository;
|
238
|
+
## http://svn.rsence.org/contrib/plugins
|
239
|
+
## ..as well as the standard "main" plugin in the "plugins" directory.
|
240
|
+
##
|
241
|
+
##
|
242
|
+
## == A minimal Plugin bundle
|
243
|
+
## The minimal active plugin bundle (named "name_of_plugin")
|
244
|
+
## is defined like this:
|
245
|
+
##
|
246
|
+
## [dir] name_of_plugin
|
247
|
+
## |
|
248
|
+
## +---[file] name_of_plugin.rb
|
249
|
+
##
|
250
|
+
## This sample Plugin doesn't do anything except construct itself and
|
251
|
+
## respond as 'name_of_plugin'.
|
252
|
+
##
|
253
|
+
## Plugin.new.register('name_of_plugin')
|
254
|
+
##
|
255
|
+
## However, this is not very useful in itself, so you'll need to extend
|
256
|
+
## its functionality to do anything useful.
|
257
|
+
##
|
258
|
+
## == A simple Plugin extension
|
259
|
+
## This plugin logs session events to the logs/session_log file.
|
260
|
+
##
|
261
|
+
## [dir] ses_logger
|
262
|
+
## |
|
263
|
+
## +---[file] ses_logger.rb
|
264
|
+
## |
|
265
|
+
## +---[dir] logs
|
266
|
+
## |
|
267
|
+
## +---[file] session_log
|
268
|
+
##
|
269
|
+
## == Contents of "ses_logger.rb"
|
270
|
+
##
|
271
|
+
## class SessionLogger < Plugin
|
272
|
+
## def init
|
273
|
+
## super
|
274
|
+
## @logfile = false
|
275
|
+
## end
|
276
|
+
## def open
|
277
|
+
## log_path = compose_plugin_path( 'session_log', 'logs' )
|
278
|
+
## @logfile = File.open( log_path, 'a' )
|
279
|
+
## end
|
280
|
+
## def close
|
281
|
+
## @logfile.close if @logfile
|
282
|
+
## @logfile = false
|
283
|
+
## end
|
284
|
+
## def flush
|
285
|
+
## @logfile.flush if @logfile
|
286
|
+
## end
|
287
|
+
## def init_ses( msg )
|
288
|
+
## super
|
289
|
+
## @logfile.write( "#{Time.new} -- Session id #{msg.ses_id} was created.\n" )
|
290
|
+
## end
|
291
|
+
## def restore_ses( msg )
|
292
|
+
## super
|
293
|
+
## @logfile.write( "#{Time.new} -- Session id #{msg.ses_id} was restored.\n" )
|
294
|
+
## end
|
295
|
+
## def idle( msg )
|
296
|
+
## @logfile.write( "#{Time.new} -- Client of session id #{msg.ses_id} connected.\n" )
|
297
|
+
## end
|
298
|
+
## end
|
299
|
+
## SessionLogger.new.register( 'ses_logger' )
|
300
|
+
##
|
301
|
+
class Plugin
|
302
|
+
|
303
|
+
include PluginUtil
|
304
|
+
|
305
|
+
# The +names+ is a list of (usually just one) names the plugin is registered under.
|
306
|
+
attr_reader :name, :path, :info, :inited
|
307
|
+
|
308
|
+
# The constructor should not take any parameters. In most cases, it's better
|
309
|
+
# to extend the +#init+ method, because it's called after the plugin is set up.
|
310
|
+
def initialize
|
311
|
+
@inited = false
|
312
|
+
@info = @@bundle_info
|
313
|
+
@name = @@bundle_name
|
314
|
+
@path = @@bundle_path
|
315
|
+
@plugins = @@plugin_manager
|
316
|
+
register unless @info[:inits_self]
|
317
|
+
end
|
318
|
+
|
319
|
+
# Extend this method to do any initial tasks before other methods are called.
|
320
|
+
# By default init_values is called to load the +values.yaml+ configuration file.
|
321
|
+
def init
|
322
|
+
@values = init_values
|
323
|
+
end
|
324
|
+
|
325
|
+
# Extend this method to do any tasks every time the client makes a request.
|
326
|
+
def idle( msg )
|
327
|
+
end
|
328
|
+
|
329
|
+
# Extend this method to invoke actions, when a new session is created.
|
330
|
+
# By default +#init_ses_values+ is called to initialize values defined in the
|
331
|
+
# +values.yaml+ configuration file.
|
332
|
+
def init_ses( msg )
|
333
|
+
init_ses_values( msg )
|
334
|
+
end
|
335
|
+
|
336
|
+
# Extend this method to invoke actions, when a previous session is restored.
|
337
|
+
# By default +#restore_ses_values+ is called to perform actions on values as
|
338
|
+
# defined in the +values.yaml+ configuration file.
|
339
|
+
def restore_ses( msg )
|
340
|
+
restore_ses_values( msg )
|
341
|
+
end
|
342
|
+
|
343
|
+
# Extend this method to invoke actions, when the session
|
344
|
+
# is a clone of another session. It's called once, just
|
345
|
+
# before +#restore_ses+ is called.
|
346
|
+
#
|
347
|
+
# A session is cloned, when a user opens a another browser
|
348
|
+
# window or tab, while the previous session is still active.
|
349
|
+
#
|
350
|
+
# The +source_ses+ is the actual previous session object, which
|
351
|
+
# was used as the source of the clone.
|
352
|
+
def cloned_target( msg, source_session )
|
353
|
+
end
|
354
|
+
|
355
|
+
# Extend this method to invoke actions, when the session
|
356
|
+
# has been cloned to another session. It's called once, just
|
357
|
+
# before +#restore_ses+ is called on the first request after
|
358
|
+
# the cloning happened.
|
359
|
+
#
|
360
|
+
# A session is cloned, when a user opens a another browser
|
361
|
+
# window or tab, while the previous session is still active.
|
362
|
+
#
|
363
|
+
# The +target_ses+ is the actual cloned session object, which
|
364
|
+
# is a copy of the current session.
|
365
|
+
def cloned_source( msg, target_sessions )
|
366
|
+
end
|
367
|
+
|
368
|
+
# This method must be called to register the plugin instance
|
369
|
+
# into the system. Otherwise, it's subject to destruction
|
370
|
+
# and garbage collection. Use the +name+ parameter to
|
371
|
+
# give the (unique) name of your plugin.
|
372
|
+
def register( name=false )
|
373
|
+
if @inited
|
374
|
+
@plugins.register_alias( @name, name )
|
375
|
+
else
|
376
|
+
if name
|
377
|
+
name = name.to_s
|
378
|
+
else
|
379
|
+
name = @name
|
380
|
+
end
|
381
|
+
@plugins.register_bundle( self, name )
|
382
|
+
@inited = true
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
private
|
387
|
+
|
388
|
+
# This method looks looks for a file called "values.yaml"
|
389
|
+
# in the plugin's bundle directory
|
390
|
+
#.
|
391
|
+
# If this file is found, it loads it for initial value definitions.
|
392
|
+
#
|
393
|
+
# These definitions are accessible as the +@values+ attribute.
|
394
|
+
def init_values
|
395
|
+
values_path = compose_plugin_path( 'values.yaml' )
|
396
|
+
return yaml_read( values_path )
|
397
|
+
end
|
398
|
+
|
399
|
+
# Returns all the names your plugin respond to.
|
400
|
+
# def name
|
401
|
+
# return @names.first
|
402
|
+
# end
|
403
|
+
|
404
|
+
|
405
|
+
# Returns or creates a new session hash for the plugin.
|
406
|
+
#
|
407
|
+
# Uses the first name registered for the plugin and converts it to a symbol.
|
408
|
+
def get_ses( msg )
|
409
|
+
name_sym = name.to_sym
|
410
|
+
unless msg.session.has_key?( name_sym )
|
411
|
+
msg.session[ name_sym ] = {}
|
412
|
+
end
|
413
|
+
return msg.session[ name_sym ]
|
414
|
+
end
|
415
|
+
|
416
|
+
# Returns the source code of the javascript file +name+ in the 'js'
|
417
|
+
# subdirectory of the plugin bundle.
|
418
|
+
def read_js( js_name )
|
419
|
+
file_read( compose_plugin_path( js_name, 'js', '.js' ) )
|
420
|
+
end
|
421
|
+
|
422
|
+
# Deprecated name of +#read_js+
|
423
|
+
alias require_js read_js
|
424
|
+
|
425
|
+
# Like +#read_js+, but reads the file only once per session.
|
426
|
+
#
|
427
|
+
# Returns the contents of the file on the first call,
|
428
|
+
# an empty string on the subsequent calls.
|
429
|
+
#
|
430
|
+
# Returns false otherwise.
|
431
|
+
def read_js_once( msg, js_name )
|
432
|
+
ses = msg.session
|
433
|
+
if not ses.has_key?(:deps)
|
434
|
+
ses[:deps] = []
|
435
|
+
end
|
436
|
+
path = compose_plugin_path( js_name, 'js', '.js' )
|
437
|
+
unless ses[:deps].include?( path )
|
438
|
+
ses[:deps].push( path )
|
439
|
+
return file_read( path )
|
440
|
+
else
|
441
|
+
return ''
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
# Deprecated name of +#read_js_once+
|
446
|
+
alias require_js_once read_js_once
|
447
|
+
|
448
|
+
# Creates a new instance of HValue, assigns it as +value_name+ into the
|
449
|
+
# session and uses the +value_properties+ Hash to define the default
|
450
|
+
# value and value responders.
|
451
|
+
#
|
452
|
+
# This method is invoked automatically, when handling the properties
|
453
|
+
# of the +values.yaml+ configuration file of a new session.
|
454
|
+
#
|
455
|
+
# It's invoked by +#init_ses+ via +#init_ses_values+.
|
456
|
+
#
|
457
|
+
# Structure of +value_properties+, all top-level items are optional:
|
458
|
+
#
|
459
|
+
# {
|
460
|
+
# # Default value; defaults to 0
|
461
|
+
# :value => 'foo',
|
462
|
+
#
|
463
|
+
# # A plugin method to call to define the default value instead of the one defined in :value
|
464
|
+
# :value_call => {
|
465
|
+
# :plugin => 'plugin_name', # defaults to the plugin where defined
|
466
|
+
# :method => 'method_name', # mandatory; name of the method to call
|
467
|
+
# :args => [ 1, 'foo', 3 ], # optional, list of parameter values for the :method
|
468
|
+
# :uses_msg => true # defaults to true; when false, doesn't pass the msg as the first parameter
|
469
|
+
# },
|
470
|
+
#
|
471
|
+
# # Restore the default, when the session is restored; defaults to false
|
472
|
+
# :restore_default => false,
|
473
|
+
#
|
474
|
+
# # List of value responder methods to bind.
|
475
|
+
# :responders => [
|
476
|
+
# {
|
477
|
+
# :plugin => 'plugin_name', # defaults to the plugin where defined
|
478
|
+
# :method => 'method_name' # mandatory, name of the method to call
|
479
|
+
# },
|
480
|
+
# # You can supply as many responders as you like:
|
481
|
+
# { :plugin => 'another_plugin', :method => 'another_method' }
|
482
|
+
# ]
|
483
|
+
# }
|
484
|
+
#
|
485
|
+
def init_ses_value( msg, value_name, value_properties )
|
486
|
+
ses = get_ses( msg )
|
487
|
+
if value_properties.has_key?(:value_call)
|
488
|
+
default_value = init_value_call( msg, value_properties[:value_call] )
|
489
|
+
elsif value_properties.has_key?(:value)
|
490
|
+
default_value = value_properties[:value]
|
491
|
+
else
|
492
|
+
default_value = 0
|
493
|
+
end
|
494
|
+
ses[value_name] = HValue.new( msg, default_value )
|
495
|
+
if value_properties.has_key?(:responders)
|
496
|
+
value_properties[:responders].each do |responder|
|
497
|
+
if responder.has_key?(:plugin)
|
498
|
+
responder_plugin = responder[:plugin]
|
499
|
+
else
|
500
|
+
responder_plugin = @name
|
501
|
+
end
|
502
|
+
if responder.has_key?(:method)
|
503
|
+
ses[value_name].bind( responder_plugin, responder[:method] )
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
# Initializes session values, if the contents of the +values.yaml+
|
510
|
+
# file is defined in the bundle directory and loaded in +#init_values+.
|
511
|
+
def init_ses_values( msg )
|
512
|
+
return unless @values
|
513
|
+
@values.each do | value_name, value_properties |
|
514
|
+
init_ses_value( msg, value_name, value_properties )
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
# Returns a value based on the :method and :plugin members of the
|
519
|
+
# +value_call+ hash.
|
520
|
+
#
|
521
|
+
# The call is made via msg.run if the method is not defined in
|
522
|
+
# the local plugin bundle.
|
523
|
+
#
|
524
|
+
# This method is called from +#init_ses_value+.
|
525
|
+
#
|
526
|
+
# Structure of the +value_call+ Hash:
|
527
|
+
# { :plugin => 'plugin_name', # defaults to the plugin where defined
|
528
|
+
# :method => 'method_name', # mandatory; name of the method to call
|
529
|
+
# :args => [ 1, 'foo', 3 ], # optional, list of parameter values for the :method
|
530
|
+
# :uses_msg => true # defaults to true; when false, doesn't pass the msg as the first parameter
|
531
|
+
# }
|
532
|
+
def init_value_call( msg, value_call )
|
533
|
+
value_call_method = value_call[:method]
|
534
|
+
if value_call.has_key?(:plugin)
|
535
|
+
value_call_plugin = value_call[:plugin]
|
536
|
+
else
|
537
|
+
value_call_plugin = false
|
538
|
+
end
|
539
|
+
if value_call.has_key?(:args)
|
540
|
+
if value_call.has_key?(:uses_msg) and value_call[:uses_msg] != false
|
541
|
+
if value_call_plugin
|
542
|
+
return msg.run( value_call_plugin, value_call_method, msg, *value_call[:args] )
|
543
|
+
else
|
544
|
+
return self.method( value_call_method ).call( msg, *value_call[:args] )
|
545
|
+
end
|
546
|
+
else
|
547
|
+
if value_call_plugin
|
548
|
+
return msg.run( value_call_plugin, value_call_method, *value_call[:args] )
|
549
|
+
else
|
550
|
+
return self.method( value_call_method ).call( *value_call[:args] )
|
551
|
+
end
|
552
|
+
end
|
553
|
+
else
|
554
|
+
if value_call.has_key?(:uses_msg) and value_call[:uses_msg] != false
|
555
|
+
if value_call_plugin
|
556
|
+
return msg.run( value_call_plugin, value_call_method, msg )
|
557
|
+
else
|
558
|
+
return self.method( value_call_method ).call( msg )
|
559
|
+
end
|
560
|
+
else
|
561
|
+
if value_call_plugin
|
562
|
+
return msg.run( value_call_plugin, value_call_method )
|
563
|
+
else
|
564
|
+
return self.method( value_call_method ).call( )
|
565
|
+
end
|
566
|
+
end
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
# Restores session values to default, unless specified otherwise.
|
571
|
+
#
|
572
|
+
# Called from +#restore_ses+
|
573
|
+
def restore_ses_values( msg )
|
574
|
+
return unless @values
|
575
|
+
ses = get_ses( msg )
|
576
|
+
@values.each do | value_name, value_properties |
|
577
|
+
if ses.has_key?( value_name ) and ses[ value_name ].class == HValue
|
578
|
+
unless value_properties[:restore_default] == false
|
579
|
+
if value_properties.has_key?(:value_call)
|
580
|
+
default_value = init_value_call( msg, value_properties[:value_call] )
|
581
|
+
elsif value_properties.has_key?(:value)
|
582
|
+
default_value = value_properties[:value]
|
583
|
+
else
|
584
|
+
default_value = 0
|
585
|
+
end
|
586
|
+
ses[value_name].set( msg, default_value )
|
587
|
+
end
|
588
|
+
else
|
589
|
+
init_ses_value( msg, value_name, value_properties )
|
590
|
+
end
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
# Extracts +HValue+ references as javascript from the session Hash.
|
595
|
+
# The +ses+ parameter is used for supplying a hash with the +HValue+
|
596
|
+
# instances. It's optional and defaults to the current plugin node in
|
597
|
+
# the active session.
|
598
|
+
#
|
599
|
+
# The return value is a string representing a js object similar to
|
600
|
+
# the ruby Hash +ses+.
|
601
|
+
#
|
602
|
+
# Sample usage:
|
603
|
+
#
|
604
|
+
# values_js( msg, msg.session[:main] )
|
605
|
+
#
|
606
|
+
def values_js( msg, ses=false )
|
607
|
+
# backwards-compatible with pre-1.3 behaviour
|
608
|
+
ses = msg if msg.class == Hash
|
609
|
+
# gets the session automatically, if false
|
610
|
+
ses = get_ses( msg ) unless ses
|
611
|
+
js_references = []
|
612
|
+
ses.each_key do |key_name|
|
613
|
+
if ses[key_name].class == HValue
|
614
|
+
js_references.push( "#{key_name.to_s}:HVM.values['#{ses[key_name].val_id}']" )
|
615
|
+
end
|
616
|
+
end
|
617
|
+
return "{#{js_references.join(',')}}"
|
618
|
+
end
|
619
|
+
|
620
|
+
# Deprecated name of +#values_js+
|
621
|
+
alias extract_hvalues_from_hash values_js
|
622
|
+
|
623
|
+
# Tells the js client framework to load a list of dependency packages.
|
624
|
+
# It keeps track of what's loaded, so nothing library loaded twice.
|
625
|
+
#
|
626
|
+
# The +dependencies+ parameter is an Array of dependencies.
|
627
|
+
#
|
628
|
+
# Sample usage:
|
629
|
+
#
|
630
|
+
# include_js( msg, [ 'default_theme', 'controls', 'lists', 'datetime' ] )
|
631
|
+
#
|
632
|
+
def include_js( msg, dependencies=[] )
|
633
|
+
ses = msg.session
|
634
|
+
# check, if the session has a dependency array
|
635
|
+
if not ses.has_key?( :deps )
|
636
|
+
# make an array of dependencies for this session, if not already done
|
637
|
+
ses[:deps] = []
|
638
|
+
end
|
639
|
+
dependencies = [dependencies] if dependencies.class == String
|
640
|
+
# Check the required dependencies until everything is loaded.
|
641
|
+
dependencies.each do |dependency|
|
642
|
+
unless ses[:deps].include?( dependency )
|
643
|
+
ses[:deps].push( dependency )
|
644
|
+
msg.reply(%{jsLoader.load("#{dependency}");})
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
|
650
|
+
end
|
651
|
+
|
652
|
+
|