Commit 158d5b428af69e19901680edef92ece0a876a97c
add drivers
wanderer committed on 3/21/2018, 11:27:12 PMParent: 8cd3e3af7c391f083f5f83593a260f831c7083af
Files changed
index.js | changed |
scheduler.js | changed |
systemObjects.js | changed |
tests/index.js | changed |
wasmContainer.js | changed |
egressDriver.js | added |
index.js | ||
---|---|---|
@@ -1,25 +1,26 @@ | ||
1 | +const crypto = require('crypto') | |
1 | 2 | const Actor = require('./actor.js') |
2 | 3 | const Scheduler = require('./scheduler.js') |
3 | 4 | const {ID} = require('./systemObjects.js') |
4 | -const crypto = require('crypto') | |
5 | 5 | |
6 | 6 | module.exports = class Hypervisor { |
7 | 7 | /** |
8 | 8 | * The Hypervisor manages the container instances by instantiating them and |
9 | 9 | * destorying them when possible. It also facilitates localating Containers |
10 | 10 | * @param {Tree} tree - a [radix tree](https://github.com/dfinity/js-dfinity-radix-tree) to store the state |
11 | 11 | */ |
12 | - constructor (tree, nonce = 0) { | |
12 | + constructor (tree, containers = [], drivers = [], nonce = 0) { | |
13 | 13 | this.tree = tree |
14 | 14 | this.scheduler = new Scheduler(this) |
15 | 15 | this._containerTypes = {} |
16 | 16 | this.nonce = nonce |
17 | + containers.forEach(container => this.registerContainer(container)) | |
18 | + drivers.forEach(driver => this.registerDriver(driver)) | |
17 | 19 | } |
18 | 20 | |
19 | 21 | /** |
20 | 22 | * sends a message |
21 | - * @param {Object} cap - the capabilitly used to send the message | |
22 | 23 | * @param {Object} message - the [message](https://github.com/primea/js-primea-message) to send |
23 | 24 | * @returns {Promise} a promise that resolves once the receiving container is loaded |
24 | 25 | */ |
25 | 26 | send (messages) { |
@@ -119,8 +120,12 @@ | ||
119 | 120 | */ |
120 | 121 | registerContainer (Constructor) { |
121 | 122 | this._containerTypes[Constructor.typeId] = Constructor |
122 | 123 | } |
124 | + | |
125 | + registerDriver (driver) { | |
126 | + this.scheduler.drivers.set(driver.id.id.toString('hex'), driver) | |
127 | + } | |
123 | 128 | } |
124 | 129 | |
125 | 130 | function encodedID (id) { |
126 | 131 | const nonce = Buffer.from([id.nonce]) |
scheduler.js | ||
---|---|---|
@@ -21,8 +21,9 @@ | ||
21 | 21 | this.hypervisor = hypervisor |
22 | 22 | this._messages = [] |
23 | 23 | this._times = [] |
24 | 24 | this.actors = new Map() |
25 | + this.drivers = new Map() | |
25 | 26 | this._running = false |
26 | 27 | } |
27 | 28 | |
28 | 29 | queue (messages) { |
@@ -47,9 +48,9 @@ | ||
47 | 48 | } |
48 | 49 | |
49 | 50 | async _processMessage (message) { |
50 | 51 | const to = message.funcRef.destId.id.toString('hex') |
51 | - let actor = this.actors.get(to) | |
52 | + let actor = this.actors.get(to) || this.drivers.get(to) | |
52 | 53 | if (!actor) { |
53 | 54 | actor = await this.hypervisor.loadActor(message.funcRef.destId) |
54 | 55 | this.actors.set(to, actor) |
55 | 56 | } |
systemObjects.js | ||
---|---|---|
@@ -19,9 +19,9 @@ | ||
19 | 19 | const decoder = new cbor.Decoder({ |
20 | 20 | tags: { |
21 | 21 | [TAGS.id]: val => new ID(val), |
22 | 22 | [TAGS.func]: val => new FunctionRef(...val), |
23 | - [TAGS.mod]: val => new ModuleRef(...val), | |
23 | + [TAGS.mod]: val => new ModuleRef(...val) | |
24 | 24 | } |
25 | 25 | }) |
26 | 26 | |
27 | 27 | class Serializable { |
@@ -36,17 +36,18 @@ | ||
36 | 36 | } |
37 | 37 | } |
38 | 38 | |
39 | 39 | class FunctionRef extends Serializable { |
40 | - constructor (privateFunc, identifier, params, id, gas=0) { | |
40 | + constructor (opts) { | |
41 | 41 | super() |
42 | - this.private = privateFunc | |
43 | - this.identifier = identifier | |
44 | - if (!(id instanceof ID)) | |
45 | - id = new ID(id) | |
46 | - this.destId = id | |
47 | - this.params = params | |
48 | - this.gas = gas | |
42 | + this.private = opts.private | |
43 | + this.identifier = opts.identifier | |
44 | + if (!(opts.id instanceof ID)) { | |
45 | + opts.id = new ID(opts.id) | |
46 | + } | |
47 | + this.destId = opts.id | |
48 | + this.params = opts.params | |
49 | + this.gas = opts.gas | |
49 | 50 | } |
50 | 51 | |
51 | 52 | encodeCBOR (gen) { |
52 | 53 | return gen.write(new cbor.Tagged(TAGS.func, [ |
@@ -69,9 +70,14 @@ | ||
69 | 70 | this.id = id |
70 | 71 | } |
71 | 72 | |
72 | 73 | getFuncRef (name) { |
73 | - return new FunctionRef(false, name, this.exports[name], this.id) | |
74 | + return new FunctionRef({ | |
75 | + private: false, | |
76 | + identifier: name, | |
77 | + params: this.exports[name], | |
78 | + id: this.id | |
79 | + }) | |
74 | 80 | } |
75 | 81 | |
76 | 82 | encodeCBOR (gen) { |
77 | 83 | return gen.write(new cbor.Tagged(TAGS.mod, [this.exports, this.id])) |
tests/index.js | ||
---|---|---|
@@ -1,9 +1,11 @@ | ||
1 | 1 | const tape = require('tape') |
2 | 2 | const Message = require('../message.js') |
3 | 3 | const Hypervisor = require('../') |
4 | +const {FunctionRef} = require('../systemObjects') | |
4 | 5 | |
5 | 6 | const level = require('level-browserify') |
7 | +const EgressDriver = require('../egressDriver') | |
6 | 8 | const RadixTree = require('dfinity-radix-tree') |
7 | 9 | const db = level('./testdb') |
8 | 10 | |
9 | 11 | class BaseContainer { |
@@ -44,11 +46,9 @@ | ||
44 | 46 | t.equals(m, 1, 'should recive a message') |
45 | 47 | } |
46 | 48 | } |
47 | 49 | |
48 | - const hypervisor = new Hypervisor(tree) | |
49 | - hypervisor.registerContainer(testVMContainer) | |
50 | - | |
50 | + const hypervisor = new Hypervisor(tree, [testVMContainer]) | |
51 | 51 | const {module} = hypervisor.createActor(testVMContainer.typeId) |
52 | 52 | |
53 | 53 | const message = new Message({ |
54 | 54 | funcRef: module.main, |
@@ -89,11 +89,9 @@ | ||
89 | 89 | return 8 |
90 | 90 | } |
91 | 91 | } |
92 | 92 | |
93 | - const hypervisor = new Hypervisor(tree) | |
94 | - hypervisor.registerContainer(testVMContainerA) | |
95 | - hypervisor.registerContainer(testVMContainerB) | |
93 | + const hypervisor = new Hypervisor(tree, [testVMContainerA, testVMContainerB]) | |
96 | 94 | |
97 | 95 | const {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId) |
98 | 96 | const {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId) |
99 | 97 | |
@@ -137,11 +135,9 @@ | ||
137 | 135 | return 8 |
138 | 136 | } |
139 | 137 | } |
140 | 138 | |
141 | - const hypervisor = new Hypervisor(tree) | |
142 | - hypervisor.registerContainer(testVMContainerA) | |
143 | - hypervisor.registerContainer(testVMContainerB) | |
139 | + const hypervisor = new Hypervisor(tree, [testVMContainerA, testVMContainerB]) | |
144 | 140 | |
145 | 141 | let {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId) |
146 | 142 | let {module: moduleA0} = hypervisor.createActor(testVMContainerA.typeId) |
147 | 143 | let {module: moduleA1} = hypervisor.createActor(testVMContainerA.typeId) |
@@ -193,11 +189,9 @@ | ||
193 | 189 | return 8 |
194 | 190 | } |
195 | 191 | } |
196 | 192 | |
197 | - const hypervisor = new Hypervisor(tree) | |
198 | - hypervisor.registerContainer(testVMContainerA) | |
199 | - hypervisor.registerContainer(testVMContainerB) | |
193 | + const hypervisor = new Hypervisor(tree, [testVMContainerA, testVMContainerB]) | |
200 | 194 | |
201 | 195 | let actorB = hypervisor.createActor(testVMContainerB.typeId) |
202 | 196 | let actorA0 = hypervisor.createActor(testVMContainerA.typeId) |
203 | 197 | let actorA1 = hypervisor.createActor(testVMContainerA.typeId) |
@@ -511,8 +505,40 @@ | ||
511 | 505 | const stateRoot = await hypervisor.createStateRoot() |
512 | 506 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
513 | 507 | }) |
514 | 508 | |
509 | +tape('driver', async t => { | |
510 | + const tree = new RadixTree({ | |
511 | + db | |
512 | + }) | |
513 | + | |
514 | + const egress = new EgressDriver() | |
515 | + | |
516 | + egress.on('message', msg => { | |
517 | + t.equals(msg.funcArguments[0], 'hello') | |
518 | + t.end() | |
519 | + }) | |
520 | + | |
521 | + class testVMContainer extends BaseContainer { | |
522 | + main (funcRef) { | |
523 | + this.actor.send(new Message({ | |
524 | + funcRef, | |
525 | + funcArguments: ['hello'] | |
526 | + })) | |
527 | + } | |
528 | + } | |
529 | + | |
530 | + const hypervisor = new Hypervisor(tree, [testVMContainer], [egress]) | |
531 | + const {module} = hypervisor.createActor(testVMContainer.typeId) | |
532 | + | |
533 | + const message = new Message({ | |
534 | + funcRef: module.main, | |
535 | + funcArguments: [new FunctionRef({id: egress.id})] | |
536 | + }) | |
537 | + | |
538 | + hypervisor.send(message) | |
539 | +}) | |
540 | + | |
515 | 541 | tape('random', async t => { |
516 | 542 | const numOfActors = 10 |
517 | 543 | const depth = 10 |
518 | 544 | const messageOrder = {} |
wasmContainer.js | ||
---|---|---|
@@ -30,10 +30,8 @@ | ||
30 | 30 | } |
31 | 31 | const message = new Message({ |
32 | 32 | funcRef: self, |
33 | 33 | funcArguments: checkedArgs |
34 | - }).on('execution:error', e => { | |
35 | - console.log(e) | |
36 | 34 | }) |
37 | 35 | container.actor.send(message) |
38 | 36 | } |
39 | 37 | } |
@@ -90,9 +88,14 @@ | ||
90 | 88 | // externalize a pervously internalized function |
91 | 89 | return self.refs.add(object) |
92 | 90 | } else { |
93 | 91 | const params = self.json.types[self.json.indexes[func.name - FUNC_INDEX_OFFSET]].params |
94 | - const ref = new FunctionRef(true, func.tableIndex, params, self.actor.id) | |
92 | + const ref = new FunctionRef({ | |
93 | + private: true, | |
94 | + identifier: func.tableIndex, | |
95 | + params, | |
96 | + id: self.actor.id | |
97 | + }) | |
95 | 98 | return self.refs.add(ref, 'func') |
96 | 99 | } |
97 | 100 | }, |
98 | 101 | internalize: (index, ref) => { |
@@ -123,9 +126,8 @@ | ||
123 | 126 | unwrap: async (ref, cb) => { |
124 | 127 | const obj = this.refs.get(ref, 'link') |
125 | 128 | const promise = this.actor.tree.dataStore.get(obj) |
126 | 129 | await this._opsQueue.push(promise) |
127 | - // todo | |
128 | 130 | } |
129 | 131 | }, |
130 | 132 | module: { |
131 | 133 | new: dataRef => { |
egressDriver.js | ||
---|---|---|
@@ -1,0 +1,13 @@ | ||
1 | +const {ID} = require('./systemObjects') | |
2 | +const EventEmitter = require('events') | |
3 | + | |
4 | +module.exports = class Egress extends EventEmitter { | |
5 | + constructor () { | |
6 | + super() | |
7 | + this.id = new ID(Buffer.from([0])) | |
8 | + } | |
9 | + | |
10 | + runMessage (message) { | |
11 | + this.emit('message', message) | |
12 | + } | |
13 | +} |
Built with git-ssb-web