InstanceManager.mjs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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: false,
  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] = new Instance(instanceOptions);
  35. }
  36. /**
  37. * Create an instance with given options and adds it to the pool of instances.
  38. * @param {Object} options - Options for configuring the instance.
  39. * @returns {Promise<Object>} - Resolves with the initialized instance.
  40. */
  41. async createInstance(options) {
  42. const instance = new Instance(options);
  43. this.instanceNames.push(instance.instanceName);
  44. this.instances[instance.instanceName] = instance;
  45. return instance;
  46. }
  47. /**
  48. * Continue running a suspended instance.
  49. * @param {string} instName - instName of the instance to continue.
  50. */
  51. async continueInstance(instName) {
  52. var instance = await this.getInstanceByinstName(instName);
  53. if (!instance.vm.cpu_is_running)
  54. await instance.vm.run();
  55. }
  56. /**
  57. * Suspend a running instance.
  58. * @param {string} instName - instName of the instance to suspend.
  59. */
  60. async suspendInstance(instName) {
  61. var instance = await this.getInstanceByinstName(instName);
  62. if (instance.vm.cpu_is_running)
  63. await instance.vm.stop();
  64. }
  65. /**
  66. * Save the state of a running instance.
  67. * @param {string} instName - instName of the instance to save state.
  68. * @returns {Promise} - Promise resolving once state is saved.
  69. */
  70. async saveState(instName) {
  71. const instance = this.getInstanceByinstName(instName);
  72. if (instance.vm.cpu_is_running)
  73. return instance.vm.save_state();
  74. }
  75. /**
  76. * Load the state of a previously saved instance.
  77. * @param {string} instName - instName of the instance to load state.
  78. * @param {any} state - State to load.
  79. * @returns {Promise} - Promise resolving once state is loaded.
  80. */
  81. async loadState(instName, state) {
  82. const instance = this.getInstanceByinstName(instName);
  83. if (instance.vm.cpu_is_running)
  84. await instance.vm.save_state(state);
  85. }
  86. /**
  87. * Connect two instances for communication through NIC's.
  88. * @param {string} destinationinstName - instName of the destination instance.
  89. * @param {string} sourceinstName - instName of the source instance.
  90. */
  91. async connectInstances(destinationinstName, sourceinstName) {
  92. const destinationInstance = this.getInstanceByinstName(destinationinstName);
  93. const sourceInstance = this.getInstanceByinstName(sourceinstName);
  94. destinationInstance.add_listener("net0-send", (data) => {
  95. source.bus.send("net0-receive", data);
  96. });
  97. sourceInstance.add_listener("net0-send", (data) => {
  98. destination.bus.send("net0-receive", data);
  99. });
  100. }
  101. /**
  102. * Execute a command within an instance.
  103. * @param {Object} inst - Instance object.
  104. * @param {string} cmd - Command to execute.
  105. * @param {Object} env - Environment variables.
  106. * @param {number} [timeout=60] - Timeout for the command execution.
  107. */
  108. async exec(inst, cmd, env, timeout = 60) {
  109. // TODO: instNamed pipes on the instance would make this super nice so multiple terminals can be had
  110. }
  111. /**
  112. * Destroy a specific instance.
  113. * @param {string} instName - instName of the instance to destroy.
  114. */
  115. async destroyInstance(instName) {
  116. await this.getInstanceByinstName(instName).destroy();
  117. }
  118. /**
  119. * Destroy all instances.
  120. */
  121. async destroyInstances() {
  122. for (const instance in this.instances)
  123. destroyInstance(instance)
  124. }
  125. /**
  126. * Get an instance by its instName.
  127. * @param {string} instName - instName of the instance.
  128. * @returns {Object} - The instance object.
  129. * @throws Will throw an error if the instance instName is not found.
  130. */
  131. async getInstanceByinstName(instName) {
  132. if (!(instName in this.instances))
  133. throw Error("getInstance: instName not found in instances object");
  134. return this.instances[instName];
  135. }
  136. }
  137. export default InstanceManager