Instance.mjs 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import * as libv86 from '../third-party/libv86.js';
  2. /**
  3. * Class representing an Instance of an emulator machine.
  4. */
  5. class Instance {
  6. /**
  7. * Create an Instance.
  8. * @param {Object} options - Options for configuring the instance.
  9. * @param {boolean} [options.term=true] - Terminal option.
  10. * @param {boolean} [options.screen=false] - Screen option.
  11. * @param {number} [options.memory=1024] - Memory size for the instance; must be power of two.
  12. * @param {HTMLElement} [options.spawnRoot=undefined] - Html element where instance should be spawned.
  13. * @param {boolean} [options.autoStart=true] - Whether to automatically start the instance.
  14. * @param {string} [options.remote="./"] - Remote URL, defaults to origin.
  15. * @param {string} [options.wsUrl=""] - Websocket URL option for communication with the outside world.
  16. * @throws Will throw an error if remote URL does not end with a slash. @throws Will throw an error if the amount of memory provided is not a power of two.
  17. */
  18. constructor(options) {
  19. const defaultOptions = {
  20. term: true,
  21. screen: false,
  22. memory: 1024,
  23. spawnRoot: undefined,
  24. autoStart: true,
  25. remote: "./",
  26. instanceName: [...Array(10)].map(() => Math.random().toString(36)[2]).join(''),
  27. wsUrl: "",
  28. };
  29. const instanceOptions = { ...defaultOptions, ...options };
  30. if (!instanceOptions.remote.endsWith('/'))
  31. throw new Error("Remote URL must end with a slash");
  32. if (typeof self !== 'undefined' && self.crypto) {
  33. this.instanceID = self.crypto.randomUUID();
  34. } else {
  35. this.instanceID = "Node";
  36. }
  37. this.terminals = [];
  38. let v86Options = {
  39. wasm_path: instanceOptions.remote + "third-party/v86.wasm",
  40. preserve_mac_from_state_image: true,
  41. memory_size: instanceOptions.memory * 1024 * 1024,
  42. vga_memory_size: 8 * 1024 * 1024,
  43. initial_state: { url: instanceOptions.remote + "static/image.bin" },
  44. filesystem: { baseurl: instanceOptions.remote + "static/9p-rootfs/" },
  45. autostart: instanceOptions.autoStart,
  46. };
  47. if (!(instanceOptions.wsUrl === ""))
  48. v86Options.network_relay_url = instanceOptions.wsUrl;
  49. if (!((Math.log(v86Options.memory_size) / Math.log(2)) % 1 === 0))
  50. throw new Error("Amount of memory provided isn't a power of two");
  51. if (instanceOptions.screen === true) {
  52. instanceOptions.spawnRoot.appendChild((() => {
  53. const div = document.createElement("div");
  54. div.setAttribute("id", instanceOptions.instanceName + '-screen');
  55. const child_div = document.createElement("div");
  56. child_div.setAttribute("style", "white-space: pre; font: 14px monospace; line-height: 14px");
  57. const canvas = document.createElement("canvas");
  58. canvas.setAttribute("style", "display: none");
  59. div.appendChild(child_div);
  60. div.appendChild(canvas);
  61. return div;
  62. })());
  63. v86Options.screen_container = document.getElementById(instanceOptions.instanceName + '-screen');
  64. }
  65. this.vm = new libv86.V86(v86Options);
  66. }
  67. }
  68. export default Instance