@samitouri / QOSami-HFS / commits / 4fa8c0e6

fix: command "status" was displaying wrong speed

Massimo Melina committed Apr 16, 2026 at 14:21 UTC 4fa8c0e601739f0c238236dd08a0e583e36648e1
6 files changed +18 -21
admin/src/MonitorPage.ts
+4 -7
@@ -55,8 +55,8 @@ function MoreInfo() {
55 .then(yes => yes && apiCall('clear_persistent', { k: ['totalSent', 'totalGot'] })
56 .then(() => alertDialog("Done", 'success'), alertDialog))
57 }),
58 - pair('outSpeed', { label: "Output", render: formatSpeedK, minWidth: '8.5em' }),
59 - pair('inSpeed', { label: "Input", render: formatSpeedK, minWidth: '8.5em' }),
58 + pair('outSpeedKb', { label: "Output", render: formatSpeedK, minWidth: '8.5em' }),
59 + pair('inSpeedKb', { label: "Input", render: formatSpeedK, minWidth: '8.5em' }),
60 (allInfo || sm) && pair('ips', { label: "IPs", title: () => "Currently connected" }),
61 (md || allInfo && md || status?.http?.error) && pair('http', { label: "HTTP", render: port }),
62 (md || allInfo && md || status?.https?.error) && pair('https', { label: "HTTPS", render: port }),
@@ -221,15 +221,12 @@ function Connections() {
221 }
222 },
223 {
224 - field: 'outSpeed',
224 + field: 'outSpeedKb',
225 headerName: "Speed",
226 width: 110,
227 hideUnder: 'sm',
228 type: 'number',
229 - renderCell: ({
230 - value,
231 - row
232 - }) => formatSpeedK(Math.max(value || 0, row.inSpeed || 0) || undefined),
229 + renderCell: ({ value, row }) => formatSpeedK(Math.max(value || 0, row.inSpeedKb || 0) || undefined),
230 mergeRender: { sent: { fontSize: 'small', textAlign: 'right' } }
231 },
232 {
src/api.monitor.ts
+3 -3
@@ -5,7 +5,7 @@ import { Connection, disconnect, getConnections } from './connections'
5 import { apiAssertTypes, isLocalHost, safeDecodeURIComponent, shortenAgent, wait, wantArray } from './misc'
6 import { ApiHandlers } from './apiMiddleware'
7 import Koa from 'koa'
8 -import { totalGot, totalInSpeed, totalOutSpeed, totalSent } from './throttler'
8 +import { totalGot, totalInSpeedKb, totalOutSpeedKb, totalSent } from './throttler'
9 import { getCurrentUsername } from './auth'
10 import { SendListReadable } from './SendList'
11 import { storedMap } from './persistence'
@@ -94,8 +94,8 @@ export default {
94 while (1) {
95 const filtered = getConnections().filter(x => !ignore(x))
96 yield {
97 - outSpeed: totalOutSpeed,
98 - inSpeed: totalInSpeed,
97 + outSpeedKb: totalOutSpeedKb,
98 + inSpeedKb: totalInSpeedKb,
99 sent_got: [totalSent.get(), totalGot.get(), totalGotSentResetTime.get()] as const,
100 connections: filtered.length,
101 ips: _.uniqBy(filtered, x => x.ip).length,
src/commands.ts
+2 -2
@@ -200,8 +200,8 @@ const commands = {
200 const conn = (await apiMonitor.get_connection_stats().next()).value
201 if (conn) {
202 const {sent_got: sg} = conn
203 - console.log(`Speed ↑ ${formatSpeed(conn.outSpeed)} ↓ ${formatSpeed(conn.inSpeed)}`)
204 - console.log(`Transfered ↑ ${formatBytes(sg[0])} ↓ ${formatBytes(sg[1])} since ${formatTimestamp(sg[2])}`)
203 + console.log(`Speed ↑ ${formatSpeed(conn.outSpeedKb * 1000)} ↓ ${formatSpeed(conn.inSpeedKb * 1000)}`)
204 + console.log(`Transferred ↑ ${formatBytes(sg[0])} ↓ ${formatBytes(sg[1])} since ${formatTimestamp(sg[2])}`)
205 console.log(`Connections ${conn.connections} (${conn.ips} IPs)`)
206 }
207 }
src/connections.ts
+2 -2
@@ -10,8 +10,8 @@ export class Connection {
10 readonly started = new Date()
11 sent = 0 // socket-scoped, not request-scoped
12 got = 0
13 - outSpeed?: number
14 - inSpeed?: number
13 + outSpeedKb?: number
14 + inSpeedKb?: number
15 ctx?: Context // this is set externally, during koa middleware, using updateConnectionForCtx, but only for regular requests; some connections may never have a ctx
16 country?: string
17 private _cachedIp?: string
src/throttler.ts
+5 -5
@@ -56,7 +56,7 @@ export const throttler: Koa.Middleware = async (ctx, next) => {
56 const ts = conn[SymThrStr] as ThrottledStream
57 const outSpeed = roundSpeed(ts.getSpeed())
58 const { state } = ctx
59 - updateConnection(conn, { outSpeed, sent: conn.socket.bytesWritten },
59 + updateConnection(conn, { outSpeedKb: outSpeed, sent: conn.socket.bytesWritten },
60 { opProgress: state.opTotal && ((state.opOffset || 0) + (ts.getBytesSent() - offset) / state.opTotal) })
61 /* in case this stream stands still for a while (before the end), we'll have neither 'sent' or 'close' events,
62 * so who will take care to updateConnection? This artificial next-call will ensure just that */
@@ -100,8 +100,8 @@ export function roundSpeed(n: number) {
100
101 export const totalSent = storedMap.singleSync<number>('totalSent', 0)
102 export const totalGot = storedMap.singleSync<number>('totalGot', 0)
103 -export let totalOutSpeed = 0
104 -export let totalInSpeed = 0
103 +export let totalOutSpeedKb = 0
104 +export let totalInSpeedKb = 0
105
106 let lastSent: number | undefined
107 let lastGot: number | undefined
@@ -112,12 +112,12 @@ setInterval(() => {
112 last = now
113 {
114 const v = totalSent.get()
115 - totalOutSpeed = roundSpeed((v - (lastSent ?? v)) / past)
115 + totalOutSpeedKb = roundSpeed((v - (lastSent ?? v)) / past) // lastSent is bytes, past is milliseconds, so the result is KB/s
116 lastSent = v
117 }
118 {
119 const v = totalGot.get()
120 - totalInSpeed = roundSpeed((v - (lastGot ?? v)) / past)
120 + totalInSpeedKb = roundSpeed((v - (lastGot ?? v)) / past)
121 lastGot = v
122 }
123 }, 1000)
src/upload.ts
+2 -2
@@ -235,10 +235,10 @@ export function uploadWriter(base: VfsNode, baseUri: string, filename: string, c
235 const h = setInterval(() => {
236 const now = Date.now()
237 const got = bytesGot()
238 - const inSpeed = roundSpeed((got - lastGot) / (now - lastGotTime))
238 + const inSpeedKb = roundSpeed((got - lastGot) / (now - lastGotTime))
239 lastGot = got
240 lastGotTime = now
241 - updateConnection(conn, { inSpeed, got }, { opProgress: (resume + got) / fullSize })
241 + updateConnection(conn, { inSpeedKb, got }, { opProgress: (resume + got) / fullSize })
242 }, 1000)
243 const stopTracking = () => clearInterval(h)
244 writeStream.once('close', stopTracking)