Files: d9ab14281e683bbcd8f54b5cb7874edbbdd088a7 / index.js
2595 bytesRaw
1 | const EventEmitter = require('events') |
2 | const Vertex = require('merkle-trie') |
3 | const PortManager = require('./portManager.js') |
4 | const imports = require('./EVMinterface.js') |
5 | const codeHandler = require('./codeHandler.js') |
6 | const common = require('./common.js') |
7 | |
8 | module.exports = class Kernel extends EventEmitter { |
9 | constructor (opts = {}) { |
10 | super() |
11 | const state = this.state = opts.state || new Vertex() |
12 | this.code = opts.code || state.value |
13 | this.path = state.path |
14 | this.imports = opts.imports || [imports] |
15 | this.ports = new PortManager(state, opts.parent, Kernel) |
16 | // rename sandbox? |
17 | this._vm = (opts.codeHandler || codeHandler).init(this.code) |
18 | this._state = 'idle' |
19 | this.ports.on('message', message => { |
20 | // was this kernel already visted? |
21 | if (message.isCyclic(this) || this._state === 'idle') { |
22 | this.run(message) |
23 | } |
24 | }) |
25 | } |
26 | |
27 | runNextMessage () { |
28 | this.ports.dequeue().then(message => { |
29 | if (message) { |
30 | 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 | this._state = 'running' |
45 | const oldState = this.state.copy() |
46 | const result = await this._vm.run(message, this, imports) || {} |
47 | |
48 | function revert () { |
49 | // revert the state |
50 | this.state.set([], oldState) |
51 | // revert all the sent messages |
52 | this.ports.outbox.revert() |
53 | this.runNextMessage() |
54 | } |
55 | |
56 | if (result.execption) { |
57 | // failed messages |
58 | revert() |
59 | } else if (message.atomic) { |
60 | // messages |
61 | message.finished().then(this.runNextMessage).catch(revert) |
62 | } else { |
63 | // non-atomic messages |
64 | this.runNextMessage() |
65 | } |
66 | return result |
67 | } |
68 | |
69 | async send (message) { |
70 | let portName = message.nextPort() |
71 | message.addVistedKernel(message) |
72 | this.lastMessage = message |
73 | // replace root with parent path to root |
74 | if (portName === common.ROOT) { |
75 | portName = common.PARENT |
76 | message.to = new Array(this.path.length).fill(common.PARENT).concat(message.to) |
77 | } |
78 | const port = await this.ports.get(portName) |
79 | return port.send(message) |
80 | } |
81 | |
82 | setValue (name, value) { |
83 | this.state.set(name, value) |
84 | } |
85 | |
86 | getValue (name) { |
87 | return this.state.get(name) |
88 | } |
89 | |
90 | deleteValue (name) { |
91 | return this.state.del(name) |
92 | } |
93 | |
94 | // remove from cache |
95 | shutdown () {} |
96 | } |
97 |
Built with git-ssb-web