git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 0f4618d69a1944599b2e15d8398df11ca4901eaa

Files: 0f4618d69a1944599b2e15d8398df11ca4901eaa / index.js

2883 bytesRaw
1const EventEmitter = require('events')
2const Vertex = require('merkle-trie')
3const PortManager = require('./portManager.js')
4const StateInterface = require('./stateInterface.js')
5const imports = require('./EVMinterface.js')
6const codeHandler = require('./codeHandler.js')
7const common = require('./common.js')
8
9module.exports = class Kernel extends EventEmitter {
10 constructor (opts = {}) {
11 super()
12 const state = this.state = opts.state || new Vertex()
13 this.stateInterface = new StateInterface(state)
14 this.code = opts.code || state.value
15 this.path = state.path
16 this.imports = opts.imports || [imports]
17 this.ports = new PortManager(state, opts.parent, Kernel)
18 this._sentAtomicMessages = []
19 // rename sandbox?
20 this._vm = (opts.codeHandler || codeHandler).init(this.code)
21 this._state = 'idle'
22 this.ports.on('message', index => {
23 this.runNextMessage(index)
24 })
25 }
26
27 runNextMessage (index = 0) {
28 this.ports.peek(index).then(message => {
29 if (message && (message.isCyclic(this) || this._state === 'idle')) {
30 this.ports.remove(index)
31 this.run(message)
32 } else {
33 this._state = 'idle'
34 this.emit('idle')
35 }
36 })
37 }
38
39 /**
40 * run the kernels code with a given enviroment
41 * The Kernel Stores all of its state in the Environment. The Interface is used
42 * to by the VM to retrive infromation from the Environment.
43 */
44 async run (message, imports = this.imports) {
45 function revert () {
46 // revert the state
47 this.state.set([], oldState)
48 // revert all the sent messages
49 for (let msg in this._sentAtomicMessages) {
50 msg.revert()
51 }
52 this.runNextMessage(0)
53 }
54
55 const oldState = this.state.copy()
56 let result
57 this._state = 'running'
58 try {
59 result = await this._vm.run(message, this, imports) || {}
60 } catch (e) {
61 result = {
62 exception: true
63 }
64 }
65 if (result.execption) {
66 // failed messages
67 revert()
68 } else if (message.atomic) {
69 // messages
70 message.finished().then(vmError => {
71 if (vmError) {
72 revert()
73 } else {
74 this.runNextMessage(0)
75 }
76 })
77 } else {
78 // non-atomic messages
79 this.runNextMessage(0)
80 }
81 return result
82 }
83
84 async send (message) {
85 let portName = message.nextPort()
86 message.addVistedKernel(message)
87 this.lastMessage = message
88 // replace root with parent path to root
89 if (portName === common.ROOT) {
90 portName = common.PARENT
91 message.to = new Array(this.path.length).fill(common.PARENT).concat(message.to)
92 }
93 const port = await this.ports.get(portName)
94 // save the atomic messages for possible reverts
95 if (message.atomic) {
96 this._sentAtomicMessages.push(message)
97 }
98 return port.send(message)
99 }
100
101 shutdown () {}
102}
103

Built with git-ssb-web