rhoconnect 3.0.0.beta1

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 (361) hide show
  1. data/CHANGELOG +208 -0
  2. data/CREDITS +38 -0
  3. data/Gemfile +18 -0
  4. data/Gemfile.lock +97 -0
  5. data/LICENSE +75 -0
  6. data/README.md +10 -0
  7. data/Rakefile +82 -0
  8. data/bench/bench +7 -0
  9. data/bench/bench_runner.rb +112 -0
  10. data/bench/benchapp/Gemfile +21 -0
  11. data/bench/benchapp/Gemfile.lock +76 -0
  12. data/bench/benchapp/Rakefile +22 -0
  13. data/bench/benchapp/application.rb +39 -0
  14. data/bench/benchapp/config.ru +36 -0
  15. data/bench/benchapp/settings/license.key +1 -0
  16. data/bench/benchapp/settings/settings.yml +20 -0
  17. data/bench/benchapp/sources/mock_adapter.rb +55 -0
  18. data/bench/benchapp/sources/queue_mock_adapter.rb +2 -0
  19. data/bench/benchapp/spec/sources/mock_adapter_spec.rb +25 -0
  20. data/bench/benchapp/spec/sources/queue_mock_adapter_spec.rb +25 -0
  21. data/bench/benchapp/spec/spec_helper.rb +42 -0
  22. data/bench/blobapp/Gemfile +31 -0
  23. data/bench/blobapp/Gemfile.lock +103 -0
  24. data/bench/blobapp/Rakefile +25 -0
  25. data/bench/blobapp/application.rb +44 -0
  26. data/bench/blobapp/config.ru +36 -0
  27. data/bench/blobapp/settings/license.key +1 -0
  28. data/bench/blobapp/settings/settings.yml +16 -0
  29. data/bench/blobapp/sources/blob_adapter.rb +71 -0
  30. data/bench/blobapp/spec/sources/blob_adapter_spec.rb +25 -0
  31. data/bench/blobapp/spec/spec_helper.rb +42 -0
  32. data/bench/lib/bench/cli.rb +16 -0
  33. data/bench/lib/bench/logging.rb +13 -0
  34. data/bench/lib/bench/mock_client.rb +41 -0
  35. data/bench/lib/bench/result.rb +50 -0
  36. data/bench/lib/bench/runner.rb +107 -0
  37. data/bench/lib/bench/session.rb +67 -0
  38. data/bench/lib/bench/statistics.rb +56 -0
  39. data/bench/lib/bench/test_data.rb +98 -0
  40. data/bench/lib/bench/timer.rb +10 -0
  41. data/bench/lib/bench/utils.rb +49 -0
  42. data/bench/lib/bench.rb +129 -0
  43. data/bench/lib/testdata/100-data.txt +148 -0
  44. data/bench/lib/testdata/5-data.txt +9 -0
  45. data/bench/lib/testdata/images/icon.ico +0 -0
  46. data/bench/lib/testdata/images/icon.png +0 -0
  47. data/bench/lib/testdata/images/loading-Landscape.png +0 -0
  48. data/bench/lib/testdata/images/loading-LandscapeLeft.png +0 -0
  49. data/bench/lib/testdata/images/loading-LandscapeRight.png +0 -0
  50. data/bench/lib/testdata/images/loading-Portrait.png +0 -0
  51. data/bench/lib/testdata/images/loading-PortraitUpsideDown.png +0 -0
  52. data/bench/lib/testdata/images/loading.png +0 -0
  53. data/bench/lib/testdata/images/loading@2x.png +0 -0
  54. data/bench/run_bench.sh +42 -0
  55. data/bench/run_blob_script.sh +3 -0
  56. data/bench/run_cud_script.sh +3 -0
  57. data/bench/run_query_md_script.sh +3 -0
  58. data/bench/run_query_only_script.sh +3 -0
  59. data/bench/run_query_script.sh +3 -0
  60. data/bench/scripts/blob_cud_script.rb +98 -0
  61. data/bench/scripts/cud_script.rb +92 -0
  62. data/bench/scripts/helpers.rb +101 -0
  63. data/bench/scripts/query_md_script.rb +45 -0
  64. data/bench/scripts/query_only_script.rb +51 -0
  65. data/bench/scripts/query_script.rb +45 -0
  66. data/bench/spec/bench_spec_helper.rb +33 -0
  67. data/bench/spec/logging_spec.rb +15 -0
  68. data/bench/spec/mock_adapter_spec.rb +61 -0
  69. data/bench/spec/mock_client_spec.rb +65 -0
  70. data/bench/spec/result_spec.rb +61 -0
  71. data/bench/spec/utils_spec.rb +36 -0
  72. data/bin/rhoconnect +34 -0
  73. data/bin/rhoconnect-setup +84 -0
  74. data/doc/async-jobs.txt +69 -0
  75. data/doc/authentication.txt +76 -0
  76. data/doc/benchmarks.txt +168 -0
  77. data/doc/blob-sync.txt +130 -0
  78. data/doc/bulk-sync.txt +102 -0
  79. data/doc/client.txt +432 -0
  80. data/doc/command-line.txt +210 -0
  81. data/doc/contributing.txt +60 -0
  82. data/doc/deploying.txt +82 -0
  83. data/doc/install.txt +28 -0
  84. data/doc/introduction.txt +20 -0
  85. data/doc/licensing.txt +18 -0
  86. data/doc/metadata.txt +458 -0
  87. data/doc/migration.txt +182 -0
  88. data/doc/public/css/print.css +29 -0
  89. data/doc/public/css/screen.css +257 -0
  90. data/doc/public/css/style.css +20 -0
  91. data/doc/push.txt +135 -0
  92. data/doc/release.txt +41 -0
  93. data/doc/rest-api.txt +367 -0
  94. data/doc/source-adapters.txt +325 -0
  95. data/doc/stats-middleware.txt +69 -0
  96. data/doc/testing.txt +222 -0
  97. data/doc/tutorial.txt +315 -0
  98. data/doc/web-console.txt +35 -0
  99. data/examples/simple/Rakefile +14 -0
  100. data/examples/simple/application.rb +27 -0
  101. data/examples/simple/config.ru +49 -0
  102. data/examples/simple/settings/license.key +1 -0
  103. data/examples/simple/settings/settings.yml +23 -0
  104. data/examples/simple/sources/sample_adapter.rb +5 -0
  105. data/examples/simple/sources/simple_adapter.rb +5 -0
  106. data/generators/rhoconnect.rb +119 -0
  107. data/generators/templates/application/Gemfile +21 -0
  108. data/generators/templates/application/Rakefile +22 -0
  109. data/generators/templates/application/application.rb +39 -0
  110. data/generators/templates/application/config.ru +36 -0
  111. data/generators/templates/application/settings/license.key +1 -0
  112. data/generators/templates/application/settings/settings.yml +14 -0
  113. data/generators/templates/application/spec/spec_helper.rb +42 -0
  114. data/generators/templates/source/source_adapter.rb +47 -0
  115. data/generators/templates/source/source_spec.rb +25 -0
  116. data/install.sh +408 -0
  117. data/installer/unix-like/rho_connect_install_checkers.rb +140 -0
  118. data/installer/unix-like/rho_connect_install_constants.rb +51 -0
  119. data/installer/unix-like/rho_connect_install_debian.rb +63 -0
  120. data/installer/unix-like/rho_connect_install_dnd.rb +58 -0
  121. data/installer/unix-like/rho_connect_install_get_params.rb +30 -0
  122. data/installer/unix-like/rho_connect_install_installers.rb +142 -0
  123. data/installer/unix-like/rho_connect_install_utilities.rb +85 -0
  124. data/installer/unix-like/rho_connect_install_yum.rb +63 -0
  125. data/installer/unix-like/rhoinstaller.rb +89 -0
  126. data/installer/utils/create_texts.rb +366 -0
  127. data/installer/utils/install_test.rb +140 -0
  128. data/installer/windows/EnvVarUpdate.nsh +328 -0
  129. data/installer/windows/ServiceLib.nsh +369 -0
  130. data/installer/windows/configUi.ini +44 -0
  131. data/installer/windows/icon.ico +0 -0
  132. data/installer/windows/rhosync.nsi +418 -0
  133. data/installer/windows/uninstall.bat +7 -0
  134. data/lib/rhoconnect/api/admin/get_api_token.rb +14 -0
  135. data/lib/rhoconnect/api/admin/get_license_info.rb +8 -0
  136. data/lib/rhoconnect/api/admin/login.rb +6 -0
  137. data/lib/rhoconnect/api/admin/reset.rb +10 -0
  138. data/lib/rhoconnect/api/admin/stats.rb +21 -0
  139. data/lib/rhoconnect/api/application/bulk_data.rb +7 -0
  140. data/lib/rhoconnect/api/application/clientcreate.rb +8 -0
  141. data/lib/rhoconnect/api/application/clientlogin.rb +6 -0
  142. data/lib/rhoconnect/api/application/clientregister.rb +6 -0
  143. data/lib/rhoconnect/api/application/clientreset.rb +6 -0
  144. data/lib/rhoconnect/api/application/query.rb +7 -0
  145. data/lib/rhoconnect/api/application/queue_updates.rb +6 -0
  146. data/lib/rhoconnect/api/application/search.rb +6 -0
  147. data/lib/rhoconnect/api/client/create_client.rb +3 -0
  148. data/lib/rhoconnect/api/client/delete_client.rb +5 -0
  149. data/lib/rhoconnect/api/client/get_client_params.rb +3 -0
  150. data/lib/rhoconnect/api/client/list_client_docs.rb +12 -0
  151. data/lib/rhoconnect/api/client/list_clients.rb +3 -0
  152. data/lib/rhoconnect/api/client/ping.rb +7 -0
  153. data/lib/rhoconnect/api/source/get_adapter.rb +3 -0
  154. data/lib/rhoconnect/api/source/get_db_doc.rb +7 -0
  155. data/lib/rhoconnect/api/source/get_source_params.rb +3 -0
  156. data/lib/rhoconnect/api/source/list_source_docs.rb +10 -0
  157. data/lib/rhoconnect/api/source/list_sources.rb +15 -0
  158. data/lib/rhoconnect/api/source/push_deletes.rb +8 -0
  159. data/lib/rhoconnect/api/source/push_objects.rb +8 -0
  160. data/lib/rhoconnect/api/source/save_adapter.rb +3 -0
  161. data/lib/rhoconnect/api/source/set_db_doc.rb +8 -0
  162. data/lib/rhoconnect/api/source/set_refresh_time.rb +8 -0
  163. data/lib/rhoconnect/api/source/upload_file.rb +4 -0
  164. data/lib/rhoconnect/api/user/create_user.rb +7 -0
  165. data/lib/rhoconnect/api/user/delete_user.rb +9 -0
  166. data/lib/rhoconnect/api/user/list_users.rb +3 -0
  167. data/lib/rhoconnect/api/user/update_user.rb +4 -0
  168. data/lib/rhoconnect/api_token.rb +19 -0
  169. data/lib/rhoconnect/app.rb +76 -0
  170. data/lib/rhoconnect/bulk_data/bulk_data.rb +88 -0
  171. data/lib/rhoconnect/bulk_data/syncdb.index.schema +4 -0
  172. data/lib/rhoconnect/bulk_data/syncdb.schema +41 -0
  173. data/lib/rhoconnect/bulk_data.rb +2 -0
  174. data/lib/rhoconnect/client.rb +96 -0
  175. data/lib/rhoconnect/client_sync.rb +412 -0
  176. data/lib/rhoconnect/console/app/helpers/auth_helper.rb +22 -0
  177. data/lib/rhoconnect/console/app/helpers/extensions.rb +19 -0
  178. data/lib/rhoconnect/console/app/helpers/helpers.rb +57 -0
  179. data/lib/rhoconnect/console/app/public/ThickBox.css +649 -0
  180. data/lib/rhoconnect/console/app/public/home.css +438 -0
  181. data/lib/rhoconnect/console/app/public/images/foot_logo_rhoconnect.png +0 -0
  182. data/lib/rhoconnect/console/app/public/images/header_halo.jpg +0 -0
  183. data/lib/rhoconnect/console/app/public/images/land_separator.gif +0 -0
  184. data/lib/rhoconnect/console/app/public/images/landing_header.jpg +0 -0
  185. data/lib/rhoconnect/console/app/public/images/logo_rhoconnect.png +0 -0
  186. data/lib/rhoconnect/console/app/public/images/rhomobile_rhohub_logo.png +0 -0
  187. data/lib/rhoconnect/console/app/public/images/tabs_separator.png +0 -0
  188. data/lib/rhoconnect/console/app/public/jqplot/excanvas.min.js +35 -0
  189. data/lib/rhoconnect/console/app/public/jqplot/jqplot.barRenderer.min.js +34 -0
  190. data/lib/rhoconnect/console/app/public/jqplot/jqplot.canvasAxisLabelRenderer.js +187 -0
  191. data/lib/rhoconnect/console/app/public/jqplot/jqplot.canvasAxisTickRenderer.js +226 -0
  192. data/lib/rhoconnect/console/app/public/jqplot/jqplot.canvasTextRenderer.js +408 -0
  193. data/lib/rhoconnect/console/app/public/jqplot/jqplot.categoryAxisRenderer.min.js +34 -0
  194. data/lib/rhoconnect/console/app/public/jqplot/jqplot.cursor.js +952 -0
  195. data/lib/rhoconnect/console/app/public/jqplot/jqplot.dateAxisRenderer.js +313 -0
  196. data/lib/rhoconnect/console/app/public/jqplot/jqplot.dateAxisRenderer.min.js +34 -0
  197. data/lib/rhoconnect/console/app/public/jqplot/jqplot.pointLabels.min.js +34 -0
  198. data/lib/rhoconnect/console/app/public/jqplot/jquery-1.4.2.min.js +154 -0
  199. data/lib/rhoconnect/console/app/public/jqplot/jquery.jqplot.min.css +1 -0
  200. data/lib/rhoconnect/console/app/public/jqplot/jquery.jqplot.min.js +34 -0
  201. data/lib/rhoconnect/console/app/public/main.css +7 -0
  202. data/lib/rhoconnect/console/app/public/reset.css +76 -0
  203. data/lib/rhoconnect/console/app/public/style.css +2201 -0
  204. data/lib/rhoconnect/console/app/public/text.txt +0 -0
  205. data/lib/rhoconnect/console/app/routes/adapter.rb +28 -0
  206. data/lib/rhoconnect/console/app/routes/auth.rb +29 -0
  207. data/lib/rhoconnect/console/app/routes/client.rb +31 -0
  208. data/lib/rhoconnect/console/app/routes/docs.rb +145 -0
  209. data/lib/rhoconnect/console/app/routes/heroku.rb +19 -0
  210. data/lib/rhoconnect/console/app/routes/home.rb +63 -0
  211. data/lib/rhoconnect/console/app/routes/timing.rb +242 -0
  212. data/lib/rhoconnect/console/app/routes/user.rb +117 -0
  213. data/lib/rhoconnect/console/app/views/adapter.erb +16 -0
  214. data/lib/rhoconnect/console/app/views/client.erb +30 -0
  215. data/lib/rhoconnect/console/app/views/content.erb +14 -0
  216. data/lib/rhoconnect/console/app/views/doc.erb +8 -0
  217. data/lib/rhoconnect/console/app/views/docdata.erb +28 -0
  218. data/lib/rhoconnect/console/app/views/docs.erb +30 -0
  219. data/lib/rhoconnect/console/app/views/edituser.erb +13 -0
  220. data/lib/rhoconnect/console/app/views/headermenu.erb +40 -0
  221. data/lib/rhoconnect/console/app/views/home.erb +24 -0
  222. data/lib/rhoconnect/console/app/views/index.erb +58 -0
  223. data/lib/rhoconnect/console/app/views/jqplot.erb +52 -0
  224. data/lib/rhoconnect/console/app/views/layout.erb +165 -0
  225. data/lib/rhoconnect/console/app/views/login.erb +26 -0
  226. data/lib/rhoconnect/console/app/views/newuser.erb +17 -0
  227. data/lib/rhoconnect/console/app/views/ping.erb +28 -0
  228. data/lib/rhoconnect/console/app/views/result.erb +11 -0
  229. data/lib/rhoconnect/console/app/views/rightboxlinks.erb +15 -0
  230. data/lib/rhoconnect/console/app/views/select_doc.erb +17 -0
  231. data/lib/rhoconnect/console/app/views/upload_doc.erb +23 -0
  232. data/lib/rhoconnect/console/app/views/user.erb +29 -0
  233. data/lib/rhoconnect/console/app/views/users.erb +12 -0
  234. data/lib/rhoconnect/console/rhoconnect_api.rb +245 -0
  235. data/lib/rhoconnect/console/server.rb +32 -0
  236. data/lib/rhoconnect/console.rb +3 -0
  237. data/lib/rhoconnect/cors.rb +229 -0
  238. data/lib/rhoconnect/credential.rb +9 -0
  239. data/lib/rhoconnect/db_adapter.rb +46 -0
  240. data/lib/rhoconnect/document.rb +49 -0
  241. data/lib/rhoconnect/dynamic_adapter.rb +91 -0
  242. data/lib/rhoconnect/generator.rb +1 -0
  243. data/lib/rhoconnect/jobs/bulk_data_job.rb +203 -0
  244. data/lib/rhoconnect/jobs/ping_job.rb +46 -0
  245. data/lib/rhoconnect/jobs/source_job.rb +16 -0
  246. data/lib/rhoconnect/license.rb +86 -0
  247. data/lib/rhoconnect/lock_ops.rb +11 -0
  248. data/lib/rhoconnect/model.rb +414 -0
  249. data/lib/rhoconnect/ping/android.rb +56 -0
  250. data/lib/rhoconnect/ping/apple.rb +52 -0
  251. data/lib/rhoconnect/ping/blackberry.rb +56 -0
  252. data/lib/rhoconnect/ping.rb +3 -0
  253. data/lib/rhoconnect/read_state.rb +31 -0
  254. data/lib/rhoconnect/rho_indifferent_access.rb +88 -0
  255. data/lib/rhoconnect/server/views/index.erb +13 -0
  256. data/lib/rhoconnect/server.rb +286 -0
  257. data/lib/rhoconnect/source.rb +289 -0
  258. data/lib/rhoconnect/source_adapter.rb +123 -0
  259. data/lib/rhoconnect/source_sync.rb +302 -0
  260. data/lib/rhoconnect/stats/middleware.rb +20 -0
  261. data/lib/rhoconnect/stats/record.rb +108 -0
  262. data/lib/rhoconnect/store.rb +232 -0
  263. data/lib/rhoconnect/tasks.rb +350 -0
  264. data/lib/rhoconnect/test_methods.rb +220 -0
  265. data/lib/rhoconnect/user.rb +95 -0
  266. data/lib/rhoconnect/version.rb +3 -0
  267. data/lib/rhoconnect/x_domain_session_wrapper.rb +53 -0
  268. data/lib/rhoconnect.rb +285 -0
  269. data/rhoconnect.gemspec +67 -0
  270. data/spec/api/admin/api_token_spec.rb +14 -0
  271. data/spec/api/admin/get_api_token_spec.rb +36 -0
  272. data/spec/api/admin/get_license_info_spec.rb +38 -0
  273. data/spec/api/admin/reset_spec.rb +22 -0
  274. data/spec/api/admin/stats_spec.rb +66 -0
  275. data/spec/api/api_helper.rb +21 -0
  276. data/spec/api/application/rhoconnect_api_spec.rb +548 -0
  277. data/spec/api/client/create_client_spec.rb +13 -0
  278. data/spec/api/client/delete_client_spec.rb +13 -0
  279. data/spec/api/client/get_client_params_spec.rb +18 -0
  280. data/spec/api/client/list_client_docs_spec.rb +32 -0
  281. data/spec/api/client/list_clients_spec.rb +22 -0
  282. data/spec/api/client/ping_spec.rb +23 -0
  283. data/spec/api/rhosync_api_spec.rb.orig +606 -0
  284. data/spec/api/source/adapter_spec.rb +29 -0
  285. data/spec/api/source/get_db_doc_spec.rb +21 -0
  286. data/spec/api/source/get_source_params_spec.rb +32 -0
  287. data/spec/api/source/list_source_docs_spec.rb +25 -0
  288. data/spec/api/source/list_sources_spec.rb +26 -0
  289. data/spec/api/source/push_deletes_spec.rb +18 -0
  290. data/spec/api/source/push_objects_spec.rb +27 -0
  291. data/spec/api/source/set_db_doc_spec.rb +19 -0
  292. data/spec/api/source/set_refresh_time_spec.rb +43 -0
  293. data/spec/api/source/upload_file_spec.rb +26 -0
  294. data/spec/api/user/create_user_spec.rb +16 -0
  295. data/spec/api/user/delete_user_spec.rb +36 -0
  296. data/spec/api/user/list_users_spec.rb +30 -0
  297. data/spec/api/user/update_user_spec.rb +31 -0
  298. data/spec/api_token_spec.rb +14 -0
  299. data/spec/app_spec.rb +18 -0
  300. data/spec/apps/emptyapp/application.rb +27 -0
  301. data/spec/apps/emptyapp/settings/license.key +1 -0
  302. data/spec/apps/emptyapp/settings/settings.yml +14 -0
  303. data/spec/apps/rhotestapp/Rakefile +1 -0
  304. data/spec/apps/rhotestapp/application.rb +19 -0
  305. data/spec/apps/rhotestapp/config.ru +1 -0
  306. data/spec/apps/rhotestapp/settings/apple_fake_cert.pem +1 -0
  307. data/spec/apps/rhotestapp/settings/license.key +1 -0
  308. data/spec/apps/rhotestapp/settings/settings.yml +36 -0
  309. data/spec/apps/rhotestapp/sources/base_adapter.rb +9 -0
  310. data/spec/apps/rhotestapp/sources/fixed_schema_adapter.rb +28 -0
  311. data/spec/apps/rhotestapp/sources/sample_adapter.rb +71 -0
  312. data/spec/apps/rhotestapp/sources/simple_adapter.rb +41 -0
  313. data/spec/apps/rhotestapp/sources/sub_adapter.rb +7 -0
  314. data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem/mygem.rb +8 -0
  315. data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem.rb +1 -0
  316. data/spec/bulk_data/bulk_data_spec.rb +97 -0
  317. data/spec/client_spec.rb +124 -0
  318. data/spec/client_sync_spec.rb +774 -0
  319. data/spec/doc/base.html +72 -0
  320. data/spec/doc/doc_spec.rb +376 -0
  321. data/spec/doc/footer.html +4 -0
  322. data/spec/doc/header.html +30 -0
  323. data/spec/document_spec.rb +31 -0
  324. data/spec/dynamic_adapter_spec.rb +43 -0
  325. data/spec/factories/factories.rb +17 -0
  326. data/spec/generator/generator_spec.rb +58 -0
  327. data/spec/generator/generator_spec_helper.rb +9 -0
  328. data/spec/jobs/bulk_data_job_spec.rb +125 -0
  329. data/spec/jobs/ping_job_spec.rb +102 -0
  330. data/spec/jobs/source_job_spec.rb +29 -0
  331. data/spec/license_spec.rb +66 -0
  332. data/spec/model_spec.rb +273 -0
  333. data/spec/perf/bulk_data_perf_spec.rb +32 -0
  334. data/spec/perf/perf_spec_helper.rb +50 -0
  335. data/spec/perf/store_perf_spec.rb +27 -0
  336. data/spec/ping/android_spec.rb +91 -0
  337. data/spec/ping/apple_spec.rb +70 -0
  338. data/spec/ping/blackberry_spec.rb +62 -0
  339. data/spec/read_state_spec.rb +35 -0
  340. data/spec/rhosync_spec.rb +75 -0
  341. data/spec/server/cors_spec.rb +287 -0
  342. data/spec/server/server_spec.rb +470 -0
  343. data/spec/server/x_domain_session_wrapper_spec.rb +150 -0
  344. data/spec/source_adapter_spec.rb +125 -0
  345. data/spec/source_spec.rb +114 -0
  346. data/spec/source_sync_spec.rb +328 -0
  347. data/spec/spec.opts +4 -0
  348. data/spec/spec_helper.rb +231 -0
  349. data/spec/stats/middleware_spec.rb +53 -0
  350. data/spec/stats/record_spec.rb +92 -0
  351. data/spec/store_spec.rb +251 -0
  352. data/spec/support/shared_examples.rb +168 -0
  353. data/spec/sync_states_spec.rb +72 -0
  354. data/spec/test_methods_spec.rb +134 -0
  355. data/spec/testdata/1000-data.txt +1414 -0
  356. data/spec/testdata/compressed/compress-data.txt +1 -0
  357. data/spec/testdata/upload1.txt +1 -0
  358. data/spec/testdata/upload2.txt +1 -0
  359. data/spec/user_spec.rb +139 -0
  360. data/tasks/redis.rake +206 -0
  361. metadata +706 -0
