@samitouri / QOSami-HFS / commits / 5c0156ba

fix: admin/monitor: inconsistent progress

Massimo Melina committed Jul 12, 2023 at 00:30 UTC 5c0156bae38f06c9e721ea0becdf495e2bc6768e
6 files changed +11 -9
admin/src/MonitorPage.ts
+1 -1
@@ -146,7 +146,7 @@ function Connections() {
146 return h(Fragment, {},
147 row.op && h(IconProgress, {
148 icon: row.op === 'upload' ? Upload : Download,
149 - progress: row.opProgress,
149 + progress: row.opProgress ?? row.opOffset,
150 offset: row.opOffset,
151 addTitle: row.opTotal && h('div', {}, "Total: " + formatBytes(row.opTotal)),
152 sx: { mr: 1 }
src/api.monitor.ts
+3 -1
@@ -2,7 +2,7 @@
2
3 import _ from 'lodash'
4 import { Connection, getConnections } from './connections'
5 -import { pendingPromise, typedKeys, wait } from './misc'
5 +import { isLocalHost, pendingPromise, typedKeys, wait } from './misc'
6 import { ApiHandlers, SendListReadable } from './apiMiddleware'
7 import Koa from 'koa'
8 import { totalGot, totalInSpeed, totalOutSpeed, totalSent } from './throttler'
@@ -52,6 +52,8 @@ const apis: ApiHandlers = {
52 Object.assign(change, fromCtx(change.ctx))
53 change.ctx = undefined
54 }
55 + if (change.opProgress)
56 + change.opProgress = _.round(change.opProgress, 3)
57 // avoid sending non-changes
58 const last = conn[sent]
59 for (const k of typedKeys(change))
src/connections.ts
+2 -3
@@ -59,9 +59,8 @@ export function socket2connection(socket: Socket) {
59 }
60
61 export function updateConnection(conn: Connection, change: Partial<Connection>) {
62 - // if no change is detected, skip update. ctx is a special case
63 - if (!change.ctx && Object.entries(change).every(([k,v]) => _.isEqual(v, conn[k as keyof Connection]) ))
64 - return
62 + if (change.op)
63 + change.opProgress ??= change.opOffset || 0
64 Object.assign(conn, change)
65 events.emit('connectionUpdated', conn, change)
66 }
src/middlewares.ts
+2 -2
@@ -235,9 +235,9 @@ export const prepareState: Koa.Middleware = async (ctx, next) => {
235 ctx.state.account = await getHttpAccount(ctx) ?? getAccount(ctx.session?.username, false)
236 const conn = ctx.state.connection = socket2connection(ctx.socket)
237 ctx.state.revProxyPath = ctx.get('x-forwarded-prefix')
238 - await next()
238 if (conn)
240 - updateConnection(conn, { ctx })
239 + updateConnection(conn, { ctx, op: undefined })
240 + await next()
241 }
242
243 async function getHttpAccount(ctx: Koa.Context) {
src/serveFile.ts
+2 -1
@@ -76,7 +76,8 @@ export async function serveFile(ctx: Koa.Context, source:string, mime?:string, c
76 return ctx.body = content
77 const { size } = stats
78 const range = getRange(ctx, size)
79 - ctx.body = createReadStream(source, range)
79 + ctx.body = createReadStream(source, range).on('end', () =>
80 + updateConnection(ctx.state.connection, { opProgress: 1 }) )
81 if (ctx.vfsNode)
82 updateConnection(ctx.state.connection, {
83 ctx, // this will cause 'path' to be sent as well
src/throttler.ts
+1 -1
@@ -53,7 +53,7 @@ export const throttler: Koa.Middleware = async (ctx, next) => {
53 updateConnection(conn, {
54 outSpeed,
55 sent: conn.socket.bytesWritten,
56 - opProgress: (conn.opOffset || 0) + ts.getBytesSent() / conn.opTotal!,
56 + opProgress: conn.opTotal && ((conn.opOffset || 0) + (ts.getBytesSent() - offset) / conn.opTotal),
57 })
58 /* in case this stream stands still for a while (before the end), we'll have neither 'sent' or 'close' events,
59 * so who will take care to updateConnection? This artificial next-call will ensure just that */