git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 48df42c8ab634c0d9fc7597e52106352878124fa

Files: 48df42c8ab634c0d9fc7597e52106352878124fa / index.js

3012 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 this._vm = (opts.codeHandler || codeHandler).init(this.code)
20 this._state = 'idle'
21 this.ports.on('message', index => {
22 this.runNextMessage(index)
23 })
24 }
25
26 runNextMessage (index = 0) {
27 return this.ports.peek(index).then(message => {
28 if (message && (message.isCyclic(this) || this._state === 'idle')) {
29 this.ports.remove(index)
30 return this.run(message)
31 } else {
32 this._state = 'idle'
33 this.emit('idle')
34 }
35 })
36 }
37
38 /**
39 * run the kernels code with a given enviroment
40 * The Kernel Stores all of its state in the Environment. The Interface is used
41 * to by the VM to retrive infromation from the Environment.
42 */
43 async run (message, imports = this.imports) {
44 function revert () {
45 // revert the state
46 this.state.set([], oldState)
47 // revert all the sent messages
48 for (let msg in this._sentAtomicMessages) {
49 msg.revert()
50 }
51 this.runNextMessage(0)
52 }
53
54 const oldState = this.state.copy()
55 let result
56 this._state = 'running'
57 try {
58 result = await this._vm.run(message, this, imports) || {}
59 } catch (e) {
60 console.log(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._finish(result)
71 message.result().then(result => {
72 if (result.execption) {
73 revert()
74 } else {
75 this.runNextMessage(0)
76 }
77 })
78 } else {
79 // non-atomic messages
80 this.runNextMessage(0)
81 }
82 return result
83 }
84
85 async send (message) {
86 let portName = message.nextPort()
87 // replace root with parent path to root
88 if (portName === common.ROOT) {
89 message.to.shift()
90 message.to = new Array(this.path.length).fill(common.PARENT).concat(message.to)
91 portName = common.PARENT
92 }
93 message.addVistedKernel(this)
94 this.lastMessage = message
95 // console.log(portName, message)
96 const port = await this.ports.get(portName)
97 // save the atomic messages for possible reverts
98 if (message.atomic) {
99 this._sentAtomicMessages.push(message)
100 }
101 port.send(message)
102 return message.result()
103 }
104
105 shutdown () {}
106}
107

Built with git-ssb-web