ChefWorker.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /**
  2. * Web Worker to handle communications between the front-end and the core.
  3. *
  4. * @author n1474335 [n1474335@gmail.com]
  5. * @copyright Crown Copyright 2017
  6. * @license Apache-2.0
  7. */
  8. import "babel-polyfill";
  9. import Chef from "./Chef.js";
  10. import OperationConfig from "./config/MetaConfig.js";
  11. import OpModules from "./config/modules/Default.js";
  12. // Set up Chef instance
  13. self.chef = new Chef();
  14. self.OpModules = OpModules;
  15. self.OperationConfig = OperationConfig;
  16. // Tell the app that the worker has loaded and is ready to operate
  17. self.postMessage({
  18. action: "workerLoaded",
  19. data: {}
  20. });
  21. /**
  22. * Respond to message from parent thread.
  23. *
  24. * Messages should have the following format:
  25. * {
  26. * action: "bake" | "silentBake",
  27. * data: {
  28. * input: {string},
  29. * recipeConfig: {[Object]},
  30. * options: {Object},
  31. * progress: {number},
  32. * step: {boolean}
  33. * } | undefined
  34. * }
  35. */
  36. self.addEventListener("message", function(e) {
  37. // Handle message
  38. const r = e.data;
  39. switch (r.action) {
  40. case "bake":
  41. bake(r.data);
  42. break;
  43. case "silentBake":
  44. silentBake(r.data);
  45. break;
  46. case "docURL":
  47. // Used to set the URL of the current document so that scripts can be
  48. // imported into an inline worker.
  49. self.docURL = r.data;
  50. break;
  51. case "highlight":
  52. calculateHighlights(
  53. r.data.recipeConfig,
  54. r.data.direction,
  55. r.data.pos
  56. );
  57. break;
  58. default:
  59. break;
  60. }
  61. });
  62. /**
  63. * Baking handler
  64. *
  65. * @param {Object} data
  66. */
  67. async function bake(data) {
  68. // Ensure the relevant modules are loaded
  69. loadRequiredModules(data.recipeConfig);
  70. try {
  71. const response = await self.chef.bake(
  72. data.input, // The user's input
  73. data.recipeConfig, // The configuration of the recipe
  74. data.options, // Options set by the user
  75. data.progress, // The current position in the recipe
  76. data.step // Whether or not to take one step or execute the whole recipe
  77. );
  78. self.postMessage({
  79. action: "bakeSuccess",
  80. data: response
  81. });
  82. } catch (err) {
  83. self.postMessage({
  84. action: "bakeError",
  85. data: err.message
  86. });
  87. }
  88. }
  89. /**
  90. * Silent baking handler
  91. */
  92. function silentBake(data) {
  93. const duration = self.chef.silentBake(data.recipeConfig);
  94. self.postMessage({
  95. action: "silentBakeComplete",
  96. data: duration
  97. });
  98. }
  99. /**
  100. * Checks that all required modules are loaded and loads them if not.
  101. *
  102. * @param {Object} recipeConfig
  103. */
  104. function loadRequiredModules(recipeConfig) {
  105. recipeConfig.forEach(op => {
  106. let module = self.OperationConfig[op.op].module;
  107. if (!OpModules.hasOwnProperty(module)) {
  108. console.log("Loading module " + module);
  109. self.sendStatusMessage("Loading module " + module);
  110. self.importScripts(self.docURL + "/" + module + ".js");
  111. }
  112. });
  113. }
  114. /**
  115. * Calculates highlight offsets if possible.
  116. *
  117. * @param {Object[]} recipeConfig
  118. * @param {string} direction
  119. * @param {Object} pos - The position object for the highlight.
  120. * @param {number} pos.start - The start offset.
  121. * @param {number} pos.end - The end offset.
  122. */
  123. function calculateHighlights(recipeConfig, direction, pos) {
  124. pos = self.chef.calculateHighlights(recipeConfig, direction, pos);
  125. self.postMessage({
  126. action: "highlightsCalculated",
  127. data: pos
  128. });
  129. }
  130. /**
  131. * Send status update to the app.
  132. *
  133. * @param {string} msg
  134. */
  135. self.sendStatusMessage = function(msg) {
  136. self.postMessage({
  137. action: "statusMessage",
  138. data: msg
  139. });
  140. };
  141. /**
  142. * Send an option value update to the app.
  143. *
  144. * @param {string} option
  145. * @param {*} value
  146. */
  147. self.setOption = function(option, value) {
  148. self.postMessage({
  149. action: "optionUpdate",
  150. data: {
  151. option: option,
  152. value: value
  153. }
  154. });
  155. };