InstanceManager.mjs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Copyright (C) 2024-present Puter Technologies Inc.
  3. *
  4. * This file is part of Puter.
  5. *
  6. * Puter is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published
  8. * by the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import Instance from "./Instance.mjs"
  20. /**
  21. * Class representing the basic interface for managing instances of emulated machines.
  22. */
  23. class InstanceManager {
  24. /**
  25. * Create an Instance Manager.
  26. * @param {Object} [options] - Options for configuring the instance manager.
  27. * @param {boolean} [options.screen=true] - Spawn screen option.
  28. * @param {boolean} [options.term=false] - Spawn terminal option.
  29. * @param {string} [options.instanceName="Host"] - Name of the instance.
  30. * @param {number} [options.memory=1024] - Memory size for the instance; must be power of two.
  31. * @param {HTMLElement} [options.spawnRoot=undefined] - Htlm element where instance should be spawned.
  32. * @param {boolean} [options.autoStart=true] - Whether to automatically start the instance.
  33. * @param {string} [options.remote="./"] - Remote URL, defaults to origin.
  34. * @param {string} [options.wsUrl=""] - Websocket URL option.
  35. */
  36. constructor(options) {
  37. const defaultOptions = {
  38. term: false,
  39. screen: false,
  40. instanceName: "Host",
  41. memory: 1024,
  42. spawnRoot: undefined,
  43. autoStart: true,
  44. remote: "./",
  45. wsUrl: "",
  46. };
  47. const instanceOptions = { ...defaultOptions, ...options };
  48. this.instances = {};
  49. this.instanceNames = [];
  50. this.curr_inst = 0;
  51. this.instanceNames.push(instanceOptions.instanceName);
  52. this.instances[instanceOptions.instanceName] = new Instance(instanceOptions);
  53. }
  54. /**
  55. * Create an instance with given options and adds it to the pool of instances.
  56. * @param {Object} options - Options for configuring the instance.
  57. * @returns {Promise<Object>} - Resolves with the initialized instance.
  58. */
  59. async createInstance(options) {
  60. const instance = new Instance(options);
  61. this.instanceNames.push(instance.instanceName);
  62. this.instances[instance.instanceName] = instance;
  63. return instance;
  64. }
  65. /**
  66. * Continue running a suspended instance.
  67. * @param {string} instName - instName of the instance to continue.
  68. */
  69. async continueInstance(instName) {
  70. var instance = await this.getInstanceByinstName(instName);
  71. if (!instance.vm.cpu_is_running)
  72. await instance.vm.run();
  73. }
  74. /**
  75. * Suspend a running instance.
  76. * @param {string} instName - instName of the instance to suspend.
  77. */
  78. async suspendInstance(instName) {
  79. var instance = await this.getInstanceByinstName(instName);
  80. if (instance.vm.cpu_is_running)
  81. await instance.vm.stop();
  82. }
  83. /**
  84. * Save the state of a running instance.
  85. * @param {string} instName - instName of the instance to save state.
  86. * @returns {Promise} - Promise resolving once state is saved.
  87. */
  88. async saveState(instName) {
  89. const instance = this.getInstanceByinstName(instName);
  90. if (instance.vm.cpu_is_running)
  91. return instance.vm.save_state();
  92. }
  93. /**
  94. * Load the state of a previously saved instance.
  95. * @param {string} instName - instName of the instance to load state.
  96. * @param {any} state - State to load.
  97. * @returns {Promise} - Promise resolving once state is loaded.
  98. */
  99. async loadState(instName, state) {
  100. const instance = this.getInstanceByinstName(instName);
  101. if (instance.vm.cpu_is_running)
  102. await instance.vm.save_state(state);
  103. }
  104. /**
  105. * Connect two instances for communication through NIC's.
  106. * @param {string} destinationinstName - instName of the destination instance.
  107. * @param {string} sourceinstName - instName of the source instance.
  108. */
  109. async connectInstances(destinationinstName, sourceinstName) {
  110. const destinationInstance = this.getInstanceByinstName(destinationinstName);
  111. const sourceInstance = this.getInstanceByinstName(sourceinstName);
  112. destinationInstance.add_listener("net0-send", (data) => {
  113. source.bus.send("net0-receive", data);
  114. });
  115. sourceInstance.add_listener("net0-send", (data) => {
  116. destination.bus.send("net0-receive", data);
  117. });
  118. }
  119. /**
  120. * Execute a command within an instance.
  121. * @param {Object} inst - Instance object.
  122. * @param {string} cmd - Command to execute.
  123. * @param {Object} env - Environment variables.
  124. * @param {number} [timeout=60] - Timeout for the command execution.
  125. */
  126. async exec(inst, cmd, env, timeout = 60) {
  127. // TODO: instNamed pipes on the instance would make this super nice so multiple terminals can be had
  128. }
  129. /**
  130. * Destroy a specific instance.
  131. * @param {string} instName - instName of the instance to destroy.
  132. */
  133. async destroyInstance(instName) {
  134. await this.getInstanceByinstName(instName).destroy();
  135. }
  136. /**
  137. * Destroy all instances.
  138. */
  139. async destroyInstances() {
  140. for (const instance in this.instances)
  141. destroyInstance(instance)
  142. }
  143. /**
  144. * Get an instance by its instName.
  145. * @param {string} instName - instName of the instance.
  146. * @returns {Object} - The instance object.
  147. * @throws Will throw an error if the instance instName is not found.
  148. */
  149. async getInstanceByinstName(instName) {
  150. if (!(instName in this.instances))
  151. throw Error("getInstance: instName not found in instances object");
  152. return this.instances[instName];
  153. }
  154. }
  155. export default InstanceManager