rsence-pre 2.1.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (313) hide show
  1. data/.yardopts +10 -0
  2. data/INSTALL.rdoc +330 -0
  3. data/LICENSE.txt +622 -0
  4. data/README.rdoc +98 -0
  5. data/VERSION +1 -0
  6. data/bin/rsence +25 -0
  7. data/bin/rsence-pre +25 -0
  8. data/conf/default_conf.yaml +346 -0
  9. data/conf/default_strings.yaml +76 -0
  10. data/conf/rsence_command_strings.yaml +444 -0
  11. data/docs/ExampleGuiPlugin.rdoc +193 -0
  12. data/docs/JavascriptBundles.rdoc +0 -0
  13. data/docs/PluginBundleInfo.rdoc +173 -0
  14. data/docs/PluginBundles.rdoc +96 -0
  15. data/docs/Values.rdoc +163 -0
  16. data/js/comm/autosync/autosync.js +17 -0
  17. data/js/comm/autosync/js.inc +0 -0
  18. data/js/comm/comm.js +203 -0
  19. data/js/comm/js.inc +0 -0
  20. data/js/comm/jsloader/js.inc +0 -0
  21. data/js/comm/jsloader/jsloader.js +112 -0
  22. data/js/comm/queue/js.inc +0 -0
  23. data/js/comm/queue/queue.js +184 -0
  24. data/js/comm/session/js.inc +0 -0
  25. data/js/comm/session/session.js +52 -0
  26. data/js/comm/sessionwatcher/js.inc +0 -0
  27. data/js/comm/sessionwatcher/sessionwatcher.js +44 -0
  28. data/js/comm/transporter/js.inc +0 -0
  29. data/js/comm/transporter/transporter.js +261 -0
  30. data/js/comm/urlresponder/js.inc +0 -0
  31. data/js/comm/urlresponder/urlresponder.js +149 -0
  32. data/js/comm/values/js.inc +0 -0
  33. data/js/comm/values/values.js +433 -0
  34. data/js/controls/button/button.js +72 -0
  35. data/js/controls/button/js.inc +0 -0
  36. data/js/controls/button/themes/bright/button.css +89 -0
  37. data/js/controls/button/themes/bright/button.html +7 -0
  38. data/js/controls/button/themes/bright/button_parts1-ie6.gif +0 -0
  39. data/js/controls/button/themes/bright/button_parts1.png +0 -0
  40. data/js/controls/button/themes/default/button.css +89 -0
  41. data/js/controls/button/themes/default/button.html +7 -0
  42. data/js/controls/button/themes/default/button_parts1-ie6.gif +0 -0
  43. data/js/controls/button/themes/default/button_parts1.png +0 -0
  44. data/js/controls/checkbox/checkbox.js +49 -0
  45. data/js/controls/checkbox/js.inc +0 -0
  46. data/js/controls/checkbox/themes/default/checkbox.css +69 -0
  47. data/js/controls/checkbox/themes/default/checkbox.html +5 -0
  48. data/js/controls/checkbox/themes/default/checkbox_parts1-ie6.gif +0 -0
  49. data/js/controls/checkbox/themes/default/checkbox_parts1.png +0 -0
  50. data/js/controls/dialogs/alert_sheet/alert_sheet.js +63 -0
  51. data/js/controls/dialogs/alert_sheet/js.inc +0 -0
  52. data/js/controls/dialogs/confirm_sheet/confirm_sheet.js +37 -0
  53. data/js/controls/dialogs/confirm_sheet/js.inc +0 -0
  54. data/js/controls/dialogs/sheet/js.inc +0 -0
  55. data/js/controls/dialogs/sheet/sheet.js +84 -0
  56. data/js/controls/dialogs/sheet/themes/default/sheet.css +64 -0
  57. data/js/controls/dialogs/sheet/themes/default/sheet.html +14 -0
  58. data/js/controls/dialogs/sheet/themes/default/sheet_bg-ie6.gif +0 -0
  59. data/js/controls/dialogs/sheet/themes/default/sheet_bg.png +0 -0
  60. data/js/controls/dialogs/sheet/themes/default/sheet_dim-ie6.gif +0 -0
  61. data/js/controls/dialogs/sheet/themes/default/sheet_dim.png +0 -0
  62. data/js/controls/dialogs/sheet/themes/default/sheet_parts1-ie6.gif +0 -0
  63. data/js/controls/dialogs/sheet/themes/default/sheet_parts1.png +0 -0
  64. data/js/controls/dialogs/sheet/themes/default/sheet_parts2-ie6.gif +0 -0
  65. data/js/controls/dialogs/sheet/themes/default/sheet_parts2.png +0 -0
  66. data/js/controls/dialogs/sheet/themes/default/sheet_warning-ie6.gif +0 -0
  67. data/js/controls/dialogs/sheet/themes/default/sheet_warning.png +0 -0
  68. data/js/controls/imageview/imageview.js +109 -0
  69. data/js/controls/imageview/js.inc +0 -0
  70. data/js/controls/imageview/themes/default/blank.gif +0 -0
  71. data/js/controls/passwordcontrol/js.inc +0 -0
  72. data/js/controls/passwordcontrol/passwordcontrol.js +23 -0
  73. data/js/controls/passwordcontrol/themes/default/passwordcontrol.css +0 -0
  74. data/js/controls/passwordcontrol/themes/default/passwordcontrol.html +18 -0
  75. data/js/controls/progress/progressbar/js.inc +0 -0
  76. data/js/controls/progress/progressbar/progressbar.js +40 -0
  77. data/js/controls/progress/progressbar/themes/default/progressbar.css +16 -0
  78. data/js/controls/progress/progressbar/themes/default/progressbar.html +2 -0
  79. data/js/controls/progress/progressindicator/js.inc +0 -0
  80. data/js/controls/progress/progressindicator/progressindicator.js +44 -0
  81. data/js/controls/radiobutton/js.inc +0 -0
  82. data/js/controls/radiobutton/radiobutton.js +43 -0
  83. data/js/controls/radiobutton/themes/default/radiobutton.css +69 -0
  84. data/js/controls/radiobutton/themes/default/radiobutton.html +5 -0
  85. data/js/controls/radiobutton/themes/default/radiobutton_parts1-ie6.gif +0 -0
  86. data/js/controls/radiobutton/themes/default/radiobutton_parts1.png +0 -0
  87. data/js/controls/sliders/slider/js.inc +0 -0
  88. data/js/controls/sliders/slider/slider.js +357 -0
  89. data/js/controls/sliders/slider/themes/default/hslider_tracks-ie6.gif +0 -0
  90. data/js/controls/sliders/slider/themes/default/hslider_tracks.png +0 -0
  91. data/js/controls/sliders/slider/themes/default/slider.css +108 -0
  92. data/js/controls/sliders/slider/themes/default/slider.html +5 -0
  93. data/js/controls/sliders/slider/themes/default/slider_thumbs-ie6.gif +0 -0
  94. data/js/controls/sliders/slider/themes/default/slider_thumbs.png +0 -0
  95. data/js/controls/sliders/vslider/js.inc +0 -0
  96. data/js/controls/sliders/vslider/themes/default/vslider.css +52 -0
  97. data/js/controls/sliders/vslider/themes/default/vslider.html +5 -0
  98. data/js/controls/sliders/vslider/themes/default/vslider_tracks-ie6.gif +0 -0
  99. data/js/controls/sliders/vslider/themes/default/vslider_tracks.png +0 -0
  100. data/js/controls/sliders/vslider/vslider.js +41 -0
  101. data/js/controls/stepper/js.inc +0 -0
  102. data/js/controls/stepper/stepper.js +213 -0
  103. data/js/controls/stepper/themes/default/stepper-ie6.gif +0 -0
  104. data/js/controls/stepper/themes/default/stepper.css +14 -0
  105. data/js/controls/stepper/themes/default/stepper.html +2 -0
  106. data/js/controls/stepper/themes/default/stepper.png +0 -0
  107. data/js/controls/stringview/js.inc +0 -0
  108. data/js/controls/stringview/stringview.js +49 -0
  109. data/js/controls/stringview/themes/default/stringview.css +8 -0
  110. data/js/controls/stringview/themes/default/stringview.html +1 -0
  111. data/js/controls/tab/js.inc +0 -0
  112. data/js/controls/tab/tab.js +280 -0
  113. data/js/controls/tab/themes/bright/tab.css +76 -0
  114. data/js/controls/tab/themes/bright/tab.html +6 -0
  115. data/js/controls/tab/themes/bright/tab_bg_color-ie6.gif +0 -0
  116. data/js/controls/tab/themes/bright/tab_bg_color.png +0 -0
  117. data/js/controls/tab/themes/bright/tab_border_pattern-ie6.gif +0 -0
  118. data/js/controls/tab/themes/bright/tab_border_pattern.png +0 -0
  119. data/js/controls/tab/themes/bright/tab_parts1-ie6.gif +0 -0
  120. data/js/controls/tab/themes/bright/tab_parts1.png +0 -0
  121. data/js/controls/tab/themes/default/tab.css +77 -0
  122. data/js/controls/tab/themes/default/tab.html +6 -0
  123. data/js/controls/tab/themes/default/tab_bg_color-ie6.gif +0 -0
  124. data/js/controls/tab/themes/default/tab_bg_color.png +0 -0
  125. data/js/controls/tab/themes/default/tab_border_pattern-ie6.gif +0 -0
  126. data/js/controls/tab/themes/default/tab_border_pattern.png +0 -0
  127. data/js/controls/tab/themes/default/tab_parts1-ie6.gif +0 -0
  128. data/js/controls/tab/themes/default/tab_parts1.png +0 -0
  129. data/js/controls/textarea/js.inc +0 -0
  130. data/js/controls/textarea/textarea.js +24 -0
  131. data/js/controls/textarea/themes/default/textarea.css +21 -0
  132. data/js/controls/textarea/themes/default/textarea.html +18 -0
  133. data/js/controls/textcontrol/js.inc +0 -0
  134. data/js/controls/textcontrol/textcontrol.js +374 -0
  135. data/js/controls/textcontrol/themes/default/textcontrol.css +107 -0
  136. data/js/controls/textcontrol/themes/default/textcontrol.html +18 -0
  137. data/js/controls/textcontrol/themes/default/textcontrol_parts1-ie6.gif +0 -0
  138. data/js/controls/textcontrol/themes/default/textcontrol_parts1.png +0 -0
  139. data/js/controls/textcontrol/themes/default/textcontrol_parts2-ie6.gif +0 -0
  140. data/js/controls/textcontrol/themes/default/textcontrol_parts2.png +0 -0
  141. data/js/controls/textcontrol/themes/default/textcontrol_parts3-ie6.gif +0 -0
  142. data/js/controls/textcontrol/themes/default/textcontrol_parts3.png +0 -0
  143. data/js/controls/uploader/js.inc +0 -0
  144. data/js/controls/uploader/themes/default/upload_progress.gif +0 -0
  145. data/js/controls/uploader/themes/default/uploader.css +108 -0
  146. data/js/controls/uploader/themes/default/uploader.html +27 -0
  147. data/js/controls/uploader/uploader.js +154 -0
  148. data/js/controls/validatorview/js.inc +0 -0
  149. data/js/controls/validatorview/themes/default/validator-ie6.gif +0 -0
  150. data/js/controls/validatorview/themes/default/validator.png +0 -0
  151. data/js/controls/validatorview/themes/default/validatorview.css +0 -0
  152. data/js/controls/validatorview/themes/default/validatorview.html +0 -0
  153. data/js/controls/validatorview/validatorview.js +62 -0
  154. data/js/controls/window/js.inc +0 -0
  155. data/js/controls/window/themes/default/window.css +219 -0
  156. data/js/controls/window/themes/default/window.html +17 -0
  157. data/js/controls/window/themes/default/window_bg_active-ie6.gif +0 -0
  158. data/js/controls/window/themes/default/window_bg_active.png +0 -0
  159. data/js/controls/window/themes/default/window_bg_inactive-ie6.gif +0 -0
  160. data/js/controls/window/themes/default/window_bg_inactive.png +0 -0
  161. data/js/controls/window/themes/default/window_buttons-ie6.gif +0 -0
  162. data/js/controls/window/themes/default/window_buttons.png +0 -0
  163. data/js/controls/window/themes/default/window_parts1-ie6.gif +0 -0
  164. data/js/controls/window/themes/default/window_parts1.png +0 -0
  165. data/js/controls/window/themes/default/window_parts2-ie6.gif +0 -0
  166. data/js/controls/window/themes/default/window_parts2.png +0 -0
  167. data/js/controls/window/window.js +286 -0
  168. data/js/core/class/class.js +318 -0
  169. data/js/core/class/js.inc +0 -0
  170. data/js/core/elem/elem.js +1383 -0
  171. data/js/core/elem/js.inc +0 -0
  172. data/js/core/event/event.js +153 -0
  173. data/js/core/event/js.inc +0 -0
  174. data/js/core/iefix/ie_css_element.htc +5 -0
  175. data/js/core/iefix/ie_css_style.htc +5 -0
  176. data/js/core/iefix/iefix.js +359 -0
  177. data/js/core/iefix/js.inc +0 -0
  178. data/js/core/rsence_ns/js.inc +0 -0
  179. data/js/core/rsence_ns/rsence_ns.js +21 -0
  180. data/js/datetime/calendar/calendar.js +198 -0
  181. data/js/datetime/calendar/js.inc +0 -0
  182. data/js/datetime/calendar/themes/default/calendar.css +108 -0
  183. data/js/datetime/calendar/themes/default/calendar.html +9 -0
  184. data/js/datetime/calendar/themes/default/calendar_arrows-ie6.gif +0 -0
  185. data/js/datetime/calendar/themes/default/calendar_arrows.png +0 -0
  186. data/js/datetime/datetimevalue/datetimevalue.js +247 -0
  187. data/js/datetime/datetimevalue/js.inc +0 -0
  188. data/js/datetime/timesheet/js.inc +0 -0
  189. data/js/datetime/timesheet/themes/default/timesheet.css +30 -0
  190. data/js/datetime/timesheet/themes/default/timesheet.html +2 -0
  191. data/js/datetime/timesheet/timesheet.js +183 -0
  192. data/js/datetime/timesheet_item/js.inc +0 -0
  193. data/js/datetime/timesheet_item/themes/default/timesheet_item.css +42 -0
  194. data/js/datetime/timesheet_item/themes/default/timesheet_item.html +8 -0
  195. data/js/datetime/timesheet_item/timesheet_item.js +248 -0
  196. data/js/datetime/timesheet_item_edit/js.inc +0 -0
  197. data/js/datetime/timesheet_item_edit/timesheet_item_edit.js +274 -0
  198. data/js/foundation/application/application.js +208 -0
  199. data/js/foundation/application/js.inc +0 -0
  200. data/js/foundation/control/control.js +339 -0
  201. data/js/foundation/control/controldefaults/controldefaults.js +56 -0
  202. data/js/foundation/control/controldefaults/js.inc +0 -0
  203. data/js/foundation/control/dummyvalue/dummyvalue.js +51 -0
  204. data/js/foundation/control/dummyvalue/js.inc +0 -0
  205. data/js/foundation/control/dyncontrol/dyncontrol.js +500 -0
  206. data/js/foundation/control/dyncontrol/js.inc +0 -0
  207. data/js/foundation/control/dyncontrol/themes/default/dyncontrol.css +0 -0
  208. data/js/foundation/control/dyncontrol/themes/default/dyncontrol.html +0 -0
  209. data/js/foundation/control/eventresponder/eventresponder.js +750 -0
  210. data/js/foundation/control/eventresponder/js.inc +0 -0
  211. data/js/foundation/control/js.inc +0 -0
  212. data/js/foundation/control/valuematrix/js.inc +0 -0
  213. data/js/foundation/control/valuematrix/valuematrix.js +135 -0
  214. data/js/foundation/control/valueresponder/js.inc +0 -0
  215. data/js/foundation/control/valueresponder/valueresponder.js +79 -0
  216. data/js/foundation/eventmanager/eventmanager.js +991 -0
  217. data/js/foundation/eventmanager/js.inc +0 -0
  218. data/js/foundation/geom/point/js.inc +0 -0
  219. data/js/foundation/geom/point/point.js +202 -0
  220. data/js/foundation/geom/rect/js.inc +0 -0
  221. data/js/foundation/geom/rect/rect.js +651 -0
  222. data/js/foundation/json_renderer/js.inc +0 -0
  223. data/js/foundation/json_renderer/json_renderer.js +246 -0
  224. data/js/foundation/system/js.inc +0 -0
  225. data/js/foundation/system/system.js +381 -0
  226. data/js/foundation/thememanager/js.inc +0 -0
  227. data/js/foundation/thememanager/thememanager.js +393 -0
  228. data/js/foundation/value/js.inc +0 -0
  229. data/js/foundation/value/value.js +183 -0
  230. data/js/foundation/view/js.inc +0 -0
  231. data/js/foundation/view/markupview/js.inc +0 -0
  232. data/js/foundation/view/markupview/markupview.js +114 -0
  233. data/js/foundation/view/morphanimation/js.inc +0 -0
  234. data/js/foundation/view/morphanimation/morphanimation.js +237 -0
  235. data/js/foundation/view/view.js +1812 -0
  236. data/js/foundation/view/viewdefaults/js.inc +0 -0
  237. data/js/foundation/view/viewdefaults/viewdefaults.js +26 -0
  238. data/js/lists/checkboxlist/checkboxlist.js +171 -0
  239. data/js/lists/checkboxlist/js.inc +0 -0
  240. data/js/lists/listitems/js.inc +0 -0
  241. data/js/lists/listitems/listitems.js +88 -0
  242. data/js/lists/propertylist/js.inc +0 -0
  243. data/js/lists/propertylist/propertylist.js +326 -0
  244. data/js/lists/radiobuttonlist/js.inc +0 -0
  245. data/js/lists/radiobuttonlist/radiobuttonlist.js +116 -0
  246. data/js/util/reloadapp/js.inc +0 -0
  247. data/js/util/reloadapp/reloadapp.js +152 -0
  248. data/js/util/reloadapp/themes/default/reloadapp_warning-ie6.gif +0 -0
  249. data/js/util/reloadapp/themes/default/reloadapp_warning.png +0 -0
  250. data/js/util/sha/js.inc +0 -0
  251. data/js/util/sha/sha.js +426 -0
  252. data/js/views/centerview/centerview.js +75 -0
  253. data/js/views/centerview/js.inc +0 -0
  254. data/js/views/inlineview/inlineview.js +15 -0
  255. data/js/views/inlineview/js.inc +0 -0
  256. data/js/views/scrollview/js.inc +0 -0
  257. data/js/views/scrollview/scrollview.js +40 -0
  258. data/lib/conf/argv.rb +850 -0
  259. data/lib/conf/default.rb +219 -0
  260. data/lib/daemon/daemon.rb +387 -0
  261. data/lib/daemon/sigcomm.rb +64 -0
  262. data/lib/http/broker.rb +150 -0
  263. data/lib/http/rackup.rb +91 -0
  264. data/lib/http/request.rb +66 -0
  265. data/lib/http/response.rb +65 -0
  266. data/lib/plugins/dependencies.rb +285 -0
  267. data/lib/plugins/gui_plugin.rb +160 -0
  268. data/lib/plugins/guiparser.rb +123 -0
  269. data/lib/plugins/plugin.rb +438 -0
  270. data/lib/plugins/plugin_base.rb +162 -0
  271. data/lib/plugins/plugin_plugins.rb +81 -0
  272. data/lib/plugins/plugin_sqlite_db.rb +98 -0
  273. data/lib/plugins/pluginmanager.rb +635 -0
  274. data/lib/plugins/plugins.rb +169 -0
  275. data/lib/plugins/servlet.rb +108 -0
  276. data/lib/rsence.rb +32 -0
  277. data/lib/session/msg.rb +327 -0
  278. data/lib/session/sessionmanager.rb +522 -0
  279. data/lib/session/sessionstorage.rb +340 -0
  280. data/lib/transporter/transporter.rb +263 -0
  281. data/lib/util/gzstring.rb +9 -0
  282. data/lib/util/ruby19_fixes.rb +18 -0
  283. data/lib/values/hvalue.rb +378 -0
  284. data/lib/values/valuemanager.rb +172 -0
  285. data/plugins/client_pkg/client_pkg.rb +157 -0
  286. data/plugins/client_pkg/info.yaml +25 -0
  287. data/plugins/client_pkg/lib/client_pkg_build.rb +561 -0
  288. data/plugins/client_pkg/lib/client_pkg_cache.rb +50 -0
  289. data/plugins/client_pkg/lib/client_pkg_serve.rb +218 -0
  290. data/plugins/index_html/img/loading.gif +0 -0
  291. data/plugins/index_html/img/riassence.gif +0 -0
  292. data/plugins/index_html/index_html.rb +120 -0
  293. data/plugins/index_html/info.yaml +18 -0
  294. data/plugins/index_html/tmpl/index.html +15 -0
  295. data/plugins/main/info.yaml +18 -0
  296. data/plugins/main/js/main.js +84 -0
  297. data/plugins/main/main.rb +255 -0
  298. data/plugins/main/values.yaml +8 -0
  299. data/plugins/ticket/info.yaml +21 -0
  300. data/plugins/ticket/lib/common.rb +392 -0
  301. data/plugins/ticket/lib/favicon.rb +39 -0
  302. data/plugins/ticket/lib/file.rb +58 -0
  303. data/plugins/ticket/lib/img.rb +50 -0
  304. data/plugins/ticket/lib/objblob.rb +66 -0
  305. data/plugins/ticket/lib/rsrc.rb +34 -0
  306. data/plugins/ticket/lib/upload.rb +236 -0
  307. data/plugins/ticket/ticket.rb +333 -0
  308. data/setup/welcome/gui/welcome.yaml +92 -0
  309. data/setup/welcome/info.yaml +13 -0
  310. data/setup/welcome/text/welcome.html +9 -0
  311. data/setup/welcome/values.yaml +9 -0
  312. data/setup/welcome/welcome.rb +54 -0
  313. metadata +407 -0
