2024-06-20 01:17:33 +02:00
|
|
|
import type {
|
2024-08-25 16:01:06 +02:00
|
|
|
Delete,
|
2024-08-25 16:10:38 +02:00
|
|
|
DislikeExtension,
|
2024-06-20 01:17:33 +02:00
|
|
|
Follow,
|
|
|
|
|
FollowAccept,
|
|
|
|
|
FollowReject,
|
2024-08-25 16:01:06 +02:00
|
|
|
Group,
|
|
|
|
|
InstanceMetadata,
|
2024-08-25 16:10:38 +02:00
|
|
|
LikeExtension,
|
2024-06-20 01:17:33 +02:00
|
|
|
Note,
|
2024-08-25 16:10:38 +02:00
|
|
|
PollVoteExtension,
|
|
|
|
|
ReactionExtension,
|
|
|
|
|
ShareExtension,
|
2024-08-25 16:01:06 +02:00
|
|
|
Unfollow,
|
2024-06-20 01:17:33 +02:00
|
|
|
User,
|
2024-09-16 12:44:11 +02:00
|
|
|
} from "./types";
|
2024-07-26 17:49:36 +02:00
|
|
|
import type { EntityValidator } from "./validator";
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
type MaybePromise<T> = T | Promise<T>;
|
|
|
|
|
|
2024-05-29 02:14:02 +02:00
|
|
|
type ParserCallbacks<T> = {
|
2024-06-20 01:17:33 +02:00
|
|
|
note: (note: Note) => MaybePromise<T>;
|
|
|
|
|
follow: (follow: Follow) => MaybePromise<T>;
|
|
|
|
|
followAccept: (followAccept: FollowAccept) => MaybePromise<T>;
|
|
|
|
|
followReject: (followReject: FollowReject) => MaybePromise<T>;
|
|
|
|
|
user: (user: User) => MaybePromise<T>;
|
2024-08-25 16:10:38 +02:00
|
|
|
"pub.versia:likes/Like": (like: LikeExtension) => MaybePromise<T>;
|
|
|
|
|
"pub.versia:likes/Dislike": (dislike: DislikeExtension) => MaybePromise<T>;
|
2024-08-25 16:01:06 +02:00
|
|
|
delete: (undo: Delete) => MaybePromise<T>;
|
|
|
|
|
instanceMetadata: (instanceMetadata: InstanceMetadata) => MaybePromise<T>;
|
|
|
|
|
group: (group: Group) => MaybePromise<T>;
|
2024-08-25 16:10:38 +02:00
|
|
|
"pub.versia:reactions/Reaction": (
|
|
|
|
|
reaction: ReactionExtension,
|
|
|
|
|
) => MaybePromise<T>;
|
|
|
|
|
"pub.versia:share/Share": (share: ShareExtension) => MaybePromise<T>;
|
|
|
|
|
"pub.versia:polls/Vote": (vote: PollVoteExtension) => MaybePromise<T>;
|
2024-08-25 16:01:06 +02:00
|
|
|
unfollow: (unfollow: Unfollow) => MaybePromise<T>;
|
|
|
|
|
unknown: (data: unknown) => MaybePromise<T>;
|
2024-05-29 01:38:47 +02:00
|
|
|
};
|
|
|
|
|
|
2024-05-29 02:22:30 +02:00
|
|
|
/**
|
|
|
|
|
* A class to parse the body of a request and call the appropriate callback.
|
|
|
|
|
* @example
|
2024-06-26 07:34:54 +02:00
|
|
|
* const body = { ... };
|
|
|
|
|
* const validator = new EntityValidator();
|
2024-05-29 02:22:30 +02:00
|
|
|
* const parser = new RequestParserHandler(body, validator);
|
|
|
|
|
*
|
|
|
|
|
* await parser.parseBody({
|
|
|
|
|
* note: (note) => {
|
2024-06-26 07:34:54 +02:00
|
|
|
* // If the object is a Note, this will be called
|
2024-05-29 02:22:30 +02:00
|
|
|
* console.log(note);
|
|
|
|
|
* },
|
|
|
|
|
* follow: (follow) => {
|
2024-06-26 07:34:54 +02:00
|
|
|
* // If the object is a Follow, this will be called
|
2024-05-29 02:22:30 +02:00
|
|
|
* console.log(follow);
|
|
|
|
|
* },
|
|
|
|
|
* ...
|
|
|
|
|
* });
|
|
|
|
|
*/
|
2024-05-29 01:38:47 +02:00
|
|
|
export class RequestParserHandler {
|
|
|
|
|
constructor(
|
|
|
|
|
private readonly body: Record<
|
|
|
|
|
string,
|
|
|
|
|
string | number | object | boolean | null
|
|
|
|
|
>,
|
|
|
|
|
private readonly validator: EntityValidator,
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parse the body of the request and call the appropriate callback.
|
2024-05-29 02:14:02 +02:00
|
|
|
* To change the return type, edit the ReturnType generic parameter.
|
2024-05-29 02:22:30 +02:00
|
|
|
* const parser = new RequestParserHandler(body, validator);
|
2024-05-29 01:38:47 +02:00
|
|
|
* @param callbacks The callbacks to call when a specific entity is found.
|
|
|
|
|
* @returns A promise that resolves when the body has been parsed, and the callbacks have finished executing.
|
2024-05-29 02:22:30 +02:00
|
|
|
* @throws If the type field is missing or invalid
|
|
|
|
|
* @example
|
|
|
|
|
* await parser.parseBody({
|
|
|
|
|
* note: (note) => {
|
|
|
|
|
* console.log(note);
|
|
|
|
|
* },
|
|
|
|
|
* follow: (follow) => {
|
|
|
|
|
* console.log(follow);
|
|
|
|
|
* },
|
|
|
|
|
* ...
|
|
|
|
|
* });
|
2024-05-29 01:38:47 +02:00
|
|
|
*/
|
2024-05-29 02:14:02 +02:00
|
|
|
public async parseBody<ReturnType = void>(
|
|
|
|
|
callbacks: Partial<ParserCallbacks<ReturnType>>,
|
|
|
|
|
): Promise<ReturnType> {
|
2024-06-20 00:21:34 +02:00
|
|
|
if (!this.body.type) {
|
|
|
|
|
throw new Error("Missing type field in body");
|
|
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
switch (this.body.type) {
|
|
|
|
|
case "Note": {
|
|
|
|
|
const note = await this.validator.Note(this.body);
|
|
|
|
|
|
2024-06-20 00:21:34 +02:00
|
|
|
if (callbacks.note) {
|
|
|
|
|
return await callbacks.note(note);
|
|
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "Follow": {
|
|
|
|
|
const follow = await this.validator.Follow(this.body);
|
|
|
|
|
|
2024-06-20 00:21:34 +02:00
|
|
|
if (callbacks.follow) {
|
|
|
|
|
return await callbacks.follow(follow);
|
|
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "FollowAccept": {
|
|
|
|
|
const followAccept = await this.validator.FollowAccept(
|
|
|
|
|
this.body,
|
|
|
|
|
);
|
|
|
|
|
|
2024-06-20 00:21:34 +02:00
|
|
|
if (callbacks.followAccept) {
|
2024-05-29 02:14:02 +02:00
|
|
|
return await callbacks.followAccept(followAccept);
|
2024-06-20 00:21:34 +02:00
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "FollowReject": {
|
|
|
|
|
const followReject = await this.validator.FollowReject(
|
|
|
|
|
this.body,
|
|
|
|
|
);
|
|
|
|
|
|
2024-06-20 00:21:34 +02:00
|
|
|
if (callbacks.followReject) {
|
2024-05-29 02:14:02 +02:00
|
|
|
return await callbacks.followReject(followReject);
|
2024-06-20 00:21:34 +02:00
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "User": {
|
|
|
|
|
const user = await this.validator.User(this.body);
|
|
|
|
|
|
2024-06-20 00:21:34 +02:00
|
|
|
if (callbacks.user) {
|
|
|
|
|
return await callbacks.user(user);
|
|
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "Like": {
|
2024-08-25 16:10:38 +02:00
|
|
|
const like = await this.validator.LikeExtension(this.body);
|
2024-05-29 01:38:47 +02:00
|
|
|
|
2024-08-25 16:10:38 +02:00
|
|
|
if (callbacks["pub.versia:likes/Like"]) {
|
|
|
|
|
return await callbacks["pub.versia:likes/Like"](like);
|
2024-06-20 00:21:34 +02:00
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "Dislike": {
|
2024-08-25 16:10:38 +02:00
|
|
|
const dislike = await this.validator.DislikeExtension(
|
|
|
|
|
this.body,
|
|
|
|
|
);
|
2024-05-29 01:38:47 +02:00
|
|
|
|
2024-08-25 16:10:38 +02:00
|
|
|
if (callbacks["pub.versia:likes/Dislike"]) {
|
|
|
|
|
return await callbacks["pub.versia:likes/Dislike"](dislike);
|
2024-06-20 00:21:34 +02:00
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-08-25 16:01:06 +02:00
|
|
|
case "Delete": {
|
|
|
|
|
// "delete" isn't an allowed variable name
|
|
|
|
|
const delete_ = await this.validator.Delete(this.body);
|
2024-05-29 01:38:47 +02:00
|
|
|
|
2024-08-25 16:01:06 +02:00
|
|
|
if (callbacks.delete) {
|
|
|
|
|
return await callbacks.delete(delete_);
|
2024-06-20 00:21:34 +02:00
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-08-25 16:01:06 +02:00
|
|
|
case "InstanceMetadata": {
|
|
|
|
|
const instanceMetadata = await this.validator.InstanceMetadata(
|
2024-05-29 01:38:47 +02:00
|
|
|
this.body,
|
|
|
|
|
);
|
|
|
|
|
|
2024-08-25 16:01:06 +02:00
|
|
|
if (callbacks.instanceMetadata) {
|
|
|
|
|
return await callbacks.instanceMetadata(instanceMetadata);
|
2024-06-20 00:21:34 +02:00
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-08-25 16:01:06 +02:00
|
|
|
case "Group": {
|
|
|
|
|
const group = await this.validator.Group(this.body);
|
2024-05-29 01:38:47 +02:00
|
|
|
|
2024-08-25 16:01:06 +02:00
|
|
|
if (callbacks.group) {
|
|
|
|
|
return await callbacks.group(group);
|
2024-06-20 00:21:34 +02:00
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-08-25 16:01:06 +02:00
|
|
|
case "Reaction": {
|
2024-08-25 16:10:38 +02:00
|
|
|
const reaction = await this.validator.ReactionExtension(
|
|
|
|
|
this.body,
|
|
|
|
|
);
|
2024-08-25 16:01:06 +02:00
|
|
|
|
2024-08-25 16:10:38 +02:00
|
|
|
if (callbacks["pub.versia:reactions/Reaction"]) {
|
|
|
|
|
return await callbacks["pub.versia:reactions/Reaction"](
|
|
|
|
|
reaction,
|
|
|
|
|
);
|
2024-08-25 16:01:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "Share": {
|
2024-08-25 16:10:38 +02:00
|
|
|
const share = await this.validator.ShareExtension(this.body);
|
2024-08-25 16:01:06 +02:00
|
|
|
|
2024-08-25 16:10:38 +02:00
|
|
|
if (callbacks["pub.versia:share/Share"]) {
|
|
|
|
|
return await callbacks["pub.versia:share/Share"](share);
|
2024-08-25 16:01:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "Vote": {
|
2024-08-25 16:10:38 +02:00
|
|
|
const vote = await this.validator.PollVoteExtension(this.body);
|
2024-08-25 16:01:06 +02:00
|
|
|
|
2024-08-25 16:10:38 +02:00
|
|
|
if (callbacks["pub.versia:polls/Vote"]) {
|
|
|
|
|
return await callbacks["pub.versia:polls/Vote"](vote);
|
2024-08-25 16:01:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "Unfollow": {
|
|
|
|
|
const unfollow = await this.validator.Unfollow(this.body);
|
|
|
|
|
|
|
|
|
|
if (callbacks.unfollow) {
|
|
|
|
|
return await callbacks.unfollow(unfollow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
if (callbacks.unknown) {
|
|
|
|
|
return await callbacks.unknown(this.body);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
}
|
2024-05-29 02:14:02 +02:00
|
|
|
|
2024-08-25 16:01:06 +02:00
|
|
|
return undefined as ReturnType;
|
2024-05-29 01:38:47 +02:00
|
|
|
}
|
|
|
|
|
}
|