iceshrimp/packages/backend/src/server/api/streaming.ts

92 lines
2.6 KiB
TypeScript
Raw Normal View History

2023-01-13 05:40:33 +01:00
import type * as http from "node:http";
import { EventEmitter } from "events";
import type { ParsedUrlQuery } from "querystring";
import * as websocket from "websocket";
2016-12-28 23:49:51 +01:00
2023-01-13 05:40:33 +01:00
import { subscriber as redisClient } from "@/db/redis.js";
import { Users } from "@/models/index.js";
import MainStreamConnection from "./stream/index.js";
import authenticate from "./authenticate.js";
import { apiLogger } from "@/server/api/logger.js";
import { MastodonStreamingConnection } from "@/server/api/mastodon/streaming/index.js";
export const streamingLogger = apiLogger.createSubLogger("streaming");
2016-12-28 23:49:51 +01:00
export const initializeStreamingServer = (server: http.Server) => {
// Init websocket server
2016-12-28 23:49:51 +01:00
const ws = new websocket.server({
2021-12-09 15:58:30 +01:00
httpServer: server,
2016-12-28 23:49:51 +01:00
});
2023-01-13 05:40:33 +01:00
ws.on("request", async (request) => {
const q = request.resourceURL.query as ParsedUrlQuery;
2023-02-11 00:41:19 +01:00
const headers = request.httpRequest.headers["sec-websocket-protocol"] || "";
const cred = q.i || q.access_token || headers;
const accessToken = cred.toString();
2020-04-26 04:19:57 +02:00
2023-01-13 05:40:33 +01:00
const [user, app] = await authenticate(
request.httpRequest.headers.authorization,
accessToken,
2023-01-13 05:40:33 +01:00
).catch((err) => {
request.reject(403, err.message);
return [];
});
if (typeof user === "undefined") {
return;
}
2017-06-08 18:03:54 +02:00
if (user?.isSuspended) {
request.reject(400);
return;
}
2018-11-11 16:31:09 +01:00
const connection = request.accept();
const ev = new EventEmitter();
async function onRedisMessage(_: string, data: string) {
const parsed = JSON.parse(data);
ev.emit(parsed.channel, parsed.message);
}
2023-01-13 05:40:33 +01:00
redisClient.on("message", onRedisMessage);
const host = `https://${request.host}`;
const prepareStream = q.stream?.toString();
const isMastodon = request.resourceURL.pathname?.endsWith('/api/v1/streaming');
if (isMastodon && !request.resourceURL.pathname?.startsWith('/mastodon')) {
streamingLogger.warn(`Received connect from mastodon on incorrect path: ${request.resourceURL.pathname}`);
}
const main = isMastodon
? new MastodonStreamingConnection(connection, ev, user, app, q)
: new MainStreamConnection(connection, ev, user, app, host, accessToken, prepareStream);
2016-12-28 23:49:51 +01:00
2023-01-13 05:40:33 +01:00
const intervalId = user
? setInterval(() => {
Users.update(user.id, {
lastActiveDate: new Date(),
});
}, 1000 * 60 * 5)
: null;
if (user) {
Users.update(user.id, {
lastActiveDate: new Date(),
});
}
2023-01-13 05:40:33 +01:00
connection.once("close", () => {
2018-07-30 00:20:27 +02:00
ev.removeAllListeners();
main.dispose();
2023-01-13 05:40:33 +01:00
redisClient.off("message", onRedisMessage);
if (intervalId) clearInterval(intervalId);
2016-12-28 23:49:51 +01:00
});
2023-01-13 05:40:33 +01:00
connection.on("message", async (data) => {
if (data.type === "utf8" && data.utf8Data === "ping") {
connection.send("pong");
2018-09-17 02:07:46 +02:00
}
});
2016-12-28 23:49:51 +01:00
});
};