admin/monitoring: show browsing activity

Massimo Melina committed Nov 7, 2023 at 16:58 UTC 5e9f023c8178ef9cfd5ad6fb95a81b891b17d310
5 files changed +21 -8
admin/src/MonitorPage.ts
+5 -3
@@ -4,7 +4,7 @@ import _ from "lodash"
4 import { createElement as h, useMemo, Fragment, useState } from "react"
5 import { apiCall, useApiEvents, useApiEx, useApiList } from "./api"
6 import { PauseCircle, PlayCircle, LinkOff, Lock, Block, FolderZip, Upload, Download } from '@mui/icons-material'
7 -import { Alert, Box, Chip, ChipProps } from '@mui/material'
7 +import { Box, Chip, ChipProps } from '@mui/material'
8 import { DataTable } from './DataTable'
9 import { formatBytes, IconBtn, IconProgress, iconTooltip, ipForUrl, manipulateConfig, useBreakpoint } from "./misc"
10 import { Field, SelectField } from '@hfs/mui-grid-form'
@@ -85,7 +85,7 @@ function Connections() {
85 const [filtered, setFiltered] = useState(true)
86 const [paused, setPaused] = useState(false)
87 const rows = useMemo(() =>
88 - list?.filter((x: any) => !filtered || x.path).map((x: any, id: number) => ({ id, ...x })),
88 + list?.filter((x: any) => !filtered || x.op).map((x: any, id: number) => ({ id, ...x })),
89 [!paused && list, filtered]) //eslint-disable-line
90 return h(Fragment, {},
91 h(Box, { display: 'flex', alignItems: 'center' },
@@ -144,9 +144,11 @@ function Connections() {
144 row.archive,
145 h(Box, { ml: 2, color: 'text.secondary' }, value)
146 )
147 + if (!row.op)
148 + return h(Box, {}, value, h(Box, { fontSize: 'x-small' }, "browsing"))
149 const i = value?.lastIndexOf('/')
150 return h(Fragment, {},
149 - row.op && h(IconProgress, {
151 + h(IconProgress, {
152 icon: row.op === 'upload' ? Upload : Download,
153 progress: row.opProgress ?? row.opOffset,
154 offset: row.opOffset,
src/api.file_list.ts
+3
@@ -10,6 +10,7 @@ import { HTTP_FOOL, HTTP_METHOD_NOT_ALLOWED, HTTP_NOT_FOUND } from './const'
10 import Koa from 'koa'
11 import { descriptIon, DESCRIPT_ION, getCommentFor, areCommentsEnabled } from './comments'
12 import { basename } from 'path'
13 +import { getConnection, updateConnection } from './connections'
14
15 export interface DirEntry { n:string, s?:number, m?:Date, c?:Date, p?: string, comment?: string, web?: boolean, url?: string }
16
@@ -38,6 +39,8 @@ export const get_file_list: ApiHandler = async ({ uri, offset, limit, search, c
39 if (!list)
40 return { ...props, list: await asyncGeneratorToArray(produceEntries()) }
41 setTimeout(async () => {
42 + ctx.state.browsing = uri
43 + updateConnection(getConnection(ctx)!, { ctx })
44 list.props(props)
45 for await (const entry of produceEntries())
46 list.add(entry)
src/api.monitor.ts
+6 -3
@@ -80,13 +80,16 @@ const apis: ApiHandlers = {
80 }
81
82 function fromCtx(ctx?: Koa.Context) {
83 - return ctx && {
83 + if (!ctx) return
84 + const path = ctx.state.browsing && decodeURIComponent(ctx.state.browsing)
85 + || ctx.state.uploadPath && decodeURIComponent(ctx.state.uploadPath)
86 + || (ctx.fileSource || ctx.state.archive) && decodeURIComponent(ctx.path) // downloads
87 + return {
88 user: getCurrentUsername(ctx),
89 agent: getBrowser(ctx.get('user-agent')),
90 archive: ctx.state.archive,
91 upload: ctx.state.uploadProgress,
88 - path: ctx.state.uploadPath && decodeURIComponent(ctx.state.uploadPath)
89 - || (ctx.fileSource || ctx.state.archive) && decodeURIComponent(ctx.path) // only uploads and downloads
92 + ...path && { path },
93 }
94 }
95 },
src/connections.ts
+6 -2
@@ -2,7 +2,7 @@
2
3 import { Socket } from 'net'
4 import events from './events'
5 -import Koa from 'koa'
5 +import { Context } from 'koa'
6 import _ from 'lodash'
7
8 export class Connection {
@@ -15,7 +15,7 @@ export class Connection {
15 opTotal?: number
16 opProgress?: number
17 opOffset?: number
18 - ctx?: Koa.Context
18 + ctx?: Context
19 private _cachedIp?: string
20 [rest:symbol]: any // let other modules add extra data, but using symbols to avoid name collision
21
@@ -57,6 +57,10 @@ export function socket2connection(socket: Socket) {
57 && x.socket.remoteAddress === socket.remoteAddress )
58 }
59
60 +export function getConnection(ctx: Context) {
61 + return _.find(all, { ctx })
62 +}
63 +
64 export function updateConnection(conn: Connection, change: Partial<Connection>) {
65 if (change.op)
66 change.opProgress ??= change.opOffset || 0
src/middlewares.ts
+1
@@ -217,6 +217,7 @@ export const prepareState: Koa.Middleware = async (ctx, next) => {
217 ctx.state.account = undefined
218 const conn = ctx.state.connection = socket2connection(ctx.socket)
219 ctx.state.revProxyPath = ctx.get('x-forwarded-prefix')
220 + ctx.state.browsing = undefined
221 if (conn)
222 updateConnection(conn, { ctx, op: undefined })
223 await next()