git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: e08047273f81b45b7107bc0bc4fa2557d9f79eb0

Files: e08047273f81b45b7107bc0bc4fa2557d9f79eb0 / index.js

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

Built with git-ssb-web