@@ -0,0 +1,635 @@
1
+ ## RSence
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
+
10
+ require 'plugins/plugins'
11
+ require 'plugins/dependencies'
12
+
13
+ module RSence
14
+
15
+ ## PluginManager is the service that loads and provides method delegation
16
+ ## amongst its plugin bundles.
17
+ ##
18
+ ## = Usage
19
+ ## plugin_paths = [ 'plugins', '/home/me/rsence/plugins' ]
20
+ ## myPluginManager = RSence::PluginManager.new( plugin_paths )
21
+ ##
22
+ class PluginManager
23
+
24
+ attr_reader :transporter, :sessions
25
+
26
+ # Returns the registry data for plugin bundle +plugin_name+
27
+ def registry( plugin_name )
28
+ return @registry[ plugin_name ]
29
+ end
30
+ alias [] registry
31
+
32
+ # By default, calling a method not defined calls a plugin of that name
33
+ def method_missing( sym, *args, &block )
34
+ if @registry.has_key?(sym)
35
+ if args == [] and block == nil
36
+ return @registry[sym]
37
+ elsif block == nil
38
+ call( sym, *args )
39
+ end
40
+ end
41
+ end
42
+
43
+ # Registers alias name for a plugin bundle.
44
+ def register_alias( bundle_name, alias_name )
45
+ if @aliases.has_key?( alias_name.to_sym )
46
+ warn "Alias already taken: #{alias_name.inspect}"
47
+ else
48
+ @aliases[ alias_name ] = bundle_name.to_sym
49
+ end
50
+ end
51
+
52
+ # Registers plugin class +inst+ into the registry using +bundle_name+
53
+ def register_bundle( inst, bundle_name )
54
+ bundle_name = bundle_name.to_sym
55
+ if @registry.has_key?( bundle_name )
56
+ if registry[ bundle_name ] != inst
57
+ warn "Tried to register a conflicting bundle name: #{bundle_name.inspect}; ignoring"
58
+ else
59
+ warn "Use @plugins.register_alias to register more than one name per plugin."
60
+ register_alias( inst.name.to_sym, bundle_name )
61
+ end
62
+ else
63
+ inst.init if inst.respond_to? :init and not inst.inited
64
+ @registry[ bundle_name ] = inst
65
+ if inst.respond_to?( :match ) and ( inst.respond_to?( :get ) or inst.respond_to?( :post ) )
66
+ @servlets.push( bundle_name )
67
+ end
68
+ end
69
+ end
70
+
71
+ def callable?( plugin_name, method_name )
72
+ return false if @deps.category?( plugin_name )
73
+ return false unless @registry.has_key?( plugin_name )
74
+ plugin = @registry[plugin_name]
75
+ return false unless plugin.respond_to?( method_name )
76
+ return true
77
+ end
78
+
79
+ # Calls the method +method_name+ with args +args+ of the plugin +plugin_name+.
80
+ # Returns false, if no such plugin or method exists.
81
+ def call( plugin_name, method_name, *args )
82
+ plugin_name = plugin_name.to_sym
83
+ if callable?( plugin_name, method_name )
84
+ begin
85
+ return @registry[ plugin_name ].send( method_name, *args )
86
+ rescue => e
87
+ plugin_error(
88
+ e,
89
+ "RSence::PluginManager.call error",
90
+ "plugin_name: #{plugin_name.inspect}, method_name: #{method_name.inspect}",
91
+ plugin_name
92
+ )
93
+ end
94
+ elsif @deps.category?( plugin_name )
95
+ warn "Warning! Tried to call category: #{plugin_name.inpsect}"
96
+ elsif not @registry.has_key?( plugin_name )
97
+ warn "Warning! No such plugin: #{plugin_name.inspect}"
98
+ elsif not @registry[ plugin_name ].respond_to?( method_name )
99
+ warn "Warning! Plugin: #{plugin_name.inspect} does not respond to #{method_name.inspect}"
100
+ end
101
+ return false
102
+ end
103
+ alias run_plugin call
104
+
105
+ # Prettier error handling.
106
+ def plugin_error( e, err_location, err_location_descr, eval_repl=false )
107
+ err_msg = [
108
+ "*"*40,
109
+ err_location,
110
+ err_location_descr,
111
+ "#{e.class.to_s}, #{e.message}",
112
+ "Backtrace:",
113
+ "\t"+e.backtrace.join("\n\t"),
114
+ "*"*40
115
+ ].join("\n")+"\n"
116
+ if eval_repl
117
+ puts
118
+ puts "plugin: #{eval_repl}"
119
+ puts
120
+ err_msg = err_msg.gsub(/^\t\(eval\)\:/s,"\t#{eval_repl}:")
121
+ end
122
+ $stderr.write( err_msg )
123
+ end
124
+
125
+ # Search servlets that match the +uri+ and +req_type+
126
+ def match_servlet_uri( uri, req_type=:get )
127
+ match_score = {}
128
+ @servlets.each do | servlet_name |
129
+ servlet = @registry[ servlet_name ]
130
+ next unless servlet.respond_to?( req_type )
131
+ begin
132
+ if servlet.match( uri, req_type )
133
+ score = servlet.score
134
+ match_score[ score ] = [] unless match_score.has_key? score
135
+ match_score[ score ].push( servlet_name )
136
+ end
137
+ rescue => e
138
+ plugin_error(
139
+ e,
140
+ "RSence::PluginManager.match_servlet_uri",
141
+ "servlet: #{servlet_name.inspect}, req_type: #{req_type.inspect}, uri: #{uri.inspect}",
142
+ servlet_name
143
+ )
144
+ end
145
+ end
146
+ match_scores = match_score.keys.sort
147
+ if match_scores.empty?
148
+ return false
149
+ else
150
+ matches_order = []
151
+ matches_best = match_score[ match_scores[0] ]
152
+ if matches_best.size > 1
153
+ matches_best = matches_best[ rand( matches_best.size ) ]
154
+ else
155
+ matches_best = matches_best.first
156
+ end
157
+ matches_order.push( matches_best )
158
+ match_score.keys.sort.each do |match_n|
159
+ match_score[ match_n ].each do | match_name |
160
+ matches_order.push( match_name ) unless matches_order.include? match_name
161
+ end
162
+ end
163
+ return matches_order
164
+ end
165
+ end
166
+
167
+ # Calls the servlet that matches the +req_type+ and +req.fullpath+ with
168
+ # the highest score.
169
+ def match_servlet( req_type, req, resp, session )
170
+ req_uri = req.fullpath
171
+ matches_order = match_servlet_uri( req_uri, req_type )
172
+ return false unless matches_order
173
+ matches_order.each do |servlet_name|
174
+ begin
175
+ @registry[servlet_name].send( req_type, req, resp, session )
176
+ return true
177
+ rescue => e
178
+ plugin_error(
179
+ e,
180
+ "RSence::PluginManager.match_servlet",
181
+ "servlet_name: #{servlet_name.inspect}, req_type: #{req_type.inspect}",
182
+ servlet_name
183
+ )
184
+ next
185
+ end
186
+ end
187
+ return false
188
+ end
189
+
190
+ # Delegates +method_name+ with +args+ to any loaded
191
+ # plugin that responds to the method.
192
+ def delegate( method_name, *args )
193
+ @deps.list.each do |plugin_name|
194
+ call( plugin_name, method_name, *args ) if callable?( plugin_name, method_name )
195
+ end
196
+ end
197
+
198
+ # Reverse delegate +method_name+ with +args+ to any loaded
199
+ # plugin that responds to the method.
200
+ def delegate_reverse( method_name, *args )
201
+ @deps.list.reverse.each do |plugin_name|
202
+ call( plugin_name, method_name, *args ) if callable?( plugin_name, method_name )
203
+ end
204
+ end
205
+
206
+ # Delegates the +flush+ and +close+ methods to any
207
+ # loaded plugins, in that order.
208
+ def shutdown
209
+ @transporter.online = false
210
+ @deps.list.reverse.each do |bundle_name|
211
+ unload_bundle( bundle_name )
212
+ end
213
+ end
214
+
215
+ # Finds the most recent file in the path
216
+ def most_recent( bundle_path, newest_date=0 )
217
+ path_date = File.stat( bundle_path ).mtime.to_i
218
+ is_dir = File.directory?( bundle_path )
219
+ if path_date > newest_date and not is_dir
220
+ newest_date = path_date
221
+ end
222
+ if is_dir
223
+ Dir.entries( bundle_path ).each do |entry_name|
224
+ next if entry_name[0].chr == '.'
225
+ full_path = File.join( bundle_path, entry_name )
226
+ unless File.directory?( full_path )
227
+ has_dot = entry_name.include?('.')
228
+ next unless has_dot
229
+ is_src_file = ['yaml','rb'].include?( entry_name.split('.')[-1] )
230
+ next unless is_src_file
231
+ end
232
+ newest_date = most_recent( full_path, newest_date )
233
+ end
234
+ end
235
+ return newest_date
236
+ end
237
+
238
+ # Gets plugin information
239
+ def bundle_info( bundle_path, bundle_name, src_file )
240
+
241
+ # Default bundle information
242
+ info = {
243
+
244
+ # The human-readable product name of the package
245
+ :title => bundle_name.to_s.capitalize,
246
+
247
+ # The human-readable version of the package
248
+ :version => '0.0.0',
249
+
250
+ # A brief description of the package (rdoc formatting supported)
251
+ :description => 'No Description',
252
+
253
+ # A flag (when false) prevents the plugin from automatically reload when changed.
254
+ :reloadable => true,
255
+
256
+ # System version requirement.
257
+ # NOTE: Has no effect yet!
258
+ :sys_version => '>= 1.0.0',
259
+
260
+ # Dependency, by default the system category (built-in plugins).
261
+ # A nil ( "~" in yaml ) value means no dependencies.
262
+ :depends_on => [ :system ],
263
+
264
+ # Optional, name of category. The built-in plugins are :system
265
+ :category => nil,
266
+
267
+ # Optional, name of plugin to replace
268
+ # NOTE: Has no effect yet!
269
+ :replaces => nil,
270
+
271
+ # Optional, reverse dependency. Loads before the prepended plugin(category).
272
+ # NOTE: Doesn't support packages yet!
273
+ :prepends => nil
274
+
275
+ }
276
+
277
+ # Merge info.yaml data into info
278
+ info_path = File.join( bundle_path, 'info.yaml' )
279
+ if File.exists?( info_path )
280
+ info_yaml = YAML.load( File.read( info_path ) )
281
+ info_yaml.each do |info_key,info_value|
282
+ info[ info_key.to_sym ] = info_value
283
+ end
284
+ else
285
+ warn "Expected info.yaml, using defaults:"
286
+ warn " #{info_path}"
287
+ end
288
+
289
+ @deps.set_deps( bundle_name, info[:depends_on] )
290
+ if info[:category]
291
+ if info[:category].class == Symbol
292
+ @deps.add_category( info[:category] ) unless @deps.category?( info[:category] )
293
+ @deps.set_deps( info[:category], bundle_name )
294
+ else
295
+ warn "Invalid category: #{info[:category].inspect}"
296
+ end
297
+ end
298
+ if info[:prepends]
299
+ if info[:prepends].class == Array
300
+ info[:prepends].each do |prep|
301
+ @deps.set_deps( prep, bundle_name )
302
+ end
303
+ else
304
+ @deps.set_deps( info[:prepends], bundle_name )
305
+ end
306
+ end
307
+
308
+ # Extra information, not override-able in info.yaml
309
+
310
+ # Path of bundle
311
+ info[:path] = bundle_path
312
+
313
+ # Name of bundle
314
+ info[:name] = bundle_name
315
+
316
+ # Full path of source file
317
+ info[:src_file] = src_file
318
+
319
+ # Timestamp of last changed file
320
+ info[:last_changed] = most_recent( bundle_path )
321
+
322
+ # ..however, don't accept future timestamps:
323
+ time_now = Time.now.to_i
324
+ info[:last_changed] = time_now if info[:last_changed] > time_now
325
+
326
+ return info
327
+ end
328
+
329
+ # Loads a plugin bundle.
330
+ def load_bundle( name )
331
+
332
+ if @deps.unresolved?(name)
333
+ warn "Warning: Bundle #{name} has unmet dependencies."
334
+ return
335
+ end
336
+
337
+ if @registry.has_key?( name )
338
+ warn "Warning: Bundle #{name} already loaded."
339
+ return
340
+ end
341
+ puts "Loading bundle: #{name.inspect}" if RSence.args[:debug]
342
+
343
+ info = @info[ name ]
344
+
345
+ path = info[:path]
346
+ src_file = info[:src_file]
347
+
348
+ bundle_src = File.read( src_file )
349
+
350
+ module_ns = Plugins.bundle_loader( {
351
+ :bundle_path => path,
352
+ :bundle_name => name,
353
+ :bundle_info => info,
354
+ :plugin_manager => self,
355
+ :src_path => src_file,
356
+ :src => bundle_src
357
+ } )
358
+
359
+ module_ns.constants.each do |module_const_name|
360
+ module_const = module_ns.const_get( module_const_name )
361
+ if module_const.class == Class
362
+ type = module_const.bundle_type
363
+ if [:Servlet, :Plugin, :GUIPlugin].include? type
364
+ bundle_inst = module_const.new( name, info, path, self )
365
+ bundle_inst.register( name ) if [ :Plugin, :GUIPlugin ].include?( type )
366
+ break
367
+ else
368
+ warn "Can't init class: #{module_const.to_s}"
369
+ break
370
+ end
371
+ else
372
+ warn "Invalid module_const.class: #{module_const.class.inspect}"
373
+ end
374
+ end
375
+ end
376
+
377
+ # loads all bundles found in order of dependency
378
+ def load_bundles
379
+ @deps.list.each do |name|
380
+ load_bundle( name ) if @deps.loadable?( name )
381
+ end
382
+ end
383
+
384
+ # If a bundle is found, set its dependencies etc
385
+ def bundle_found( bundle_path, bundle_name, src_file )
386
+ @info[ bundle_name ] = bundle_info( bundle_path, bundle_name, src_file )
387
+ end
388
+
389
+ # Returns false, if the plugin directory isn't valid.
390
+ # Returns [bundle_path, src_file] otherwise.
391
+ def valid_plugindir?( path, bundle_name )
392
+ return false if bundle_name[0].chr == '.'
393
+ bundle_path = File.expand_path( File.join( path, bundle_name ) )
394
+ return false unless File.directory?( bundle_path )
395
+ bundle_file = bundle_name+'.rb'
396
+ src_file = File.join( bundle_path, bundle_file )
397
+ if not File.exists?( src_file )
398
+ bundle_file = 'main.rb'
399
+ src_file = File.join( bundle_path, bundle_file )
400
+ return false unless File.exists?( src_file )
401
+ end
402
+ return [ bundle_path, src_file ]
403
+ end
404
+
405
+ # Returns true, if the bundle is disabled
406
+ def disabled?( bundle_path )
407
+ File.exists?( File.join( bundle_path, 'disabled' ) )
408
+ end
409
+
410
+ # Returns true, if the bundle is loaded.
411
+ def loaded?( bundle_name )
412
+ @registry.has_key?( bundle_name )
413
+ end
414
+
415
+ # Scans a directory of plugins, calls +load_plugin+ for bundles that match
416
+ # the definition of a plugin bundle.
417
+ # - Skips bundles starting with a dot
418
+ # - Skips bundles without a ruby source file with the same
419
+ # name as the directory (plus '.rb').
420
+ # - Skips bundles containing a file or directory named 'disabled'
421
+ def find_bundles( path )
422
+ bundles_found = []
423
+ Dir.entries(path).each do |bundle_name|
424
+ bundle_status = valid_plugindir?( path, bundle_name )
425
+ if bundle_status
426
+ (bundle_path, src_file) = bundle_status
427
+ unless disabled?( bundle_path )
428
+ bundles_found.push( [bundle_path, bundle_name.to_sym, src_file] )
429
+ end
430
+ end
431
+ end
432
+ return bundles_found
433
+ end
434
+
435
+ # Unloads the plugin bundle named +bundle_name+
436
+ def unload_bundle( bundle_name )
437
+ if @registry.has_key?( bundle_name )
438
+ unload_order = @deps.del_order( bundle_name )
439
+ unload_order.each do |unload_dep|
440
+ unload_bundle( unload_dep ) unless unload_dep == bundle_name
441
+ end
442
+ puts "Unloading bundle: #{bundle_name.inspect}" if RSence.args[:debug]
443
+ @deps.del_item( bundle_name )
444
+ online_status = @transporter.online?
445
+ @transporter.online = false
446
+ call( bundle_name, :flush )
447
+ call( bundle_name, :close )
448
+ @registry.delete( bundle_name )
449
+ @aliases.each do |a_name,b_name|
450
+ if b_name == bundle_name
451
+ @aliases.delete( a_name )
452
+ end
453
+ end
454
+ if @servlets.include?( bundle_name )
455
+ @servlets.delete( bundle_name )
456
+ end
457
+ if @info.include?( bundle_name )
458
+ @info.delete( bundle_name )
459
+ end
460
+ @transporter.online = online_status
461
+ return unload_order
462
+ end
463
+ end
464
+
465
+ # Returns true, if a plugin bundle has changed.
466
+ # Only compares timestamp, not checksum.
467
+ def changed?( plugin_name )
468
+ info = @info[plugin_name]
469
+ last_changed = info[:last_changed]
470
+ newest_change = most_recent( info[:path], last_changed )
471
+ return last_changed < newest_change
472
+ end
473
+
474
+ # Logs and speaks the message, if the speech synthesis command "say" exists.
475
+ def say( message )
476
+ puts message
477
+ if RSence.args[:say]
478
+ Thread.new do
479
+ Thread.pass
480
+ system(%{say "#{message.gsub('"','')}"})
481
+ end
482
+ end
483
+ end
484
+
485
+ # Checks for changed plugin bundles and unloads/loads/reloads them accordingly.
486
+ def update_bundles!
487
+ (are_found, to_load, to_unload, to_reload) = [[],[],[],[]]
488
+ found_map = {}
489
+ @plugin_paths.each do |path|
490
+ are_found += find_bundles( path )
491
+ end
492
+ are_found.each do |item|
493
+ (path, name, src_file) = item
494
+ found_map[name] = item
495
+ is_loaded = loaded?( name )
496
+ if is_loaded and changed?( name )
497
+ to_reload.push( name )
498
+ elsif not is_loaded
499
+ to_load.push( name )
500
+ end
501
+ end
502
+ @registry.keys.each do |name|
503
+ to_unload.push( name ) if not found_map.has_key?( name )
504
+ end
505
+ to_unload.each do |name|
506
+ next if @deps.category?( name )
507
+ if RSence.args[:verbose]
508
+ print "Unloading #{name.inspect}..."; STDOUT.flush
509
+ end
510
+ unload_bundle( name )
511
+ puts "done!" if RSence.args[:verbose]
512
+ end
513
+ to_reload.each do |name|
514
+ next if @deps.category?( name )
515
+ if RSence.args[:verbose]
516
+ print "Unloading #{name.inspect}..."; STDOUT.flush
517
+ end
518
+ unload_order = unload_bundle( name )
519
+ to_load += unload_order
520
+ puts "done!" if RSence.args[:verbose]
521
+ end
522
+ info_map = {}
523
+ to_load.each do |name|
524
+ next unless found_map.has_key? name
525
+ info_map[name] = bundle_info( *found_map[name] )
526
+ end
527
+ no_deps = {}
528
+ to_load.dup.each do |name|
529
+ if @deps.unresolved?( name )
530
+ no_deps[ name ] = @deps.deps_on( name )
531
+ @deps.del_item( name )
532
+ to_load.delete( name )
533
+ end
534
+ end
535
+ to_open = []
536
+ @deps.list.each do |name|
537
+ next if @deps.category?( name )
538
+ next unless to_load.include?( name )
539
+ info = info_map[name]
540
+ if RSence.args[:verbose]
541
+ if to_reload.include?( name )
542
+ print "Reloading #{name.inspect}..."
543
+ else
544
+ print "Loading #{name.inspect}..."
545
+ end
546
+ STDOUT.flush
547
+ end
548
+ @info[name] = info
549
+ load_bundle( name )
550
+ to_open.push( name )
551
+ puts "done!" if RSence.args[:verbose]
552
+ end
553
+ unless no_deps.empty?
554
+ warn "Warning! Unable to load the following bundles; missing dependencies:"
555
+ no_deps.each do |name,deps|
556
+ warn " #{name} depends on: #{deps.join(', ')}"
557
+ end
558
+ end
559
+ to_open.each do |name|
560
+ if RSence.args[:verbose]
561
+ print "Opening #{name.inspect}..."; STDOUT.flush
562
+ end
563
+ call( name, :open )
564
+ puts "done!" if RSence.args[:verbose]
565
+ end
566
+ if not (to_load.empty? and to_unload.empty? and to_reload.empty?)
567
+ puts "Plugin bundles:"
568
+ puts " loaded: #{to_load.join(', ')}" unless to_load.empty?
569
+ puts " unloaded: #{to_unload.join(', ')}" unless to_unload.empty?
570
+ puts " reloaded: #{to_reload.join(', ')}" unless to_reload.empty?
571
+ puts " opened: #{to_open.join(', ')}" unless to_open.empty?
572
+ end
573
+ end
574
+
575
+ # Top-level method for scanning all plugin directories.
576
+ # Clears previously loaded plugins.
577
+ def init_bundles!
578
+ @registry = {} # bundle_name => bundle_instance mapping
579
+ @info = {} # bundle_name => bundle_info mapping
580
+ @aliases = {} # bundle_alias => bundle_name mapping
581
+ @servlets = [] # bundle_name list of Servlet class instances
582
+ update_bundles!
583
+ end
584
+
585
+ # Initialize with a list of directories as plugin_paths.
586
+ # It's an array containing all plugin directories to scan.
587
+ def initialize( plugin_paths, transporter=nil,
588
+ autoreload=false, name_prefix=false,
589
+ resolved_deps=[], resolved_categories={} )
590
+ if transporter
591
+ @transporter = transporter
592
+ @sessions = transporter.sessions
593
+ end
594
+ @name_prefix = name_prefix
595
+ @plugin_paths = plugin_paths
596
+ @deps = Dependencies.new( resolved_deps, resolved_categories )
597
+ puts "Loading #{name_prefix+' ' if name_prefix}plugins..." if RSence.args[:verbose]
598
+ init_bundles!
599
+ puts %{Plugins #{"of #{name_prefix} " if name_prefix}loaded.} if RSence.args[:verbose]
600
+ if autoreload
601
+ @thr = Thread.new do
602
+ Thread.pass
603
+ while true
604
+ begin
605
+ update_bundles!
606
+ rescue => e
607
+ plugin_error( e, "PluginManager#update_bundles!", "An error occurred while reloading bundles" )
608
+ end
609
+ sleep 3
610
+ end
611
+ end
612
+ end
613
+ end
614
+ end
615
+ end
616
+
617
+
618
+
619
+
620
+
621
+
622
+
623
+
624
+
625
+
626
+
627
+
628
+
629
+
630
+
631
+
632
+
633
+
634
+
635
+