git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 8ced6c46cc8f744d128a65d00c117a79e68918b8

Files: 8ced6c46cc8f744d128a65d00c117a79e68918b8 / index.js

3096 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()
71 message.result().then(result => {
72 if (result.execption) {
73 revert()
74 } else {
75 this.runNextMessage(0)
76 }
77 })
78
79 if (message.hops === message.to.length) {
80 message._respond(result)
81 }
82 } else {
83 // non-atomic messages
84 this.runNextMessage(0)
85 }
86 return result
87 }
88
89 async send (message) {
90 let portName = message.nextPort()
91 // replace root with parent path to root
92 if (portName === common.ROOT) {
93 message.to.shift()
94 message.to = new Array(this.path.length).fill(common.PARENT).concat(message.to)
95 portName = common.PARENT
96 }
97 message.addVistedKernel(this)
98 this.lastMessage = message
99 // console.log(portName, message)
100 const port = await this.ports.get(portName)
101 // save the atomic messages for possible reverts
102 if (message.atomic) {
103 this._sentAtomicMessages.push(message)
104 }
105 port.send(message)
106 return message.result()
107 }
108
109 shutdown () {}
110}
111

Built with git-ssb-web