git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: bde72a3aa9363b13bf59b50cff532ff35ef665f4

Files: bde72a3aa9363b13bf59b50cff532ff35ef665f4 / index.js

4544 bytesRaw
1const Graph = require('ipld-graph-builder')
2const Message = require('primea-message')
3const Kernel = require('./kernel.js')
4const Scheduler = require('./scheduler.js')
5const DFSchecker = require('./dfsChecker.js')
6
7const ROOT_ID = 'zdpuAm6aTdLVMUuiZypxkwtA7sKm7BWERy8MPbaCrFsmiyzxr'
8
9module.exports = class Hypervisor {
10 /**
11 * The Hypervisor manages the container instances by instantiating them and
12 * destorying them when possible. It also facilitates localating Containers
13 * @param {Graph} dag an instance of [ipfs.dag](https://github.com/ipfs/interface-ipfs-core/tree/master/API/dag#dag-api)
14 * @param {object} state - the starting state
15 */
16 constructor (dag, state = {}) {
17 this.graph = new Graph(dag)
18 this.scheduler = new Scheduler()
19 this.state = state
20 this._containerTypes = {}
21 this._nodesToCheck = new Set()
22 }
23
24 /**
25 * add a potaintail node in the state graph to check for garbage collection
26 * @param {string} id
27 */
28 addNodeToCheck (id) {
29 this._nodesToCheck.add(id)
30 }
31
32 /**
33 * given a port, this finds the corridsponeding endpoint port of the channel
34 * @param {object} port
35 * @returns {Promise}
36 */
37 getDestPort (port) {
38 if (port.destPort) {
39 return port.destPort
40 } else {
41 return this.graph.get(this.state, `${port.destId}/ports/${port.destName}`)
42 }
43 }
44
45 async send (port, message) {
46 if (port.destId) {
47 const id = port.destId
48 const instance = await this.getInstance(id)
49 return instance.queue(port.destName, message)
50 } else {
51 // port is unbound
52 port.destPort.messages.push(message)
53 }
54 }
55
56 // loads an instance of a container from the state
57 async _loadInstance (id) {
58 const state = await this.graph.get(this.state, id)
59 const container = this._containerTypes[state.type]
60
61 // create a new kernel instance
62 const kernel = new Kernel({
63 hypervisor: this,
64 state: state,
65 container: container,
66 id: id
67 })
68
69 // save the newly created instance
70 this.scheduler.update(kernel)
71 return kernel
72 }
73
74 // get a hash from a POJO
75 _getHashFromObj (obj) {
76 return this.graph.flush(obj).then(obj => obj['/'])
77 }
78
79 /**
80 * gets an existsing container instances
81 * @param {string} id - the containers ID
82 * @returns {Promise}
83 */
84 async getInstance (id) {
85 let instance = this.scheduler.getInstance(id)
86 if (instance) {
87 return instance
88 } else {
89 const resolve = this.scheduler.getLock(id)
90 const instance = await this._loadInstance(id)
91 resolve(instance)
92 return instance
93 }
94 }
95
96 /**
97 * creates an new container instances and save it in the state
98 * @param {string} type - the type of container to create
99 * @param {*} code
100 * @param {array} entryPorts
101 * @param {object} id
102 * @param {object} id.nonce
103 * @param {object} id.parent
104 * @returns {Promise}
105 */
106 async createInstance (type, message = new Message(), id = {nonce: 0, parent: null}) {
107 // create a lock to prevent the scheduler from reloving waits before the
108 // new container is loaded
109 const resolve = this.scheduler.getLock(id)
110 const idHash = await this._getHashFromObj(id)
111 // const code = message.data.byteLength ? message.data : undefined
112 const state = {
113 nonce: [0],
114 ports: {},
115 type: type
116 }
117
118 // save the container in the state
119 await this.graph.set(this.state, idHash, state)
120 // create the container instance
121 const instance = await this._loadInstance(idHash)
122 resolve(instance)
123 // send the intialization message
124 await instance.initialize(message)
125
126 return instance
127 }
128
129 /**
130 * creates a state root starting from a given container and a given number of
131 * ticks
132 * @param {Number} ticks the number of ticks at which to create the state root
133 * @returns {Promise}
134 */
135 async createStateRoot (ticks) {
136 await this.scheduler.wait(ticks)
137 const unlinked = await DFSchecker(this.graph, this.state, ROOT_ID, this._nodesToCheck)
138 unlinked.forEach(id => {
139 delete this.state[id]
140 })
141 return this.graph.flush(this.state)
142 }
143
144 /**
145 * regirsters a container with the hypervisor
146 * @param {String} type - the name of the type
147 * @param {Class} Constructor - a Class for instantiating the container
148 * @param {*} args - any args that the contructor takes
149 */
150 registerContainer (type, Constructor, args) {
151 Constructor.type = type
152 this._containerTypes[type] = {
153 Constructor: Constructor,
154 args: args
155 }
156 }
157}
158

Built with git-ssb-web