@@ -0,0 +1,302 @@
1
+ module Rhoconnect
2
+ class SourceSync
3
+ attr_reader :adapter
4
+
5
+ def initialize(source)
6
+ @source = source
7
+ raise InvalidArgumentError.new('Invalid source') if @source.nil?
8
+ raise InvalidArgumentError.new('Invalid app for source') unless @source.app
9
+ @adapter = SourceAdapter.create(@source)
10
+ end
11
+
12
+ # CUD Operations
13
+ def create(client_id)
14
+ _measure_and_process_cud('create',client_id)
15
+ end
16
+
17
+ def update(client_id)
18
+ _measure_and_process_cud('update',client_id)
19
+ end
20
+
21
+ def delete(client_id)
22
+ _measure_and_process_cud('delete',client_id)
23
+ end
24
+
25
+ # Pass through CUD to adapter, no data stored
26
+ def pass_through_cud(cud_params,query_params)
27
+ return if _auth_op('login') == false
28
+ res,processed_objects = {},[]
29
+ begin
30
+ ['create','update','delete'].each do |op|
31
+ key,objects = op,cud_params[op]
32
+ objects.each do |key,value|
33
+ case op
34
+ when 'create'
35
+ @adapter.send(op.to_sym,value)
36
+ when 'update'
37
+ value['id'] = key
38
+ @adapter.send(op.to_sym,value)
39
+ when 'delete'
40
+ value['id'] = key
41
+ @adapter.send(op.to_sym,value)
42
+ end
43
+ processed_objects << key
44
+ end if objects
45
+ end
46
+ rescue Exception => e
47
+ log "Error in pass through method: #{e.message}"
48
+ res['error'] = {'message' => e.message }
49
+ end
50
+ _auth_op('logoff')
51
+ res['processed'] = processed_objects
52
+ res.to_json
53
+ end
54
+
55
+ # Read Operation; params are query arguments
56
+ def read(client_id=nil,params=nil)
57
+ _read('query',client_id,params)
58
+ end
59
+
60
+ def search(client_id=nil,params=nil)
61
+ return if _auth_op('login',client_id) == false
62
+ res = _read('search',client_id,params)
63
+ _auth_op('logoff',client_id)
64
+ res
65
+ end
66
+
67
+ def process_cud(client_id)
68
+ if @source.cud_queue or @source.queue
69
+ async(:cud,@source.cud_queue || @source.queue,client_id)
70
+ else
71
+ do_cud(client_id)
72
+ end
73
+ end
74
+
75
+ def do_cud(client_id)
76
+ return if _auth_op('login') == false
77
+ self.create(client_id)
78
+ self.update(client_id)
79
+ self.delete(client_id)
80
+ _auth_op('logoff')
81
+ end
82
+
83
+ def process_query(params=nil)
84
+ if @source.query_queue or @source.queue
85
+ async(:query,@source.query_queue || @source.queue,nil,params)
86
+ else
87
+ do_query(params)
88
+ end
89
+ end
90
+
91
+ def do_query(params=nil)
92
+ result = nil
93
+ @source.if_need_refresh do
94
+ Stats::Record.update("source:query:#{@source.name}") do
95
+ return if _auth_op('login') == false
96
+ result = self.read(nil,params)
97
+ _auth_op('logoff')
98
+ end
99
+ end
100
+ result
101
+ end
102
+
103
+ # Enqueue a job for the source based on job type
104
+ def async(job_type,queue_name,client_id=nil,params=nil)
105
+ SourceJob.queue = queue_name
106
+ Resque.enqueue(SourceJob,job_type,@source.id,
107
+ @source.app_id,@source.user_id,client_id,params)
108
+ end
109
+
110
+ def push_objects(objects,timeout=10,raise_on_expire=false)
111
+ @source.lock(:md,timeout,raise_on_expire) do |s|
112
+ doc = @source.get_data(:md)
113
+ orig_doc_size = doc.size
114
+ objects.each do |id,obj|
115
+ doc[id] ||= {}
116
+ doc[id].merge!(obj)
117
+ end
118
+ diff_count = doc.size - orig_doc_size
119
+ @source.put_data(:md,doc)
120
+ @source.update_count(:md_size,diff_count)
121
+ end
122
+ end
123
+
124
+ def push_deletes(objects,timeout=10,raise_on_expire=false)
125
+ @source.lock(:md,timeout,raise_on_expire) do |s|
126
+ doc = @source.get_data(:md)
127
+ orig_doc_size = doc.size
128
+ objects.each do |id|
129
+ doc.delete(id)
130
+ end
131
+ diff_count = doc.size - orig_doc_size
132
+ @source.put_data(:md,doc)
133
+ @source.update_count(:md_size,diff_count)
134
+ end
135
+ end
136
+
137
+ private
138
+ def _auth_op(operation,client_id=-1)
139
+ edockey = client_id == -1 ? @source.docname(:errors) :
140
+ Client.load(client_id,{:source_name => @source.name}).docname(:search_errors)
141
+ begin
142
+ Store.flash_data(edockey) if operation == 'login'
143
+ @adapter.send operation
144
+ rescue Exception => e
145
+ log "SourceAdapter raised #{operation} exception: #{e}"
146
+ log e.backtrace.join("\n")
147
+ Store.put_data(edockey,{"#{operation}-error"=>{'message'=>e.message}},true)
148
+ return false
149
+ end
150
+ true
151
+ end
152
+
153
+ def _process_create(client,key,value,links,creates,deletes)
154
+ # Perform operation
155
+ link = @adapter.create value
156
+ # Store object-id link for the client
157
+ # If we have a link, store object in client document
158
+ # Otherwise, store object for delete on client
159
+ if link
160
+ links ||= {}
161
+ links[key] = { 'l' => link.to_s }
162
+ creates ||= {}
163
+ creates[link.to_s] = value
164
+ else
165
+ deletes ||= {}
166
+ deletes[key] = value
167
+ end
168
+ end
169
+
170
+ def _process_update(client,key,value)
171
+ begin
172
+ # Add id to object hash to forward to backend call
173
+ value['id'] = key
174
+ # Perform operation
175
+ @adapter.update value
176
+ rescue Exception => e
177
+ # TODO: This will be slow!
178
+ cd = client.get_data(:cd)
179
+ client.put_data(:update_rollback,{key => cd[key]},true) if cd[key]
180
+ raise e
181
+ end
182
+ end
183
+
184
+ def _process_delete(client,key,value,dels)
185
+ value['id'] = key
186
+ # Perform operation
187
+ @adapter.delete value
188
+ dels ||= {}
189
+ dels[key] = value
190
+ end
191
+
192
+ def _measure_and_process_cud(operation,client_id)
193
+ Stats::Record.update("source:#{operation}:#{@source.name}") do
194
+ _process_cud(operation,client_id)
195
+ end
196
+ end
197
+
198
+ def _process_cud(operation,client_id)
199
+ errors,links,deletes,creates,dels = {},{},{},{},{}
200
+ client = Client.load(client_id,{:source_name => @source.name})
201
+ modified = client.get_data(operation)
202
+ # Process operation queue, one object at a time
203
+ modified.each do |key,value|
204
+ begin
205
+ # Remove object from queue
206
+ modified.delete(key)
207
+ # Call on source adapter to process individual object
208
+ case operation
209
+ when 'create'
210
+ _process_create(client,key,value,links,creates,deletes)
211
+ when 'update'
212
+ _process_update(client,key,value)
213
+ when 'delete'
214
+ _process_delete(client,key,value,dels)
215
+ end
216
+ rescue Exception => e
217
+ log "SourceAdapter raised #{operation} exception: #{e}"
218
+ log e.backtrace.join("\n")
219
+ errors ||= {}
220
+ errors[key] = value
221
+ errors["#{key}-error"] = {'message'=>e.message}
222
+ break
223
+ end
224
+ end
225
+ # Record operation results
226
+ { "delete_page" => deletes,
227
+ "#{operation}_links" => links,
228
+ "#{operation}_errors" => errors }.each do |doctype,value|
229
+ client.put_data(doctype,value,true) unless value.empty?
230
+ end
231
+ unless operation != 'create' and creates.empty?
232
+ client.put_data(:cd,creates,true)
233
+ client.update_count(:cd_size,creates.size)
234
+ @source.lock(:md) do |s|
235
+ s.put_data(:md,creates,true)
236
+ s.update_count(:md_size,creates.size)
237
+ end
238
+ end
239
+ if operation == 'delete'
240
+ # Clean up deleted objects from master document and corresponding client document
241
+ client.delete_data(:cd,dels)
242
+ client.update_count(:cd_size,-dels.size)
243
+ @source.lock(:md) do |s|
244
+ s.delete_data(:md,dels)
245
+ s.update_count(:md_size,-dels.size)
246
+ end
247
+ end
248
+ # Record rest of queue (if something in the middle failed)
249
+ if modified.empty?
250
+ client.flash_data(operation)
251
+ else
252
+ client.put_data(operation,modified)
253
+ end
254
+ modified.size
255
+ end
256
+
257
+ # Metadata Operation; source adapter returns json
258
+ def _get_data(method)
259
+ if @adapter.respond_to?(method)
260
+ data = @adapter.send(method)
261
+ if data
262
+ @source.put_value(method,data)
263
+ @source.put_value("#{method}_sha1",Digest::SHA1.hexdigest(data))
264
+ end
265
+ end
266
+ end
267
+
268
+ # Read Operation; params are query arguments
269
+ def _read(operation,client_id,params=nil)
270
+ errordoc = nil
271
+ result = nil
272
+ begin
273
+ if operation == 'search'
274
+ client = Client.load(client_id,{:source_name => @source.name})
275
+ errordoc = client.docname(:search_errors)
276
+ compute_token(client.docname(:search_token))
277
+ result = @adapter.search(params)
278
+ @adapter.save(client.docname(:search)) unless @source.is_pass_through?
279
+ else
280
+ errordoc = @source.docname(:errors)
281
+ [:metadata,:schema].each do |method|
282
+ _get_data(method)
283
+ end
284
+ result = @adapter.do_query(params)
285
+ end
286
+ # operation,sync succeeded, remove errors
287
+ Store.lock(errordoc) do
288
+ Store.flash_data(errordoc)
289
+ end
290
+ rescue Exception => e
291
+ # store sync,operation exceptions to be sent to all clients for this source/user
292
+ log "SourceAdapter raised #{operation} exception: #{e}"
293
+ log e.backtrace.join("\n")
294
+ Store.lock(errordoc) do
295
+ Store.put_data(errordoc,{"#{operation}-error"=>{'message'=>e.message}},true)
296
+ end
297
+ end
298
+ # pass through expects result hash
299
+ @source.is_pass_through? ? result : true
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,20 @@
1
+ module Rhoconnect
2
+ module Stats
3
+ class Middleware
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ start = Time.now.to_f
10
+ status, headers, body = @app.call(env)
11
+ finish = Time.now.to_f
12
+ metric = "http:#{env['REQUEST_METHOD']}:#{env['PATH_INFO']}"
13
+ source_name = env['rack.request.query_hash']["source_name"] if env['rack.request.query_hash']
14
+ metric << ":#{source_name}" if source_name
15
+ Record.save_average(metric,finish - start)
16
+ [status, headers, body]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,108 @@
1
+ module Rhoconnect
2
+ module Stats
3
+ class Record
4
+ class << self
5
+
6
+ # Add a value to a metric. If zset already has a member,
7
+ # update the existing member with an incremented value by default.
8
+ # Also supports updating the value with a block (useful for averages)
9
+ def set(metric, value = 0)
10
+ start = (Time.now.to_i / resolution(metric)) * resolution(metric)
11
+ current, current_score = 0, start
12
+ Store.lock(key(metric)) do
13
+ range = Store.db.zrevrange(key(metric), 0, 0)
14
+ if !range.empty?
15
+ member = range[0]
16
+ m_current = member.split(':')[0]
17
+ m_current_score = Store.db.zscore(key(metric), member).to_i
18
+ if m_current_score > (start - resolution(metric))
19
+ Store.db.zrem(key(metric), member)
20
+ current, current_score = m_current, m_current_score
21
+ end
22
+ end
23
+ value = block_given? ? yield(current, value) : value
24
+ Store.db.zadd(key(metric), current_score, "#{value}:#{start}")
25
+ Store.db.zremrangebyscore(key(metric), 0, start - record_size(metric))
26
+ end
27
+ end
28
+
29
+ def add(metric, value = 1)
30
+ set(metric,value) { |current,value| current.to_i + value }
31
+ end
32
+
33
+ # Saves the accumulated average for a resolution in a metric
34
+ def save_average(metric, value)
35
+ set(metric,value) do |current,value|
36
+ sum = value
37
+ if current.is_a?(String)
38
+ current,sum = current.split(',')
39
+ current = current.to_f
40
+ sum = sum.to_f+value
41
+ end
42
+ "#{current + 1},#{sum}"
43
+ end
44
+ end
45
+
46
+ def update(metric)
47
+ if Rhoconnect.stats
48
+ start = Time.now.to_f
49
+ # perform the operations
50
+ yield
51
+ finish = Time.now.to_f
52
+ save_average(metric, finish - start)
53
+ else
54
+ yield
55
+ end
56
+ end
57
+
58
+ def keys(glob='*')
59
+ Store.db.keys(key(glob)).collect {|c| c[5..-1]}
60
+ end
61
+
62
+ def reset(metric)
63
+ Store.db.del(key(metric))
64
+ end
65
+
66
+ def reset_all
67
+ Store.flash_data('stat:*')
68
+ end
69
+
70
+ # Returns simple string metric
71
+ def get_value(metric)
72
+ Store.get_value(key(metric))
73
+ end
74
+
75
+ # Sets a string metric
76
+ def set_value(metric, value)
77
+ Store.set_value(key(metric), value)
78
+ end
79
+
80
+ # Returns the metric data, uses array indexing
81
+ def range(metric, start, finish = -1)
82
+ Store.db.zrange(key(metric), start, finish)
83
+ end
84
+
85
+ # Returns the resolution for a given metric, default 60 seconds
86
+ def resolution(metric)
87
+ resolution = STATS_RECORD_RESOLUTION rescue nil
88
+ resolution || 60 #=> 1 minute aggregate
89
+ end
90
+
91
+ # Returns the # of records to save for a given metric
92
+ def record_size(metric)
93
+ size = STATS_RECORD_SIZE rescue nil
94
+ size || 60 * 24 * 31 #=> 44640 minutes
95
+ end
96
+
97
+ # Returns redis object type for a record
98
+ def rtype(metric)
99
+ Store.db.type(key(metric))
100
+ end
101
+
102
+ def key(metric)
103
+ "stat:#{metric}"
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,232 @@
1
+ module Rhoconnect
2
+
3
+ class StoreLockException < RuntimeError; end
4
+
5
+ class Store
6
+ RESERVED_ATTRIB_NAMES = ["attrib_type", "id"] unless defined? RESERVED_ATTRIB_NAMES
7
+ @@db = nil
8
+
9
+ class << self
10
+ def db; @@db || @@db = _get_redis end
11
+
12
+ def db=(server=nil)
13
+ @@db = _get_redis(server)
14
+ end
15
+
16
+ def create(server=nil)
17
+ @@db ||= _get_redis(server)
18
+ raise "Error connecting to Redis store." unless @@db and
19
+ (@@db.is_a?(Redis) or @@db.is_a?(Redis::Client))
20
+ end
21
+
22
+ # Adds set with given data, replaces existing set
23
+ # if it exists or appends data to the existing set
24
+ # if append flag set to true
25
+ def put_data(dockey,data={},append=false)
26
+ if dockey and data
27
+ flash_data(dockey) unless append
28
+ # Inserts a hash or array
29
+ if data.is_a?(Hash)
30
+ @@db.pipelined do
31
+ data.each do |key,value|
32
+ raise ArgumentError, "Invalid value object: #{value.inspect}. Hash is expected." unless value.is_a?(Hash)
33
+ value.each do |attrib,value|
34
+ unless _is_reserved?(attrib,value)
35
+ @@db.sadd(dockey,setelement(key,attrib,value))
36
+ end
37
+ end
38
+ end
39
+ end
40
+ else
41
+ @@db.pipelined do
42
+ data.each do |value|
43
+ @@db.sadd(dockey,value)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ true
49
+ end
50
+
51
+ # Adds a simple key/value pair
52
+ def put_value(dockey,value)
53
+ if dockey
54
+ @@db.del(dockey)
55
+ @@db.set(dockey,value.to_s) if value
56
+ end
57
+ end
58
+
59
+ # Retrieves value for a given key
60
+ def get_value(dockey)
61
+ @@db.get(dockey) if dockey
62
+ end
63
+
64
+ def incr(dockey)
65
+ @@db.incr(dockey)
66
+ end
67
+
68
+ def decr(dockey)
69
+ @@db.decr(dockey)
70
+ end
71
+
72
+ # Retrieves set for given dockey,source,user
73
+ def get_data(dockey,type=Hash)
74
+ res = type == Hash ? {} : []
75
+ if dockey
76
+ members = @@db.smembers(dockey)
77
+ members.each do |element|
78
+ if type == Hash
79
+ key,attrib,value = getelement(element)
80
+ res[key] = {} unless res[key]
81
+ res[key].merge!({attrib => value})
82
+ else
83
+ res << element
84
+ end
85
+ end if members
86
+ res
87
+ end
88
+ end
89
+
90
+ # Retrieves diff data hash between two sets
91
+ def get_diff_data(src_dockey,dst_dockey,p_size=nil)
92
+ res = {}
93
+ if src_dockey and dst_dockey
94
+ @@db.sdiff(dst_dockey,src_dockey).each do |element|
95
+ key,attrib,value = getelement(element)
96
+ res[key] = {} unless res[key]
97
+ res[key].merge!({attrib => value})
98
+ end
99
+ end
100
+ if p_size
101
+ diff = {}
102
+ page_size = p_size
103
+ res.each do |key,item|
104
+ diff[key] = item
105
+ page_size -= 1
106
+ break if page_size <= 0
107
+ end
108
+ [diff,res.size]
109
+ else
110
+ [res,res.size]
111
+ end
112
+ end
113
+
114
+ # Deletes data from a given doctype,source,user
115
+ def delete_data(dockey,data={})
116
+ if dockey and data
117
+ @@db.pipelined do
118
+ data.each do |key,value|
119
+ value.each do |attrib,val|
120
+ @@db.srem(dockey,setelement(key,attrib,val))
121
+ end
122
+ end
123
+ end
124
+ end
125
+ true
126
+ end
127
+
128
+ # Deletes all keys matching a given mask
129
+ def flash_data(keymask)
130
+ @@db.keys(keymask).each do |key|
131
+ @@db.del(key)
132
+ end
133
+ end
134
+
135
+ # Returns array of keys matching a given keymask
136
+ def get_keys(keymask)
137
+ @@db.keys(keymask)
138
+ end
139
+
140
+ # Returns true if given item is a member of the given set
141
+ def ismember?(setkey,item)
142
+ @@db.sismember(setkey,item)
143
+ end
144
+
145
+ # Lock a given key and release when provided block is finished
146
+ def lock(dockey,timeout=0,raise_on_expire=false)
147
+ m_lock = get_lock(dockey,timeout,raise_on_expire)
148
+ res = yield
149
+ release_lock(dockey,m_lock)
150
+ res
151
+ end
152
+
153
+ def get_lock(dockey,timeout=0,raise_on_expire=false)
154
+ lock_key = _lock_key(dockey)
155
+ current_time = Time.now.to_i
156
+ ts = current_time+(Rhoconnect.lock_duration || timeout)+1
157
+ loop do
158
+ if not @@db.setnx(lock_key,ts)
159
+ if raise_on_expire or Rhoconnect.raise_on_expired_lock
160
+ if @@db.get(lock_key).to_i <= current_time
161
+ # lock expired before operation which set it up completed
162
+ # this process cannot continue without corrupting locked data
163
+ raise StoreLockException, "Lock \"#{lock_key}\" expired before it was released"
164
+ end
165
+ else
166
+ if @@db.get(lock_key).to_i <= current_time and
167
+ @@db.getset(lock_key,ts).to_i <= current_time
168
+ # previous lock expired and we replaced it with our own
169
+ break
170
+ end
171
+ end
172
+ sleep(1)
173
+ current_time = Time.now.to_i
174
+ else
175
+ break #no lock was set, so we set ours and leaving
176
+ end
177
+ end
178
+ return ts
179
+ end
180
+
181
+ # Due to redis bug #140, setnx always returns true so this doesn't work
182
+ # def get_lock(dockey,timeout=0)
183
+ # lock_key = _lock_key(dockey)
184
+ # until @@db.setnx(lock_key,1) do
185
+ # sleep(1)
186
+ # end
187
+ # @@db.expire(lock_key,timeout+1)
188
+ # Time.now.to_i+timeout+1
189
+ # end
190
+
191
+ def release_lock(dockey,lock)
192
+ @@db.del(_lock_key(dockey)) if (lock >= Time.now.to_i)
193
+ end
194
+
195
+ # Create a copy of srckey in dstkey
196
+ def clone(srckey,dstkey)
197
+ @@db.sdiffstore(dstkey,srckey,'')
198
+ end
199
+
200
+ # Rename srckey to dstkey
201
+ def rename(srckey,dstkey)
202
+ @@db.rename(srckey,dstkey) if @@db.exists(srckey)
203
+ end
204
+
205
+ alias_method :set_value, :put_value
206
+ alias_method :set_data, :put_data
207
+
208
+ private
209
+ def _get_redis(server=nil)
210
+ if ENV[REDIS_URL]
211
+ Redis.connect(:url => ENV[REDIS_URL])
212
+ elsif server and server.is_a?(String)
213
+ host,port,db,password = server.split(':')
214
+ Redis.new(:thread_safe => true, :host => host,
215
+ :port => port, :db => db, :password => password)
216
+ elsif server and server.is_a?(Redis)
217
+ server
218
+ else
219
+ Redis.new(:thread_safe => true)
220
+ end
221
+ end
222
+
223
+ def _lock_key(dockey)
224
+ "lock:#{dockey}"
225
+ end
226
+
227
+ def _is_reserved?(attrib,value) #:nodoc:
228
+ RESERVED_ATTRIB_NAMES.include? attrib
229
+ end
230
+ end
231
+ end
232
+ end