InstanceManager.mjs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import Instance from "./Instance.mjs"
  2. /**
  3. * Class representing the basic interface for managing instances of emulated machines.
  4. */
  5. class InstanceManager {
  6. /**
  7. * Create an Instance Manager.
  8. * @param {Object} [options] - Options for configuring the instance manager.
  9. * @param {boolean} [options.screen=true] - Spawn screen option.
  10. * @param {boolean} [options.term=false] - Spawn terminal option.
  11. * @param {string} [options.instanceName="Host"] - Name of the instance.
  12. * @param {number} [options.memory=1024] - Memory size for the instance; must be power of two.
  13. * @param {HTMLElement} [options.spawnRoot=undefined] - Htlm element where instance should be spawned.
  14. * @param {boolean} [options.autoStart=true] - Whether to automatically start the instance.
  15. * @param {string} [options.remote="./"] - Remote URL, defaults to origin.
  16. * @param {string} [options.wsUrl=""] - Websocket URL option.
  17. */
  18. constructor(options) {
  19. const defaultOptions = {
  20. term: true,
  21. screen: false,
  22. instanceName: "Host",
  23. memory: 1024,
  24. spawnRoot: undefined,
  25. autoStart: true,
  26. remote: "./",
  27. wsUrl: "",
  28. };
  29. const instanceOptions = { ...defaultOptions, ...options };
  30. this.instances = {};
  31. this.instanceNames = [];
  32. this.curr_inst = 0;
  33. this.instanceNames.push(instanceOptions.instanceName);
  34. this.instances[instanceOptions.instanceName] = this.initInstance(instanceOptions);
  35. }
  36. /**
  37. * Initialize an instance with given options.
  38. * @param {Object} options - Options for configuring the instance.
  39. * @returns {Promise<Object>} - Resolves with the initialized instance.
  40. */
  41. initInstance(options) {
  42. return new Instance(options);
  43. }
  44. /**
  45. * Continue running a suspended instance.
  46. * @param {string} instName - instName of the instance to continue.
  47. */
  48. async continueInstance(instName) {
  49. var instance = await this.getInstanceByinstName(instName);
  50. if (!instance.vm.cpu_is_running)
  51. await instance.vm.run();
  52. }
  53. /**
  54. * Suspend a running instance.
  55. * @param {string} instName - instName of the instance to suspend.
  56. */
  57. async suspendInstance(instName) {
  58. var instance = await this.getInstanceByinstName(instName);
  59. if (instance.vm.cpu_is_running)
  60. await instance.vm.stop();
  61. }
  62. /**
  63. * Save the state of a running instance.
  64. * @param {string} instName - instName of the instance to save state.
  65. * @returns {Promise} - Promise resolving once state is saved.
  66. */
  67. async saveState(instName) {
  68. const instance = this.getInstanceByinstName(instName);
  69. if (instance.vm.cpu_is_running)
  70. return instance.vm.save_state();
  71. }
  72. /**
  73. * Load the state of a previously saved instance.
  74. * @param {string} instName - instName of the instance to load state.
  75. * @param {any} state - State to load.
  76. * @returns {Promise} - Promise resolving once state is loaded.
  77. */
  78. async loadState(instName, state) {
  79. const instance = this.getInstanceByinstName(instName);
  80. if (instance.vm.cpu_is_running)
  81. await instance.vm.save_state(state);
  82. }
  83. /**
  84. * Connect two instances for communication through NIC's.
  85. * @param {string} destinationinstName - instName of the destination instance.
  86. * @param {string} sourceinstName - instName of the source instance.
  87. */
  88. async connectInstances(destinationinstName, sourceinstName) {
  89. const destinationInstance = this.getInstanceByinstName(destinationinstName);
  90. const sourceInstance = this.getInstanceByinstName(sourceinstName);
  91. destinationInstance.add_listener("net0-send", (data) => {
  92. source.bus.send("net0-receive", data);
  93. });
  94. sourceInstance.add_listener("net0-send", (data) => {
  95. destination.bus.send("net0-receive", data);
  96. });
  97. }
  98. /**
  99. * Execute a command within an instance.
  100. * @param {Object} inst - Instance object.
  101. * @param {string} cmd - Command to execute.
  102. * @param {Object} env - Environment variables.
  103. * @param {number} [timeout=60] - Timeout for the command execution.
  104. */
  105. async exec(inst, cmd, env, timeout = 60) {
  106. // TODO: instNamed pipes on the instance would make this super nice so multiple terminals can be had
  107. }
  108. /**
  109. * Destroy a specific instance.
  110. * @param {string} instName - instName of the instance to destroy.
  111. */
  112. async destroyInstance(instName) {
  113. await this.getInstanceByinstName(instName).destroy();
  114. }
  115. /**
  116. * Destroy all instances.
  117. */
  118. async destroyInstances() {
  119. for (const instance in this.instances)
  120. destroyInstance(instance)
  121. }
  122. /**
  123. * Get an instance by its instName.
  124. * @param {string} instName - instName of the instance.
  125. * @returns {Object} - The instance object.
  126. * @throws Will throw an error if the instance instName is not found.
  127. */
  128. async getInstanceByinstName(instName) {
  129. if (!(instName in this.instances))
  130. throw Error("getInstance: instName not found in instances object");
  131. return this.instances[instName];
  132. }
  133. }
  134. export default InstanceManager