Fix gateway encoding Date objects as {} when using erlpack. Fixes NaN/NaN/NaN timestamps in desktop client

This commit is contained in:
Madeline 2023-02-21 11:56:56 +11:00
parent 5f553cc614
commit eee98516dd
4 changed files with 41 additions and 21 deletions

View File

@ -23,6 +23,7 @@ import {
Config, Config,
initDatabase, initDatabase,
initEvent, initEvent,
JSONReplacer,
Sentry, Sentry,
WebAuthn, WebAuthn,
} from "@fosscord/util"; } from "@fosscord/util";
@ -84,24 +85,7 @@ export class FosscordServer extends Server {
); );
} }
// Discord.com sends ISO strings with +00:00 extension, not Z this.app.set("json replacer", JSONReplacer);
// This causes issues with Python bot libs
this.app.set(
"json replacer",
function (
this: { [key: string]: unknown },
key: string,
value: unknown,
) {
if (this[key] instanceof Date) {
return (this[key] as Date)
.toISOString()
.replace("Z", "+00:00");
}
return value;
},
);
this.app.use(CORS); this.app.use(CORS);
this.app.use(BodyParser({ inflate: true, limit: "10mb" })); this.app.use(BodyParser({ inflate: true, limit: "10mb" }));

View File

@ -20,7 +20,7 @@ import { Payload, WebSocket } from "@fosscord/gateway";
import fs from "fs/promises"; import fs from "fs/promises";
import path from "path"; import path from "path";
import type { ErlpackType } from "@fosscord/util"; import { ErlpackType, JSONReplacer } from "@fosscord/util";
let erlpack: ErlpackType | null = null; let erlpack: ErlpackType | null = null;
try { try {
erlpack = require("erlpack") as ErlpackType; erlpack = require("erlpack") as ErlpackType;
@ -28,6 +28,21 @@ try {
// empty // empty
} }
// don't care
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const recurseJsonReplace = (json: any) => {
for (const key in json) {
// eslint-disable-next-line no-prototype-builtins
if (!json.hasOwnProperty(key)) continue;
json[key] = JSONReplacer.call(json, key, json[key]);
if (typeof json[key] == "object" && json[key] !== null)
json[key] = recurseJsonReplace(json[key]);
}
return json;
};
export function Send(socket: WebSocket, data: Payload) { export function Send(socket: WebSocket, data: Payload) {
if (process.env.WS_VERBOSE) if (process.env.WS_VERBOSE)
console.log(`[Websocket] Outgoing message: ${JSON.stringify(data)}`); console.log(`[Websocket] Outgoing message: ${JSON.stringify(data)}`);
@ -47,9 +62,14 @@ export function Send(socket: WebSocket, data: Payload) {
} }
let buffer: Buffer | string; let buffer: Buffer | string;
if (socket.encoding === "etf" && erlpack) buffer = erlpack.pack(data); if (socket.encoding === "etf" && erlpack) {
// Erlpack doesn't like Date objects, encodes them as {}
data = recurseJsonReplace(data);
buffer = erlpack.pack(data);
}
// TODO: encode circular object // TODO: encode circular object
else if (socket.encoding === "json") buffer = JSON.stringify(data); else if (socket.encoding === "json")
buffer = JSON.stringify(data, JSONReplacer);
else return; else return;
// TODO: compression // TODO: compression
if (socket.deflate) { if (socket.deflate) {

15
src/util/util/JSON.ts Normal file
View File

@ -0,0 +1,15 @@
// Discord.com sends ISO strings with +00:00 extension, not Z
// This causes issues with Python bot libs
const JSONReplacer = function (
this: { [key: string]: unknown },
key: string,
value: unknown,
) {
if (this[key] instanceof Date) {
return (this[key] as Date).toISOString().replace("Z", "+00:00");
}
return value;
};
export { JSONReplacer };

View File

@ -40,3 +40,4 @@ export * from "./TraverseDirectory";
export * from "./InvisibleCharacters"; export * from "./InvisibleCharacters";
export * from "./Sentry"; export * from "./Sentry";
export * from "./WebAuthn"; export * from "./WebAuthn";
export * from "./JSON";