Hyper-P2P Module Tests / unit-all (push) Failing after 1h16m23s
Origin hybrid weighted select, latency path stats, live-edge listing; topic channel batch publish and retained clear; wakeup reschedule and cancelAll; electron bridge handler registry helpers. Co-authored-by: Cursor <[email protected]>
98 lines
2.5 KiB
JavaScript
98 lines
2.5 KiB
JavaScript
require('bare-process/global')
|
|
const EventEmitter = require('bare-events')
|
|
const { assertStreamId, mediaStats } = require('../../_shared/media-streaming-base.js')
|
|
|
|
const PROTOCOL = 'origin-hybrid-bridge/v1'
|
|
|
|
class HyperP2POriginHybridBridge extends EventEmitter {
|
|
constructor (opts = {}) {
|
|
super()
|
|
this._origins = new Map()
|
|
this._stats = { originBytes: 0, p2pBytes: 0 }
|
|
}
|
|
|
|
registerOrigin (streamId, url, weight = 1) {
|
|
const sid = assertStreamId(streamId)
|
|
if (!url) throw new Error('url required')
|
|
const list = this._origins.get(sid) || []
|
|
list.push({ url: String(url), weight: Math.max(0, weight), at: Date.now() })
|
|
list.sort((a, b) => b.weight - a.weight)
|
|
this._origins.set(sid, list)
|
|
return list[0]
|
|
}
|
|
|
|
selectOrigin (streamId) {
|
|
const list = this._origins.get(assertStreamId(streamId))
|
|
return list && list.length ? list[0] : null
|
|
}
|
|
|
|
recordPull (bytes, via = 'origin') {
|
|
const n = Math.max(0, bytes | 0)
|
|
if (via === 'p2p') this._stats.p2pBytes += n
|
|
else this._stats.originBytes += n
|
|
this.emit('pull', { bytes: n, via })
|
|
return n
|
|
}
|
|
|
|
p2pOffloadRatio () {
|
|
const total = this._stats.originBytes + this._stats.p2pBytes
|
|
if (!total) return 0
|
|
return this._stats.p2pBytes / total
|
|
}
|
|
|
|
shouldFallbackP2P (coverage) {
|
|
return coverage < 0.85
|
|
}
|
|
|
|
listOrigins (streamId) {
|
|
return [...(this._origins.get(assertStreamId(streamId)) || [])]
|
|
}
|
|
|
|
removeOrigin (streamId, url) {
|
|
const sid = assertStreamId(streamId)
|
|
const list = this._origins.get(sid)
|
|
if (!list) return false
|
|
const idx = list.findIndex((o) => o.url === url)
|
|
if (idx < 0) return false
|
|
list.splice(idx, 1)
|
|
if (!list.length) this._origins.delete(sid)
|
|
return true
|
|
}
|
|
|
|
listStreamIds () {
|
|
return [...this._origins.keys()]
|
|
}
|
|
|
|
weightedSelect (streamId) {
|
|
const list = this._origins.get(assertStreamId(streamId))
|
|
if (!list || !list.length) return null
|
|
const total = list.reduce((s, o) => s + o.weight, 0)
|
|
let r = Math.random() * total
|
|
for (const o of list) {
|
|
r -= o.weight
|
|
if (r <= 0) return o
|
|
}
|
|
return list[0]
|
|
}
|
|
|
|
totalBytes () {
|
|
return this._stats.originBytes + this._stats.p2pBytes
|
|
}
|
|
|
|
getStats () {
|
|
return mediaStats(this._stats, PROTOCOL, {
|
|
offloadRatio: this.p2pOffloadRatio(),
|
|
streams: this._origins.size
|
|
})
|
|
}
|
|
|
|
async ready () { return this }
|
|
|
|
async close () {
|
|
this._origins.clear()
|
|
this.emit('closed')
|
|
}
|
|
}
|
|
|
|
module.exports = { HyperP2POriginHybridBridge, PROTOCOL }
|