server.js.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: server.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: server.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>/**
  20. * Object for communicating with the external servers. This includes functionality for
  21. * saving and loading files, logging events, saving completions, and retrieving history.
  22. *
  23. * @constructor
  24. * @this {BlockPyServer}
  25. * @param {Object} main - The main BlockPy instance
  26. */
  27. function BlockPyServer(main) {
  28. this.main = main;
  29. // Add the LocalStorage connection
  30. // Presently deprecated, but we should investigate this
  31. this.storage = new LocalStorageWrapper("BLOCKPY");
  32. this.saveTimer = {};
  33. this.presentationTimer = null;
  34. // For managing "walks" that let us rerun stored code
  35. this.inProgressWalks = [];
  36. this.createSubscriptions();
  37. }
  38. BlockPyServer.prototype.createSubscriptions = function() {
  39. var server = this, model = this.main.model;
  40. model.program.subscribe(function() { server.saveCode(); });
  41. model.assignment.name.subscribe(function(e) { server.saveAssignment();});
  42. model.assignment.introduction.subscribe(function(e) { server.saveAssignment(); });
  43. model.assignment.parsons.subscribe(function(e) { server.saveAssignment(); });
  44. model.assignment.importable.subscribe(function(e) { server.saveAssignment(); });
  45. model.assignment.disable_algorithm_errors.subscribe(function(e) { server.saveAssignment(); });
  46. model.assignment.initial_view.subscribe(function(e) { server.saveAssignment(); });
  47. model.settings.editor.subscribe(function(newValue) { server.logEvent('editor', newValue); });
  48. model.execution.show_trace.subscribe(function(newValue) { server.logEvent('trace', newValue); });
  49. model.execution.trace_step.subscribe(function(newValue) { server.logEvent('trace_step', newValue); });
  50. };
  51. /**
  52. *
  53. * Some subscriptions have to happen after other things have been loaded.
  54. * Right now this is just after CORGIS libraries have been loaded, but maybe
  55. * we'll add more later and this will need to be refactored.
  56. *
  57. */
  58. BlockPyServer.prototype.finalizeSubscriptions = function() {
  59. var server = this, model = this.main.model;
  60. model.assignment.modules.subscribe(function(e) { server.saveAssignment(); });
  61. };
  62. BlockPyServer.prototype.TIMER_DELAY = 1000;
  63. BlockPyServer.prototype.createServerData = function() {
  64. var assignment = this.main.model.assignment;
  65. var d = new Date();
  66. var seconds = Math.round(d.getTime() / 1000);
  67. data = {
  68. 'assignment_id': assignment.assignment_id,
  69. 'course_id': assignment.course_id,
  70. 'student_id': assignment.student_id,
  71. 'version': assignment.version(),
  72. 'timestamp': seconds
  73. };
  74. if (this.main.model.settings.log_id() != null) {
  75. data['log_id'] = this.main.model.settings.log_id();
  76. }
  77. return data;
  78. }
  79. BlockPyServer.prototype.setStatus = function(status, server_error) {
  80. this.main.model.status.server(status);
  81. if (server_error !== undefined) {
  82. this.main.model.status.server_error(server_error);
  83. } else {
  84. this.main.model.status.server_error('');
  85. }
  86. }
  87. BlockPyServer.prototype.defaultResponseWithoutVersioning = function(response) {
  88. if (response.success) {
  89. this.setStatus('Saved');
  90. } else {
  91. console.error(response);
  92. this.setStatus('Error', response.message);
  93. }
  94. }
  95. BlockPyServer.prototype.defaultResponse = function(response) {
  96. /*console.log(response);
  97. if (!response.is_version_correct) {
  98. this.setStatus('Out of date');
  99. } else */if (response.success) {
  100. this.setStatus('Saved');
  101. } else {
  102. console.error(response);
  103. this.setStatus('Error', response.message);
  104. }
  105. }
  106. BlockPyServer.prototype.defaultFailure = function(error, textStatus) {
  107. this.setStatus('Disconnected', "Could not access server!\n"+textStatus);
  108. }
  109. BlockPyServer.prototype.logEvent = function(event_name, action, body) {
  110. var data = this.createServerData();
  111. data['event'] = event_name;
  112. data['action'] = action;
  113. if (body === undefined) {
  114. data['body'] = '';
  115. } else {
  116. data['body'] = body;
  117. }
  118. this.setStatus('Logging');
  119. if (this.main.model.server_is_connected('log_event')) {
  120. $.post(this.main.model.constants.urls.log_event, data,
  121. this.defaultResponse.bind(this))
  122. .fail(this.defaultFailure.bind(this));
  123. } else {
  124. this.setStatus('Offline', "Server is not connected!");
  125. }
  126. }
  127. BlockPyServer.prototype.markSuccess = function(success) {
  128. var data = this.createServerData();
  129. var server = this,
  130. model = this.main.model;
  131. data['code'] = model.programs.__main__;
  132. data['status'] = success;
  133. this.main.components.editor.getPngFromBlocks(function(pngData, img) {
  134. data['image'] = pngData;
  135. img.remove();
  136. server.setStatus('Saving');
  137. if (model.server_is_connected('save_success')) {
  138. $.post(model.constants.urls.save_success, data,
  139. server.defaultResponse.bind(server))
  140. .fail(server.defaultFailure.bind(server));
  141. } else {
  142. server.setStatus('Offline', "Server is not connected!");
  143. }
  144. });
  145. };
  146. BlockPyServer.prototype.saveAssignment = function() {
  147. var data = this.createServerData();
  148. var model = this.main.model;
  149. data['introduction'] = model.assignment.introduction();
  150. data['parsons'] = model.assignment.parsons();
  151. data['initial'] = model.assignment.initial_view();
  152. data['importable'] = model.assignment.importable();
  153. data['disable_algorithm_errors'] = model.assignment.disable_algorithm_errors();
  154. data['name'] = model.assignment.name();
  155. //data['disabled'] = disabled;
  156. data['modules'] = model.assignment.modules().join(','); // TODO: hackish, broken if ',' is in name
  157. var server = this;
  158. this.setStatus('Saving');
  159. if (this.main.model.server_is_connected('save_assignment') &amp;&amp;
  160. this.main.model.settings.auto_upload()) {
  161. clearTimeout(this.presentationTimer);
  162. this.presentationTimer = setTimeout(function() {
  163. $.post(server.main.model.constants.urls.save_assignment, data,
  164. server.defaultResponseWithoutVersioning.bind(server))
  165. .fail(server.defaultFailure.bind(server));
  166. }, this.TIMER_DELAY);
  167. } else {
  168. this.setStatus('Offline', "Server is not connected!");
  169. }
  170. }
  171. BlockPyServer.prototype.saveCode = function() {
  172. var filename = this.main.model.settings.filename();
  173. var data = this.createServerData();
  174. data['filename'] = filename;
  175. data['code'] = this.main.model.programs[filename]();
  176. var server = this;
  177. this.setStatus('Saving');
  178. if (this.main.model.server_is_connected('save_code') &amp;&amp;
  179. this.main.model.settings.auto_upload()) {
  180. if (this.saveTimer[filename]) {
  181. clearTimeout(this.saveTimer[filename]);
  182. }
  183. this.saveTimer[filename] = setTimeout(function() {
  184. $.post(server.main.model.constants.urls.save_code, data,
  185. filename == '__main__'
  186. ? server.defaultResponse.bind(server)
  187. : server.defaultResponseWithoutVersioning.bind(server))
  188. .fail(server.defaultFailure.bind(server));
  189. }, this.TIMER_DELAY);
  190. } else {
  191. this.setStatus('Offline', "Server is not connected!");
  192. }
  193. }
  194. BlockPyServer.prototype.getHistory = function(callback) {
  195. var data = this.createServerData();
  196. var model = this.main.model;
  197. var server = this;
  198. this.setStatus('Loading History');
  199. if (model.server_is_connected('get_history')) {
  200. $.post(model.constants.urls.get_history, data,
  201. function(response) {
  202. if (response.success) {
  203. server.setStatus('Saved');
  204. callback(response.data);
  205. } else {
  206. console.error(response);
  207. server.setStatus('Error', response.message);
  208. }
  209. })
  210. .fail(server.defaultFailure.bind(server));
  211. } else {
  212. this.setStatus('Offline', "Server is not connected!");
  213. callback([]);
  214. /*callback([
  215. {code: "=", time: "20160801-105102"},
  216. {code: "= 0", time: "20160801-105112"},
  217. {code: "a = 0", time: "20160801-105502"},
  218. {code: "a = 0\nprint", time: "20160801-110003"},
  219. {code: "a = 0\nprint(a)", time: "20160801-111102"}
  220. ])*/
  221. }
  222. }
  223. BlockPyServer.prototype.walkOldCode = function() {
  224. var server = this,
  225. main = this.main;
  226. if (this.inProgressWalks.length > 0) {
  227. var response = this.inProgressWalks.pop();
  228. console.log('Processing walk', response.log_id);
  229. main.setCode(response.code, '__main__');
  230. main.setCode(response.feedback, 'give_feedback');
  231. main.model.assignment.assignment_id = response.assignment_id;
  232. main.model.assignment.user_id = response.user_id;
  233. main.model.settings.log_id(response.log_id);
  234. main.components.engine.onExecutionEnd = function(newState) {
  235. console.log(response.log_id, newState);
  236. main.components.engine.onExecutionEnd = null;
  237. setTimeout(function() {
  238. server.walkOldCode()
  239. }, 0);
  240. };
  241. console.log("Running");
  242. main.components.engine.run();
  243. } else {
  244. var data = this.createServerData();
  245. this.setStatus('Retrieving');
  246. if (main.model.server_is_connected('walk_old_code')) {
  247. $.post(server.main.model.constants.urls.walk_old_code, data,
  248. function (response) {
  249. if (response.success) {
  250. if (response.more_to_do) {
  251. server.inProgressWalks = response.walks;
  252. server.walkOldCode();
  253. }
  254. } else {
  255. this.setStatus('Failure', response.message);
  256. }
  257. })
  258. .fail(
  259. function(response) {
  260. console.error(response);
  261. setTimeout(function() {
  262. server.walkOldCode()
  263. }, 3000);
  264. }
  265. );
  266. //server.defaultFailure.bind(server));
  267. } else {
  268. this.setStatus('Offline', "Server is not connected!");
  269. }
  270. }
  271. }
  272. /*
  273. BlockPyServer.prototype.load = function() {
  274. var data = {
  275. 'question_id': this.model.question.question_id,
  276. 'student_id': this.model.question.student_id,
  277. 'context_id': this.model.question.context_id
  278. };
  279. var alertBox = this.alertBox;
  280. var server = this, blockpy = this.blockpy;
  281. if (this.model.urls.server !== false &amp;&amp; this.model.urls.load_code !== false) {
  282. $.post(this.model.urls.load_code, data, function(response) {
  283. if (response.success) {
  284. if (server.storage.has(data.question_id)) {
  285. if (server.storage.is_new(data.question_id, response.timestamp)) {
  286. var xml = server.storage.get(data.question_id);
  287. server.model.load(xml);
  288. server.save();
  289. } else {
  290. server.storage.remove(data.question_id);
  291. if (response.code !== null) {
  292. server.model.load(response.code);
  293. }
  294. }
  295. } else {
  296. if (response.code !== null) {
  297. server.model.load(response.code);
  298. }
  299. }
  300. if (response.completed) {
  301. blockpy.feedback.success('');
  302. }
  303. alertBox("Loaded").delay(200).fadeOut("slow");
  304. } else {
  305. console.error("Server Load Error", response.message);
  306. alertBox("Loading failed");
  307. }
  308. }).fail(function() {
  309. alertBox("Loading failed");
  310. }).always(function() {
  311. server.model.loaded = true;
  312. });
  313. } else {
  314. server.model.loaded = true;
  315. alertBox("Loaded").delay(200).fadeOut("slow");
  316. if (this.model.urls.load_success === true) {
  317. this.blockpy.feedback.success('');
  318. }
  319. }
  320. };
  321. */</code></pre>
  322. </article>
  323. </section>
  324. </div>
  325. <nav>
  326. <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="BlockPy.html">BlockPy</a></li><li><a href="BlockPyCorgis.html">BlockPyCorgis</a></li><li><a href="BlockPyDialog.html">BlockPyDialog</a></li><li><a href="BlockPyEditor.html">BlockPyEditor</a></li><li><a href="BlockPyEngine.html">BlockPyEngine</a></li><li><a href="BlockPyEnglish.html">BlockPyEnglish</a></li><li><a href="BlockPyFeedback.html">BlockPyFeedback</a></li><li><a href="BlockPyHistory.html">BlockPyHistory</a></li><li><a href="BlockPyPresentation.html">BlockPyPresentation</a></li><li><a href="BlockPyPrinter.html">BlockPyPrinter</a></li><li><a href="BlockPyServer.html">BlockPyServer</a></li><li><a href="BlockPyToolbar.html">BlockPyToolbar</a></li><li><a href="LocalStorageWrapper.html">LocalStorageWrapper</a></li><li><a href="PythonToBlocks.html">PythonToBlocks</a></li></ul><h3>Global</h3><ul><li><a href="global.html#BlockPyInterface">BlockPyInterface</a></li><li><a href="global.html#cloneNode">cloneNode</a></li><li><a href="global.html#encodeHTML">encodeHTML</a></li><li><a href="global.html#expandArray">expandArray</a></li><li><a href="global.html#EXTENDED_ERROR_EXPLANATION">EXTENDED_ERROR_EXPLANATION</a></li><li><a href="global.html#indent">indent</a></li><li><a href="global.html#instructor_module">instructor_module</a></li><li><a href="global.html#prettyPrintDateTime">prettyPrintDateTime</a></li><li><a href="global.html#randomInteger">randomInteger</a></li><li><a href="global.html#set_button_loaded">set_button_loaded</a></li><li><a href="global.html#timerGuard">timerGuard</a></li></ul>
  327. </nav>
  328. <br class="clear">
  329. <footer>
  330. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Sun Mar 26 2017 09:45:03 GMT-0400 (Eastern Daylight Time)
  331. </footer>
  332. <script> prettyPrint(); </script>
  333. <script src="scripts/linenumber.js"> </script>
  334. </body>
  335. </html>