use promise lock and add an await

This commit is contained in:
Mathium05 committed 2026-08-26 14:02:23 -05:00
1 parent d888f253f2
commit c1de80e61b
2 files changed
+149 -137

No files matched your search

+141 -136
View File
@@ -10,6 +10,7 @@ import {Emoji} from "./emoji.js";
import {I18n} from "./i18n.js";
import {Localuser} from "./localuser.js";
import {MarkDown} from "./markdown.js";
import {PromiseLock} from "./utils/promiseLock.js";
interface OptionsElement<x> {
//
@@ -2350,161 +2351,165 @@ class Form implements OptionsElement<object> {
this.preprocessor = func;
}
onFormError = (_: FormError) => {};
subbmitting = false;
submitLock = new PromiseLock();
async submit() {
if (this.submitLock.locked) return;
const lock = await this.submitLock.acquireLock();
try {
this.submitInt();
} finally {
lock();
}
}
private async submitInt() {
if (this.options.subOptions) {
this.options.subOptions.submit();
return;
}
if (this.subbmitting) return;
this.subbmitting = true;
try {
console.log("start");
const build = {};
for (const key of Object.keys(this.values)) {
const thing = this.values[key];
if (thing instanceof Function) {
try {
(build as any)[key] = thing();
} catch (e: any) {
if (e instanceof FormError) {
this.handleError(e);
}
return;
console.log("start");
const build = {};
for (const key of Object.keys(this.values)) {
const thing = this.values[key];
if (thing instanceof Function) {
try {
(build as any)[key] = thing();
} catch (e: any) {
if (e instanceof FormError) {
this.handleError(e);
}
return;
}
} else {
(build as any)[key] = thing;
}
}
console.log("middle");
const promises: Promise<void>[] = [];
for (const thing of this.names.keys()) {
if (thing === "") continue;
const input = this.names.get(thing) as OptionsElement<any>;
if (input instanceof SelectInput) {
(build as any)[thing] = (this.selectMap.get(input) as string[])[input.value];
continue;
} else if (input instanceof FileInput) {
const options = this.fileOptions.get(input);
if (!options) {
throw new Error(
"FileInput without its options is in this form, this should never happen.",
);
}
if (options.files === "one") {
console.log(input.value);
if (input.value) {
const reader = new FileReader();
const promise = new Promise<void>((res) => {
reader.onload = () => {
(build as any)[thing] = reader.result;
res();
};
});
reader.readAsDataURL(input.value[0]);
promises.push(promise);
continue;
}
} else {
(build as any)[key] = thing;
console.error(options.files + " is not currently implemented");
}
} else if (input instanceof EmojiInput) {
if (!input.value) {
(build as any)[thing] = input.value;
} else if (input.value.id) {
(build as any)[thing] = input.value.id;
} else if (input.value.emoji) {
(build as any)[thing] = input.value.emoji;
}
continue;
}
console.log("middle");
const promises: Promise<void>[] = [];
for (const thing of this.names.keys()) {
if (thing === "") continue;
const input = this.names.get(thing) as OptionsElement<any>;
if (input instanceof SelectInput) {
(build as any)[thing] = (this.selectMap.get(input) as string[])[input.value];
continue;
} else if (input instanceof FileInput) {
const options = this.fileOptions.get(input);
if (!options) {
throw new Error(
"FileInput without its options is in this form, this should never happen.",
);
(build as any)[thing] = input.value;
}
console.log("middle2");
await Promise.allSettled(promises);
try {
this.preprocessor(build);
} catch (e) {
if (e instanceof FormError) {
this.handleError(e);
}
return;
}
if (this.fetchURL !== "") {
const onSubmit = async (json: any) => {
try {
await this.onSubmit(json, build);
} catch (e) {
console.error(e);
if (e instanceof FormError) {
this.handleError(e);
}
if (options.files === "one") {
console.log(input.value);
if (input.value) {
const reader = new FileReader();
const promise = new Promise<void>((res) => {
reader.onload = () => {
(build as any)[thing] = reader.result;
res();
};
});
reader.readAsDataURL(input.value[0]);
promises.push(promise);
continue;
return;
}
};
const doFetch = async () => {
fetch(this.fetchURL, {
method: this.method,
body: JSON.stringify(build),
headers: this.headers,
})
.then(async (_) => {
return [await _.text(), _.status] as const;
})
.then(([_, status]) => {
if (_ === "") return [null, status];
return [JSON.parse(_), status] as const;
})
.then(async ([json, status]) => {
if (await handleCaptcha(json, build, this.captcha)) {
return await doFetch();
}
} else {
console.error(options.files + " is not currently implemented");
}
} else if (input instanceof EmojiInput) {
if (!input.value) {
(build as any)[thing] = input.value;
} else if (input.value.id) {
(build as any)[thing] = input.value.id;
} else if (input.value.emoji) {
(build as any)[thing] = input.value.emoji;
}
continue;
}
(build as any)[thing] = input.value;
}
console.log("middle2");
await Promise.allSettled(promises);
const match = this.fetchURL.match(/https?:\/\/[^\/]*\/api/gm);
if (match && this.tfaCheck) {
const tried = await handle2fa(json, match[0]);
if (tried) {
return await onSubmit(tried);
}
}
if (json.ticket) {
}
if (json.errors) {
if (this.errors(json)) {
return;
}
} else if (status === 500) {
this.error(
[...this.names].at(-1)?.[0] ?? "",
json.message ?? "internal server error",
);
return;
}
if (
Math.floor(json.code / 100) === 4 &&
json.message &&
typeof json.message === "string"
) {
this.showPrimError(json.message);
return;
}
onSubmit(json);
});
};
await doFetch();
} else {
try {
this.preprocessor(build);
await this.onSubmit(build, build);
} catch (e) {
if (e instanceof FormError) {
this.handleError(e);
}
return;
}
if (this.fetchURL !== "") {
const onSubmit = async (json: any) => {
try {
await this.onSubmit(json, build);
} catch (e) {
console.error(e);
if (e instanceof FormError) {
this.handleError(e);
}
return;
}
};
const doFetch = async () => {
fetch(this.fetchURL, {
method: this.method,
body: JSON.stringify(build),
headers: this.headers,
})
.then(async (_) => {
return [await _.text(), _.status] as const;
})
.then(([_, status]) => {
if (_ === "") return [null, status];
return [JSON.parse(_), status] as const;
})
.then(async ([json, status]) => {
if (await handleCaptcha(json, build, this.captcha)) {
return await doFetch();
}
const match = this.fetchURL.match(/https?:\/\/[^\/]*\/api/gm);
if (match && this.tfaCheck) {
const tried = await handle2fa(json, match[0]);
if (tried) {
return await onSubmit(tried);
}
}
if (json.ticket) {
}
if (json.errors) {
if (this.errors(json)) {
return;
}
} else if (status === 500) {
this.error(
[...this.names].at(-1)?.[0] ?? "",
json.message ?? "internal server error",
);
return;
}
if (
Math.floor(json.code / 100) === 4 &&
json.message &&
typeof json.message === "string"
) {
this.showPrimError(json.message);
return;
}
onSubmit(json);
});
};
doFetch();
} else {
try {
await this.onSubmit(build, build);
} catch (e) {
if (e instanceof FormError) {
this.handleError(e);
}
return;
}
}
console.warn("needs to be implemented");
} finally {
this.subbmitting = false;
}
console.warn("needs to be implemented");
}
showPrimError(error: string) {
const pop = new PopUp(error, {goAbove: true, buttons: popUpButtonTypes.dismiss});
+8 -1
View File
@@ -1,10 +1,17 @@
export class PromiseLock {
lastLock = Promise.resolve();
private unlockedLock = this.lastLock;
async acquireLock() {
const {promise, resolve: res} = Promise.withResolvers<void>();
const last = this.lastLock;
this.lastLock = promise;
await last;
return res;
return () => {
this.unlockedLock = promise;
res();
};
}
get locked() {
return this.lastLock !== this.unlockedLock;
}
}