-
Notifications
You must be signed in to change notification settings - Fork 133
/
Copy pathmonitor.js
111 lines (91 loc) · 3.37 KB
/
monitor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
const ReadyResource = require('ready-resource')
const safetyCatch = require('safety-catch')
const speedometer = require('speedometer')
module.exports = class Monitor extends ReadyResource {
constructor (drive, opts = {}) {
super()
this.drive = drive
this.blobs = null
this.name = opts.name || null
this.entry = opts.entry || null
this._boundOnUpload = this._onUpload.bind(this)
this._boundOnDownload = this._onDownload.bind(this)
const stats = {
startTime: 0,
percentage: 0,
peers: 0,
speed: 0,
blocks: 0,
totalBytes: 0, // local + bytes loaded during monitoring
monitoringBytes: 0, // bytes loaded during monitoring
targetBytes: 0,
targetBlocks: 0
}
// Updated on each upload/download event
this.uploadStats = { ...stats }
this.downloadStats = { ...stats }
this.uploadSpeedometer = null
this.downloadSpeedometer = null
this.ready().catch(safetyCatch)
}
async _open () {
await this.drive.ready()
this.blobs = await this.drive.getBlobs()
if (!this.entry && this.name) this.entry = await this.drive.entry(this.name)
if (this.entry) this._setEntryInfo()
// Handlers
this.blobs.core.on('upload', this._boundOnUpload)
this.blobs.core.on('download', this._boundOnDownload)
}
async _close () {
this.blobs.core.off('upload', this._boundOnUpload)
this.blobs.core.off('download', this._boundOnDownload)
this.drive.monitors.delete(this)
}
_setEntryInfo () {
if (!this.downloadStats.targetBytes || !this.downloadStats.targetBlocks) {
this.downloadStats.targetBytes = this.entry.value.blob.byteLength
this.downloadStats.targetBlocks = this.entry.value.blob.blockLength
}
if (!this.uploadStats.targetBytes || !this.uploadStats.targetBlocks) {
this.uploadStats.targetBytes = this.entry.value.blob.byteLength
this.uploadStats.targetBlocks = this.entry.value.blob.blockLength
}
}
_onUpload (index, bytes, from) {
if (!this.uploadSpeedometer) this.uploadSpeedometer = speedometer()
this.uploadStats.speed = this.uploadSpeedometer(bytes)
this._updateStats(this.uploadStats, index, bytes, from)
}
_onDownload (index, bytes, from) {
if (!this.downloadSpeedometer) this.downloadSpeedometer = speedometer()
this.downloadStats.speed = this.downloadSpeedometer(bytes)
this._updateStats(this.downloadStats, index, bytes, from)
}
_updateStats (stats, index, bytes, from) {
if (!this.entry || this.closing) return
if (!isWithinRange(index, this.entry)) return
if (!stats.startTime) stats.startTime = Date.now()
stats.peers = from.replicator.peers.length
stats.blocks++
stats.monitoringBytes += bytes
stats.totalBytes += bytes
// NOTE: you should not rely on the percentage until the monitor is initialized with the local state of the file
stats.percentage = toFixed(stats.blocks / stats.targetBlocks * 100)
this.emit('update')
}
downloadSpeed () {
return this.downloadSpeedometer ? this.downloadSpeedometer() : 0
}
uploadSpeed () {
return this.uploadSpeedometer ? this.uploadSpeedometer() : 0
}
}
function isWithinRange (index, entry) {
if (!entry || !entry.value) return
const { blockOffset, blockLength } = entry.value.blob
return index >= blockOffset && index < blockOffset + blockLength
}
function toFixed (n) {
return Math.round(n * 100) / 100
}