Files: 07c0df717b109d015093957f1176a824fe29d25a / index.js
3469 bytesRaw
1 | const Graph = require('ipld-graph-builder') |
2 | const ExoInterface = require('./exoInterface.js') |
3 | |
4 | module.exports = class Hypervisor { |
5 | /** |
6 | * The Hypervisor manages the container instances by instantiating them and |
7 | * destorying them when possible. It also facilitates localating Containers |
8 | * @param {Graph} dag an instance of [ipfs.dag](https://github.com/ipfs/interface-ipfs-core/tree/master/API/dag#dag-api) |
9 | */ |
10 | constructor (dag) { |
11 | this.graph = new Graph(dag) |
12 | this._runningContainers = new Map() |
13 | this._containerTypes = {} |
14 | } |
15 | |
16 | async getByPath (root, path) { |
17 | path = path.split('/') |
18 | for (const name of path) { |
19 | const portRef = root.ports.get(name) |
20 | root = await this.getOrCreateInstance(portRef, root.entryPort) |
21 | } |
22 | return root |
23 | } |
24 | |
25 | /** |
26 | * get a contrainer instance given its entry port and its mounting port |
27 | * @param {Object} port the entry port for the container |
28 | * @param {Object} parentPort the entry port of the parent container |
29 | */ |
30 | async getOrCreateInstance (port, parentPort) { |
31 | let instance = this._runningContainers.get(port) |
32 | // if there is no container running crceate one |
33 | if (!instance) { |
34 | instance = await this.createInstance(port.type, port.link, port, parentPort) |
35 | instance.on('idle', () => { |
36 | // once the container is done shut it down |
37 | this._runningContainers.delete(port) |
38 | }) |
39 | } |
40 | return instance |
41 | } |
42 | |
43 | /** |
44 | * given a port, wait untill its source contract has reached the threshold |
45 | * tick count |
46 | * @param {Object} port the port to wait on |
47 | * @param {Number} threshold the number of ticks to wait before resolving |
48 | * @param {Object} fromPort the entryPort of the container requesting the |
49 | * wait. Used internally so that waits don't become cyclic |
50 | */ |
51 | async wait (port, threshold, fromPort) { |
52 | let instance = this._runningContainers.get(port) |
53 | if (instance) { |
54 | return instance.wait(threshold, fromPort) |
55 | } else { |
56 | return threshold |
57 | } |
58 | } |
59 | |
60 | /** |
61 | * creates an instance given the container type, starting state, entry port |
62 | * and the parentPort |
63 | * @param {String} the type of VM to load |
64 | * @param {Object} the starting state of the VM |
65 | * @param {Object} the entry port |
66 | * @param {Object} the parent port |
67 | */ |
68 | async createInstance (type, state, entryPort = null, parentPort) { |
69 | const Container = this._containerTypes[type] |
70 | |
71 | if (!state) { |
72 | state = { |
73 | '/': Container.createState() |
74 | } |
75 | } |
76 | |
77 | // create a new kernel instance |
78 | const exoInterface = new ExoInterface({ |
79 | entryPort: entryPort, |
80 | parentPort: parentPort, |
81 | hypervisor: this, |
82 | state: state, |
83 | Container: Container |
84 | }) |
85 | |
86 | // save the newly created instance |
87 | this._runningContainers.set(entryPort, exoInterface) |
88 | await exoInterface.start() |
89 | return exoInterface |
90 | } |
91 | |
92 | /** |
93 | * creates a state root starting from a given container and a given number of |
94 | * ticks |
95 | * @param {Container} container an container instance |
96 | * @param {Number} ticks the number of ticks at which to create the state root |
97 | */ |
98 | async createStateRoot (container, ticks) { |
99 | await container.wait(ticks) |
100 | return this.graph.flush(container.state) |
101 | } |
102 | |
103 | /** |
104 | * regirsters a container with the hypervisor |
105 | * @param {String} the name of the type |
106 | * @param {Class} a Class for instantiating the container |
107 | */ |
108 | registerContainer (type, vm) { |
109 | this._containerTypes[type] = vm |
110 | } |
111 | } |
112 |
Built with git-ssb-web