@samitouri / QOSami-HFS / commits / a38a9036

admin: better message for some http errors

Massimo Melina committed Aug 26, 2025 at 11:31 UTC a38a9036b5009817071f4f7b73ec7f6812239d25
4 files changed +11 -9
admin/src/OnlinePlugins.ts
+2 -2
@@ -3,7 +3,7 @@
3 import { apiCall, useApiList } from './api'
4 import { Fragment, createElement as h, useState } from 'react'
5 import { DataTable } from './DataTable'
6 -import { HFS_REPO, HTTP_FAILED_DEPENDENCY, newDialog, wantArray, xlate } from './misc'
6 +import { err2msg, HFS_REPO, HTTP_FAILED_DEPENDENCY, newDialog, wantArray, xlate } from './misc'
7 import { ArrowBack, ArrowForward, Download, RemoveRedEye, Search, Warning } from '@mui/icons-material'
8 import { StringField } from '@hfs/mui-grid-form'
9 import { useDebounce } from 'usehooks-ts'
@@ -31,7 +31,7 @@ export default function OnlinePlugins() {
31 label: "Search text"
32 }),
33 h(DataTable, {
34 - error: xlate(error, PLUGIN_ERRORS),
34 + error: error && err2msg(xlate(error, PLUGIN_ERRORS)),
35 rows: list.length ? list : [], // workaround for DataGrid bug causing 'no rows' message to be not displayed after 'loading' was also used
36 noRows: "No compatible plugins have been found",
37 fillFlex: true,
admin/src/PluginsPage.ts
+1 -1
@@ -13,7 +13,7 @@ const TABS = {
13 }
14 const LABELS = Object.keys(TABS)
15 const PANES = Object.values(TABS)
16 -export const PLUGIN_ERRORS = { ENOTFOUND: "Cannot reach github.com" }
16 +export const PLUGIN_ERRORS = { ENOTFOUND: "Cannot reach github.com", ECONNREFUSED: "Cannot reach github.com" }
17
18 export default function PluginsPage() {
19 const [tab, setTab] = useState(0)
admin/src/misc.ts
+2 -1
@@ -3,6 +3,7 @@
3 import { apiCall } from './api'
4 import { HTTP_MESSAGES, MD_TAGS } from '@hfs/shared'
5 import { Link } from '@mui/material'
6 +import httpCodes from './httpCodes'
7 export * from '@hfs/shared'
8
9 ;(MD_TAGS as any).a = Link
@@ -23,7 +24,7 @@ export function err2msg(code: string | number) {
24 github_quota: "Request denied. You may have reached the limit, retry later.",
25 ENOENT: "Not found",
26 ENOTDIR: "Not a folder",
26 - }[code] || HTTP_MESSAGES[code as any] || String(code)
27 + }[code] || HTTP_MESSAGES[code as any] || httpCodes[code] || String(code) // prefer short form, as httpCodes is quite long
28 }
29
30 export function formatTimestamp(x: number | string | Date) {
src/util-http.ts
+6 -5
@@ -32,7 +32,7 @@ export interface XRequestOptions extends https.RequestOptions {
32 }
33
34 export declare namespace httpStream { let defaultProxy: string | undefined }
35 -export function httpStream(url: string, { body, jar, noRedirect, httpThrow, proxy, ...options }: XRequestOptions ={}) {
35 +export function httpStream(url: string, { body, proxy, jar, noRedirect, httpThrow, ...options }: XRequestOptions ={}) {
36 const controller = new AbortController()
37 options.signal ??= controller.signal
38 return Object.assign(new Promise<IncomingMessage>(async (resolve, reject) => {
@@ -59,8 +59,8 @@ export function httpStream(url: string, { body, jar, noRedirect, httpThrow, prox
59 url = parsed.protocol + '//' + parsed.host + parsed.path // rewrite without authentication part
60 }
61 if (proxy) {
62 - options.path = url
63 - options.headers.host ??= parse(url).host || undefined
62 + options.path = url // full url as path
63 + options.headers.host ??= parse(url).host || undefined // keep original host header
64 }
65 // this needs the prefix "proxy-"
66 const proxyAuth = proxyParsed?.auth ? { 'proxy-authorization': `Basic ${Buffer.from(proxyParsed.auth, 'utf8').toString('base64')}` } : undefined
@@ -93,7 +93,9 @@ export function httpStream(url: string, { body, jar, noRedirect, httpThrow, prox
93 return resolve(httpStream(r, options))
94 }
95 resolve(res)
96 - }).on('error', e => {
96 + }).on('error', (e: any) => {
97 + if (proxy && e?.code === 'ECONNREFUSED')
98 + console.debug("cannot connect to proxy ", proxy)
99 reject((req as any).res || e)
100 })
101 if (body && body instanceof Readable)
@@ -123,4 +125,3 @@ export function httpStream(url: string, { body, jar, noRedirect, httpThrow, prox
125 abort() { controller.abort() }
126 })
127 }
126 -