git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: c5cdc89599c7a0c7c34af77912e1b919bf4cbf26

Files: c5cdc89599c7a0c7c34af77912e1b919bf4cbf26 / portManager.js

3203 bytesRaw
1const Port = require('./port.js')
2const BN = require('bn.js')
3const ENTRY = Symbol('entry')
4
5// decides which message to go first
6function messageArbiter (pairA, pairB) {
7 const portA = pairA[1]
8 const portB = pairB[1]
9 const a = portA.peek()
10 const b = portB.peek()
11
12 if (!a) {
13 return pairB
14 } else if (!b) {
15 return pairA
16 }
17
18 // order by number of ticks if messages have different number of ticks
19 if (a._fromPortTicks !== b._fromPortTicks) {
20 return a._fromPortTicks < b._fromPortTicks ? pairA : pairB
21 } else if (a.priority !== b.priority) {
22 // decide by priority
23 return a.priority > b.priority ? pairA : pairB
24 } else if (portA.name === ENTRY) {
25 // pairB can never be the entry port since the port map is odered by
26 // insertion order
27 return pairA
28 } else {
29 return portA.name < portB.name ? pairA : pairB
30 }
31}
32
33module.exports = class PortManager {
34 constructor (opts) {
35 Object.assign(this, opts)
36 this._portMap = new Map()
37 }
38
39 async start () {
40 // skip the root, since it doesn't have a parent
41 if (this.parentPort !== undefined) {
42 this._bindRef(this.parentPort, ENTRY)
43 }
44 // map ports to thier id's
45 this.ports = await this.hypervisor.graph.get(this.state, 'ports')
46 Object.keys(this.ports).map(name => {
47 const port = this.ports[name]
48 this._bindRef(port, name)
49 })
50 }
51
52 _bindRef (portRef, name) {
53 const port = new Port(name)
54 this._portMap.set(portRef, port)
55 }
56
57 bind (port, name) {
58 // save the port instance
59 this.ports[name] = port
60 this._bindRef(port, name)
61 }
62
63 queue (message) {
64 this._portMap.get(message.fromPort).queue(message)
65 }
66
67 get (key) {
68 return this.ports[key]
69 }
70
71 delete (key) {
72 const port = this.ports[key]
73 delete this.ports[key]
74 this._portMap.delete(port)
75 }
76
77 isValidPort (port) {
78 return this._portMap.has(port)
79 }
80
81 create (type) {
82 const VM = this.hypervisor._containerTypes[type]
83 const parentId = this.entryPort ? this.entryPort.id : null
84 let nonce = this.state['/'].nonce
85
86 const portRef = {
87 'messages': [],
88 'id': {
89 '/': {
90 nonce: nonce,
91 parent: parentId
92 }
93 },
94 'type': type,
95 'link': {
96 '/': VM.createState()
97 }
98 }
99
100 // incerment the nonce
101 nonce = new BN(nonce)
102 nonce.iaddn(1)
103 this.state['/'].nonce = nonce.toArray()
104 return portRef
105 }
106
107 // waits till all ports have reached a threshold tick count
108 wait (threshold, fromPort) {
109 // find the ports that have a smaller tick count then the threshold tick count
110 const unkownPorts = [...this._portMap].filter(([portRef, port]) => {
111 return port.ticks < threshold && fromPort !== portRef
112 })
113
114 const promises = unkownPorts.map(async ([portRef, port]) => {
115 // update the port's tick count
116 port.ticks = await this.hypervisor.wait(portRef, threshold, this.entryPort)
117 })
118
119 return Promise.all(promises)
120 }
121
122 async getNextMessage () {
123 if (this._portMap.size) {
124 await this.wait(this.kernel.ticks, this.entryPort)
125 const portMap = [...this._portMap].reduce(messageArbiter)
126 return portMap[1].shift()
127 }
128 }
129}
130

Built with git-ssb-web