git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: c091abb0870d405499f6c16a44b7e83135f443d2

Files: c091abb0870d405499f6c16a44b7e83135f443d2 / portManager.js

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

Built with git-ssb-web