git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 59e5c5ee7cd9ec4372da75fa9427c4f06b0a6806

Files: 59e5c5ee7cd9ec4372da75fa9427c4f06b0a6806 / index.js

4688 bytesRaw
1const Tree = require('merkle-radix-tree')
2const Graph = require('ipld-graph-builder')
3const Kernel = require('./kernel.js')
4const Scheduler = require('./scheduler.js')
5const DFSchecker = require('./dfsChecker.js')
6const CreationService = require('./creationService.js')
7
8const CREATION_ID = 0
9// const ROUTING_ID = 1
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 = {'/': Tree.emptyTreeState}) {
19 this.graph = new Graph(dag)
20 this.tree = new Tree({
21 graph: this.graph,
22 root: state
23 })
24 this.scheduler = new Scheduler()
25 this.state = state
26 this._containerTypes = {}
27 this._nodesToCheck = new Set()
28
29 this.creationService = new CreationService({
30 hypervisor: this
31 })
32 this.scheduler.systemServices.set(CREATION_ID, this.creationService)
33
34 this.ROOT_ID = 'zdpuAm6aTdLVMUuiZypxkwtA7sKm7BWERy8MPbaCrFsmiyzxr'
35 }
36
37 /**
38 * add a potaintail node in the state graph to check for garbage collection
39 * @param {string} id
40 */
41 addNodeToCheck (id) {
42 this._nodesToCheck.add(id)
43 }
44
45 /**
46 * given a port, this finds the corridsponeding endpoint port of the channel
47 * @param {object} port
48 * @returns {Promise}
49 */
50 async getDestPort (port) {
51 if (port.destPort) {
52 return port.destPort
53 } else {
54 const instance = await this.scheduler.getInstance(port.destId)
55 let containerState
56 if (instance) {
57 containerState = instance.state
58 } else {
59 containerState = await this.tree.get(port.destId)
60 }
61 return this.graph.get(containerState, `ports/${port.destName}`)
62 }
63 }
64
65 async send (port, message) {
66 const id = port.destId
67 if (id !== undefined) {
68 const instance = await this.getInstance(id)
69 return instance.queue(port, message)
70 } else {
71 // port is unbound
72 port.destPort.messages.push(message)
73 }
74 }
75
76 // loads an instance of a container from the state
77 async _loadInstance (id, state) {
78 if (!state) {
79 state = await this.tree.get(id)
80 }
81 const container = this._containerTypes[state.type]
82 let code
83
84 // checks if the code stored in the state is an array and that the elements
85 // are merkle link
86 if (state.code && state.code[0]['/']) {
87 await this.graph.tree(state.code, 1)
88 code = state.code.map(a => a['/']).reduce((a, b) => a + b)
89 } else {
90 code = state.code
91 }
92
93 // create a new kernel instance
94 const kernel = new Kernel({
95 hypervisor: this,
96 state: state,
97 code: code,
98 container: container,
99 id: id
100 })
101
102 // save the newly created instance
103 this.scheduler.update(kernel)
104 return kernel
105 }
106
107 /**
108 * gets an existsing container instances
109 * @param {string} id - the containers ID
110 * @returns {Promise}
111 */
112 async getInstance (id) {
113 let instance = this.scheduler.getInstance(id)
114 if (instance) {
115 return instance
116 } else {
117 const resolve = this.scheduler.lock(id)
118 const instance = await this._loadInstance(id)
119 await instance.startup()
120 resolve(instance)
121 return instance
122 }
123 }
124
125 createInstance (message, id) {
126 return this.creationService.createInstance(message, id)
127 }
128
129 createChannel () {
130 const port1 = {
131 messages: []
132 }
133
134 const port2 = {
135 messages: [],
136 destPort: port1
137 }
138
139 port1.destPort = port2
140 return [port1, port2]
141 }
142
143 /**
144 * creates a state root starting from a given container and a given number of
145 * ticks
146 * @param {Number} ticks the number of ticks at which to create the state root
147 * @returns {Promise}
148 */
149 async createStateRoot (ticks) {
150 await this.scheduler.wait(ticks)
151
152 const unlinked = await DFSchecker(this.tree, this._nodesToCheck, (id) => {
153 return this.ROOT_ID === id
154 })
155 for (const id of unlinked) {
156 await this.tree.delete(id)
157 }
158 return this.graph.flush(this.state)
159 }
160
161 /**
162 * regirsters a container with the hypervisor
163 * @param {Class} Constructor - a Class for instantiating the container
164 * @param {*} args - any args that the contructor takes
165 * @param {interger} typeId - the container's type identification ID
166 */
167 registerContainer (Constructor, args, typeId = Constructor.typeId) {
168 this._containerTypes[typeId] = {
169 Constructor: Constructor,
170 args: args
171 }
172 }
173}
174

Built with git-ssb-web