git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: ea9456b0cd659d6f9a4f7a039e4207d594c292e4

Files: ea9456b0cd659d6f9a4f7a039e4207d594c292e4 / portManager.js

3224 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
45 // map ports to thier id's
46 this.ports = await this.hypervisor.graph.get(this.state, 'ports')
47 Object.keys(this.ports).map(name => {
48 const port = this.ports[name]
49 this._bindRef(port, name)
50 })
51 }
52
53 _bindRef (portRef, name) {
54 const port = new Port(name)
55 this._portMap.set(portRef, port)
56 }
57
58 bind (port, name) {
59 // save the port instance
60 this.ports[name] = port
61 this._bindRef(port, name)
62 }
63
64 queue (message) {
65 this._portMap.get(message.fromPort).queue(message)
66 }
67
68 get (key) {
69 return this.ports[key]
70 }
71
72 delete (key) {
73 const port = this.ports[key]
74 delete this.ports[key]
75 this._portMap.delete(port)
76 }
77
78 isValidPort (port) {
79 return this._portMap.has(port)
80 }
81
82 create (type) {
83 const Container = this.hypervisor._containerTypes[type]
84 const parentId = this.entryPort ? this.entryPort.id : null
85 let nonce = this.state['/'].nonce
86
87 const portRef = {
88 'messages': [],
89 'id': {
90 '/': {
91 nonce: nonce,
92 parent: parentId
93 }
94 },
95 'type': type,
96 'link': {
97 '/': Container.createState()
98 }
99 }
100
101 // incerment the nonce
102 nonce = new BN(nonce)
103 nonce.iaddn(1)
104 this.state['/'].nonce = nonce.toArray()
105 return portRef
106 }
107
108 // waits till all ports have reached a threshold tick count
109 wait (threshold, fromPort) {
110 // find the ports that have a smaller tick count then the threshold tick count
111 const unkownPorts = [...this._portMap].filter(([portRef, port]) => {
112 return port.ticks < threshold && fromPort !== portRef
113 })
114
115 const promises = unkownPorts.map(async ([portRef, port]) => {
116 // update the port's tick count
117 port.ticks = await this.hypervisor.wait(portRef, threshold, this.entryPort)
118 })
119
120 return Promise.all(promises)
121 }
122
123 async getNextMessage () {
124 if (this._portMap.size) {
125 await this.wait(this.exoInterface.ticks, this.entryPort)
126 const portMap = [...this._portMap].reduce(messageArbiter)
127 return portMap[1].shift()
128 }
129 }
130}
131

Built with git-ssb-web