fix: (regression beta) admin/logs: not showing country and notes for past lines

Massimo Melina committed Feb 12, 2024 at 16:24 UTC c4dc87e3ec697677620d4e29db067e2cd216a644
3 files changed +28 -19
admin/src/LogsPage.ts
+18 -18
@@ -5,7 +5,7 @@ import { Box, Tab, Tabs } from '@mui/material'
5 import { API_URL, useApi, useApiList } from './api'
6 import { DataTable } from './DataTable'
7 import { CFG, Dict, formatBytes, HTTP_UNAUTHORIZED, newDialog, prefix, shortenAgent, splitAt, tryJson,
8 - typedKeys, NBSP, _dbg } from '@hfs/shared'
8 + typedKeys, NBSP, _dbg, mapFilter } from '@hfs/shared'
9 import { logLabels } from './OptionsPage'
10 import {
11 NetmaskField, Flex, IconBtn, useBreakpoint, usePauseButton, useToggleButton, WildcardsSupported, Country,
@@ -94,6 +94,7 @@ function LogFile({ file, addToFooter, hidden }: { hidden?: boolean, file: string
94 const [limited, setLimited] = useState(true)
95 const [skipped, setSkipped] = useState(0)
96 const MAX = 2**20
97 + const invert = true
98 useApi('get_log_file', { file, range: limited || !skipped ? -MAX : `0-${skipped}` }, {
99 skipParse: true, skipLog: true,
100 onResponse(res, body) {
@@ -111,26 +112,11 @@ function LogFile({ file, addToFooter, hidden }: { hidden?: boolean, file: string
112 toast(`Entire log loaded, ${formatBytes(skipped)}`)
113 setSkipped(0)
114 }
114 - const treated = lines.map(parseLogLine).filter(Boolean).reverse()
115 + const treated = mapFilter(lines, (x: any, i) => enhanceLogLine(parseLogLine(x, i)), Boolean, invert)
116 setList(x => [...x, ...treated])
117 }
118 })
118 - const { list, setList, error, connecting } = useApiList('get_log', { file }, {
119 - invert: true,
120 - pause,
121 - map(x) {
122 - const { extra } = x
123 - if (extra?.country && !showCountry)
124 - setShowCountry(true)
125 - if (extra?.ua && !showAgent)
126 - setShowAgent(true)
127 - x.notes = extra?.dl ? "fully downloaded"
128 - : (x.method === 'PUT' || extra?.ul) ? "uploaded " + formatBytes(extra.size, { sep: NBSP })
129 - : x.status === HTTP_UNAUTHORIZED && x.uri?.startsWith(API_URL + 'loginSrp') ? "login failed" + prefix(':\n', extra?.u)
130 - : x.notes
131 - return x
132 - }
133 - })
119 + const { list, setList, error, connecting } = useApiList('get_log', { file }, { invert, pause, map: enhanceLogLine })
120 const tsColumn: GridColDef = {
121 field: 'ts',
122 headerName: "Timestamp",
@@ -262,6 +248,20 @@ function LogFile({ file, addToFooter, hidden }: { hidden?: boolean, file: string
248 },
249 ]
250 })
251 +
252 + function enhanceLogLine(x: any) {
253 + if (!x) return
254 + const { extra } = x
255 + if (extra?.country && !showCountry)
256 + setShowCountry(true)
257 + if (extra?.ua && !showAgent)
258 + setShowAgent(true)
259 + x.notes = extra?.dl ? "fully downloaded"
260 + : (x.method === 'PUT' || extra?.ul) ? "uploaded " + formatBytes(extra.size, { sep: NBSP })
261 + : x.status === HTTP_UNAUTHORIZED && x.uri?.startsWith(API_URL + 'loginSrp') ? "login failed" + prefix(':\n', extra?.u)
262 + : x.notes
263 + return x
264 + }
265 }
266
267 export function agentIcons(agent: string) {
src/cross.ts
+9
@@ -440,6 +440,15 @@ export function inCommon<T extends string | unknown[]>(a: T, b: T) {
440 return i
441 }
442
443 +export function mapFilter<T=unknown, R=T>(arr: T[], map: (x:T, idx: number) => R, filter=(x: R) => x === undefined, invert=false) {
444 + return arr[invert ? 'reduceRight' : 'reduce']((ret, x, idx) => {
445 + const y = map(x, idx)
446 + if (filter(y))
447 + ret.push(y) // push is much faster than unshift, therefore invert using reduceRight https://measurethat.net/Benchmarks/Show/29/0/array-push-vs-unshift
448 + return ret
449 + }, [] as R[])
450 +}
451 +
452 export function shortenAgent(agent: string) {
453 return _.findKey(BROWSERS, re => re.test(agent))
454 || /^[^/(]+ ?/.exec(agent)?.[0]
src/log.ts
+1 -1
@@ -130,7 +130,7 @@ export const logMw: Koa.Middleware = async (ctx, next) => {
130 ctx.req.httpVersion,
131 ctx.status,
132 length?.toString() ?? '-',
133 - _.isEmpty(extra) ? '' : JSON.stringify(JSON.stringify(extra)),
133 + _.isEmpty(extra) ? '' : JSON.stringify(JSON.stringify(extra)), // jsonize twice, as we need a field enclosed by double-quotes
134 ))
135 })
136 }