rsence-pre 2.1.0.1.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+