better code

Massimo Melina committed Sep 20, 2023 at 21:53 UTC d58887c5afc703b887e467798c988137e234610c
8 files changed +49 -50
README.md
+1 -1
@@ -68,7 +68,7 @@ If you don't like this behavior, disable it in the Admin-panel or enter this con
68
69 If your system is not Windows/Linux/Mac or you just don't want to run the binaries, you can try this alternative version:
70
71 -1. [install node.js](https://nodejs.org)
71 +1. [install node.js](https://nodejs.org) version 18
72 2. execute at command line `npx hfs@latest`
73
74 The `@latest` part is optional, and ensures that you are always up to date.
mui-grid-form/index.ts
+3 -1
@@ -34,16 +34,18 @@ export interface FieldDescriptor<T=any> extends FieldApi<T> {
34 fromField?: (v: any) => T
35 before?: ReactNode
36 after?: ReactNode
37 + getError?: GetError
38 [extraProp: string]: any
39 }
40
41 // it seems necessary to cast (Multi)SelectField sometimes
42 export type Field<T> = FC<FieldProps<T>>
43
44 +type GetError = (v: any, extra?: any) => Promisable<ValidationError>
45 export type Promisable<T> = T | Promise<T>
46 interface FieldApi<T> {
47 // provide getError if you want your error to be visible by the Form component
46 - getError?: (v: any, extra?: any) => Promisable<ValidationError>
48 + getError?: GetError
49 isEqual?: (a: T, b: T) => boolean,
50 }
51 export interface FieldProps<T> {
plugins/download-counter/plugin.js
+14 -15
@@ -44,21 +44,20 @@ exports.init = async api => {
44 frontend_js: 'main.js',
45 frontend_css: 'style.css',
46 unload: () => save.flush(), // we may have pending savings
47 - middleware: (ctx) =>
48 - () => { // execute after other middlewares are done
49 - if (ctx.status >= 300 || ctx.state.download_counter_ignore || ctx.state.includesLastByte === false) return
50 - if (!(ctx.vfsNode || api.getConfig('archives') && ctx.state.archive)) return
51 - ctx.state.completed.then(() => {
52 - const key = uri2key(ctx.path)
53 - const entries = ctx.vfsNode ? [key]
54 - : ctx.state.originalStream?.getArchiveEntries?.().filter(x => x.at(-1) !== '/').map(x => key + uri2key(x))
55 - if (!entries) return
56 - for (const k of entries)
57 - counters[k] = counters[k] + 1 || 1
58 - save()
59 - })
60 - },
61 - onDirEntry: ({ entry, listUri }) => {
47 + middleware: ctx => () => { // callback = execute after other middlewares are done
48 + if (ctx.status >= 300 || ctx.state.download_counter_ignore || ctx.state.includesLastByte === false) return
49 + if (!(ctx.vfsNode || api.getConfig('archives') && ctx.state.archive)) return
50 + ctx.state.completed.then(() => {
51 + const key = uri2key(ctx.path)
52 + const entries = ctx.vfsNode ? [key]
53 + : ctx.state.originalStream?.getArchiveEntries?.().filter(x => x.at(-1) !== '/').map(x => key + uri2key(x))
54 + if (!entries) return
55 + for (const k of entries)
56 + counters[k] = counters[k] + 1 || 1
57 + save()
58 + })
59 + },
60 + onDirEntry({ entry, listUri }) {
61 const k = uri2key(listUri + entry.n)
62 const n = counters[k]
63 if (n)
src/api.plugins.ts
+1 -1
@@ -28,7 +28,7 @@ import { HTTP_FAILED_DEPENDENCY, HTTP_NOT_FOUND, HTTP_SERVER_ERROR } from './con
28 const apis: ApiHandlers = {
29
30 get_plugins({}, ctx) {
31 - const list = new SendListReadable({ addAtStart: [ ...mapPlugins(serialize), ...getAvailablePlugins().map(serialize) ] })
31 + const list = new SendListReadable({ addAtStart: [ ...mapPlugins(serialize, false), ...getAvailablePlugins().map(serialize) ] })
32 return list.events(ctx, {
33 pluginInstalled: p => list.add(serialize(p)),
34 'pluginStarted pluginStopped pluginUpdated': p => {
src/config.ts
+2 -5
@@ -5,7 +5,7 @@ import { argv, ORIGINAL_CWD, VERSION } from './const'
5 import { watchLoad } from './watchLoad'
6 import yaml from 'yaml'
7 import _ from 'lodash'
8 -import { DAY, debounceAsync, newObj, onOff, tryJson, wait, with_ } from './misc'
8 +import { DAY, debounceAsync, newObj, onOff, throw_, tryJson, wait, with_ } from './misc'
9 import { statSync } from 'fs'
10 import { join, resolve } from 'path'
11 import events from './events'
@@ -86,10 +86,7 @@ export function defineConfig<T, CT=T>(k: string, defaultValue: T, compiler?: Sub
86 else
87 setConfig1(k, v)
88 },
89 - compiled: () => {
90 - if (!compiler) throw "missing compiler"
91 - return compiled as CT
92 - }
89 + compiled: () => compiled ?? throw_("missing compiler"),
90 }
91 if (compiler)
92 ret.sub((...args) =>
src/cross.ts
+5
@@ -88,6 +88,11 @@ export function _log(...args: any[]) {
88 return args[args.length-1]
89 }
90
91 +export function _dbg(x: any) {
92 + debugger
93 + return x
94 +}
95 +
96 export type PendingPromise<T=unknown> = Promise<T> & { resolve: (value?: T) => void, reject: (reason?: any) => void }
97 export function pendingPromise<T>() {
98 let takeOut
src/debounceAsync.ts
+1
@@ -19,6 +19,7 @@ export default function debounceAsync<Cancelable extends boolean = false, A exte
19 let lastSince = 0
20 const interceptingWrapper = (...args: A) => runningDebouncer = debouncer(...args)
21 return Object.assign(interceptingWrapper, {
22 + clearRetain: () => last = undefined,
23 flush: () => runningCallback ?? exec(),
24 ...cancelable && {
25 cancel() {
src/plugins.ts
+22 -27
@@ -7,18 +7,8 @@ import { API_VERSION, APP_PATH, COMPATIBLE_API_VERSION, IS_WINDOWS, PLUGINS_PUB_
7 import * as Const from './const'
8 import Koa from 'koa'
9 import {
10 - adjustStaticPathForGlob,
11 - Callback,
12 - debounceAsync,
13 - Dict,
14 - getOrSet,
15 - onProcessExit,
16 - PendingPromise, pendingPromise,
17 - same,
18 - tryJson,
19 - wait,
20 - wantArray,
21 - watchDir
10 + adjustStaticPathForGlob, Callback, debounceAsync, Dict, getOrSet, onProcessExit,
11 + PendingPromise, pendingPromise, same, tryJson, wait, wantArray, watchDir
12 } from './misc'
13 import { defineConfig, getConfig } from './config'
14 import { DirEntry } from './api.file_list'
@@ -89,19 +79,12 @@ export function setPluginConfig(id: string, changes: Dict) {
79 }
80
81 export function getPluginInfo(id: string) {
82 + if (id === SERVER_CODE_ID)
83 + return serverCodeReturned
84 const running = plugins[id]?.getData()
85 return running && Object.assign(running, {id}) || availablePlugins[id]
86 }
87
96 -export function mapPlugins<T>(cb:(plugin:Readonly<Plugin>, pluginName:string)=> T) {
97 - return _.map(plugins, (pl,plName) => {
98 - try { return cb(pl,plName) }
99 - catch(e) {
100 - console.log('plugin error', plName, String(e))
101 - }
102 - }).filter(x => x !== undefined) as Exclude<T,undefined>[]
103 -}
104 -
88 export function findPluginByRepo<T>(repo: string) {
89 return _.find(plugins, pl => match(pl.getData()))
90 || _.find(availablePlugins, match)
@@ -126,6 +109,21 @@ const serverCode = defineConfig('server_code', '', async (script, { k }) => {
109 }
110 })
111
112 +const SERVER_CODE_ID = '.'
113 +let serverCodeReturned: any
114 +serverCode.sub(() => serverCode.compiled().then(x => serverCodeReturned = x))
115 +export function mapPlugins<T>(cb:(plugin:Readonly<Plugin>, pluginName:string)=> T, includeServerCode=true) {
116 + const entries = Object.entries(plugins)
117 + if (includeServerCode && serverCodeReturned)
118 + entries.push([SERVER_CODE_ID, serverCodeReturned])
119 + return entries.map(([plName,pl]) => {
120 + try { return cb(pl,plName) }
121 + catch(e) {
122 + console.log('plugin error', plName, String(e))
123 + }
124 + }).filter(x => x !== undefined) as Exclude<T,undefined>[]
125 +}
126 +
127 async function initPlugin<T>(pl: any, more?: T) {
128 return Object.assign(pl, await pl.init?.({
129 const: Const, // legacy, deprecated in 0.48
@@ -143,11 +141,7 @@ async function initPlugin<T>(pl: any, more?: T) {
141 export const pluginsMiddleware: Koa.Middleware = async (ctx, next) => {
142 const after: Dict<CallMeAfter> = {}
143 // run middleware plugins
146 - const entries = Object.entries(plugins)
147 - const sc = await serverCode.compiled()
148 - if (sc)
149 - entries.push(['.', await serverCode.compiled()])
150 - for (const [id,pl] of entries)
144 + await Promise.all(mapPlugins(async (pl, id) => {
145 try {
146 const res = await pl.middleware?.(ctx)
147 if (res === true)
@@ -158,7 +152,8 @@ export const pluginsMiddleware: Koa.Middleware = async (ctx, next) => {
152 catch(e){
153 printError(id, e)
154 }
161 - // expose public plugins' files
155 + }))
156 + // expose public plugins' files`
157 if (!ctx.pluginBlockedRequest) {
158 const { path } = ctx
159 if (path.startsWith(PLUGINS_PUB_URI)) {