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 }