git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: cd25165f33c14d34c9ec8f487af17959f29ed06d

Files: cd25165f33c14d34c9ec8f487af17959f29ed06d / index.js

4531 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 code: code
117 }
118
119 // save the container in the state
120 await this.graph.set(this.state, idHash, state)
121 // create the container instance
122 const instance = await this._loadInstance(idHash)
123 resolve(instance)
124 // send the intialization message
125 await instance.initialize(message)
126
127 return instance
128 }
129
130 /**
131 * creates a state root starting from a given container and a given number of
132 * ticks
133 * @param {Number} ticks the number of ticks at which to create the state root
134 * @returns {Promise}
135 */
136 async createStateRoot (ticks) {
137 await this.scheduler.wait(ticks)
138 const unlinked = await DFSchecker(this.graph, this.state, ROOT_ID, this._nodesToCheck)
139 unlinked.forEach(id => {
140 delete this.state[id]
141 })
142 return this.graph.flush(this.state)
143 }
144
145 /**
146 * regirsters a container with the hypervisor
147 * @param {String} type - the name of the type
148 * @param {Class} Constructor - a Class for instantiating the container
149 * @param {*} args - any args that the contructor takes
150 */
151 registerContainer (type, Constructor, args) {
152 this._containerTypes[type] = {
153 Constructor: Constructor,
154 args: args
155 }
156 }
157}
158

Built with git-ssb-web