diff --git a/gateway/src/Server.ts b/gateway/src/Server.ts
index a50c24a6..944174c7 100644
--- a/gateway/src/Server.ts
+++ b/gateway/src/Server.ts
@@ -1,7 +1,7 @@
import "missing-native-js-functions";
import dotenv from "dotenv";
dotenv.config();
-import { Config, db, initEvent, RabbitMQ } from "@fosscord/util";
+import { closeDatabase, Config, initDatabase, initEvent, RabbitMQ } from "@fosscord/util";
import { Server as WebSocketServer } from "ws";
import { Connection } from "./events/Connection";
import http from "http";
@@ -38,15 +38,8 @@ export class Server {
this.ws.on("error", console.error);
}
- async setupSchema() {
- // TODO: adjust expireAfterSeconds -> lower
- await Promise.all([db.collection("events").createIndex({ created_at: 1 }, { expireAfterSeconds: 60 })]);
- }
-
async start(): Promise<void> {
- // @ts-ignore
- await (db as Promise<Connection>);
- await this.setupSchema();
+ await initDatabase();
await Config.init();
await initEvent();
if (!this.server.listening) {
@@ -56,7 +49,7 @@ export class Server {
}
async stop() {
- await db.close();
+ closeDatabase();
this.server.close();
}
}
diff --git a/gateway/src/listener/listener.ts b/gateway/src/listener/listener.ts
index 51082586..75ca1680 100644
--- a/gateway/src/listener/listener.ts
+++ b/gateway/src/listener/listener.ts
@@ -1,22 +1,21 @@
import {
- db,
- Event,
- UserModel,
+ User,
getPermission,
Permissions,
- ChannelModel,
+ Channel,
RabbitMQ,
- EVENT,
listenEvent,
EventOpts,
ListenEventOpts,
+ Member,
} from "@fosscord/util";
import { OPCODES } from "../util/Constants";
import { Send } from "../util/Send";
import WebSocket from "../util/WebSocket";
import "missing-native-js-functions";
-import { ConsumeMessage } from "amqplib";
-import { Channel } from "amqplib";
+import { Channel as AMQChannel } from "amqplib";
+import { In, Like } from "../../../util/node_modules/typeorm";
+import { Recipient } from "../../../util/dist/entities/Recipient";
// TODO: close connection on Invalidated Token
// TODO: check intent
@@ -27,15 +26,15 @@ import { Channel } from "amqplib";
// TODO: use already queried guilds/channels of Identify and don't fetch them again
export async function setupListener(this: WebSocket) {
- const user = await UserModel.findOne({ id: this.user_id }, { guilds: true }).exec();
- const channels = await ChannelModel.find(
- { $or: [{ recipient_ids: this.user_id }, { guild_id: { $in: user.guilds } }] },
- { id: true, permission_overwrites: true }
- ).exec();
- const dm_channels = channels.filter((x) => !x.guild_id);
+ const members = await Member.find({ where: { id: this.user_id } });
+ const guild_ids = members.map((x) => x.guild_id);
+ const user = await User.findOneOrFail({ id: this.user_id });
+ const recipients = await Recipient.find({ where: { id: this.user_id }, relations: ["channel"] });
+ const channels = await Channel.find({ guild_id: In(guild_ids) });
+ const dm_channels = recipients.map((x) => x.channel);
const guild_channels = channels.filter((x) => x.guild_id);
- const opts: { acknowledge: boolean; channel?: Channel } = { acknowledge: true };
+ const opts: { acknowledge: boolean; channel?: AMQChannel } = { acknowledge: true };
const consumer = consume.bind(this);
if (RabbitMQ.connection) {
@@ -50,7 +49,7 @@ export async function setupListener(this: WebSocket) {
this.events[channel.id] = await listenEvent(channel.id, consumer, opts);
}
- for (const guild of user.guilds) {
+ for (const guild of guild_ids) {
// contains guild and dm channels
getPermission(this.user_id, guild)
diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts
index 91f7f675..958f1b73 100644
--- a/gateway/src/opcodes/Identify.ts
+++ b/gateway/src/opcodes/Identify.ts
@@ -1,17 +1,16 @@
import { CLOSECODES, Payload, OPCODES } from "../util/Constants";
import WebSocket from "../util/WebSocket";
import {
- ChannelModel,
+ Channel,
checkToken,
- GuildModel,
+ Guild,
Intents,
- MemberDocument,
- MemberModel,
+ Member,
ReadyEventData,
- UserModel,
- toObject,
+ User,
EVENTEnum,
Config,
+ dbConnection,
} from "@fosscord/util";
import { setupListener } from "../listener/listener";
import { IdentifySchema } from "../schema/Identify";
@@ -19,6 +18,8 @@ import { Send } from "../util/Send";
// import experiments from "./experiments.json";
const experiments: any = [];
import { check } from "./instanceOf";
+import { Like } from "../../../util/node_modules/typeorm";
+import { Recipient } from "../../../util/dist/entities/Recipient";
// TODO: bot sharding
// TODO: check priviliged intents
@@ -54,17 +55,22 @@ export async function onIdentify(this: WebSocket, data: Payload) {
}
}
- const members = toObject(await MemberModel.find({ id: this.user_id }).exec());
+ const members = await Member.find({
+ where: { id: this.user_id },
+ relations: ["guild", "guild.channels", "guild.emojis", "guild.roles", "guild.stickers", "user", "roles"],
+ });
const merged_members = members.map((x: any) => {
- const y = { ...x, user_id: x.id };
- delete y.settings;
- delete y.id;
- return [y];
- }) as MemberDocument[][];
+ return [x];
+ }) as Member[][];
+ const guilds = members.map((x) => ({ ...x.guild, joined_at: x.joined_at }));
const user_guild_settings_entries = members.map((x) => x.settings);
- const channels = await ChannelModel.find({ recipient_ids: this.user_id }).exec();
- const user = await UserModel.findOne({ id: this.user_id }).exec();
+ const recipients = await Recipient.find({
+ where: { id: this.user_id },
+ relations: ["channel", "channel.recipients"],
+ });
+ const channels = recipients.map((x) => x.channel);
+ const user = await User.findOneOrFail({ id: this.user_id });
if (!user) return this.close(CLOSECODES.Authentication_failed);
const public_user = {
@@ -74,12 +80,9 @@ export async function onIdentify(this: WebSocket, data: Payload) {
public_flags: user.public_flags,
avatar: user.avatar,
bot: user.bot,
+ bio: user.bio,
};
- const guilds = await GuildModel.find({ id: { $in: user.guilds } })
- .populate({ path: "joined_at", match: { id: this.user_id } })
- .exec();
-
const privateUser = {
avatar: user.avatar,
mobile: user.mobile,
@@ -99,14 +102,15 @@ export async function onIdentify(this: WebSocket, data: Payload) {
bot: user.bot,
accent_color: user.accent_color || 0,
banner: user.banner,
+ bio: user.bio,
};
const d: ReadyEventData = {
v: 8,
user: privateUser,
- user_settings: user.user_settings,
+ user_settings: user.settings,
// @ts-ignore
- guilds: toObject(guilds).map((x) => {
+ guilds: guilds.map((x) => {
// @ts-ignore
x.guild_hashes = {
channels: { omitted: false, hash: "y4PV2fZ0gmo" },
@@ -118,7 +122,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
}),
guild_experiments: [], // TODO
geo_ordered_rtc_regions: [], // TODO
- relationships: user.user_data.relationships,
+ relationships: user.relationships,
read_state: {
// TODO
entries: [],
@@ -130,12 +134,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
partial: false, // TODO partial
version: 642,
},
- // @ts-ignore
- private_channels: toObject(channels).map((x: ChannelDocument) => {
- x.recipient_ids = x.recipients.map((y: any) => y.id);
- delete x.recipients;
- return x;
- }),
+ private_channels: channels,
session_id: "", // TODO
analytics_token: "", // TODO
connected_accounts: [], // TODO
@@ -144,17 +143,12 @@ export async function onIdentify(this: WebSocket, data: Payload) {
consented: false, // TODO
},
},
- country_code: user.user_settings.locale,
+ country_code: user.settings.locale,
friend_suggestion_count: 0, // TODO
// @ts-ignore
experiments: experiments, // TODO
guild_join_requests: [], // TODO what is this?
- users: [
- public_user,
- ...toObject(channels)
- .map((x: any) => x.recipients)
- .flat(),
- ].unique(), // TODO
+ users: [public_user].unique(), // TODO
merged_members: merged_members,
// shard // TODO: only for bots sharding
// application // TODO for applications
diff --git a/gateway/src/opcodes/LazyRequest.ts b/gateway/src/opcodes/LazyRequest.ts
index 63075e5a..9f514f5f 100644
--- a/gateway/src/opcodes/LazyRequest.ts
+++ b/gateway/src/opcodes/LazyRequest.ts
@@ -18,45 +18,43 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
permissions.hasThrow("VIEW_CHANNEL");
// MongoDB query to retrieve all hoisted roles and join them with the members and users collection
- const roles = toObject(
- await db
- .collection("roles")
- .aggregate([
- {
- $match: {
- guild_id,
- // hoist: true // TODO: also match @everyone role
- },
+ const roles = await db
+ .collection("roles")
+ .aggregate([
+ {
+ $match: {
+ guild_id,
+ // hoist: true // TODO: also match @everyone role
},
- { $sort: { position: 1 } },
- {
- $lookup: {
- from: "members",
- let: { id: "$id" },
- pipeline: [
- { $match: { $expr: { $in: ["$$id", "$roles"] } } },
- { $limit: 100 },
- {
- $lookup: {
- from: "users",
- let: { user_id: "$id" },
- pipeline: [
- { $match: { $expr: { $eq: ["$id", "$$user_id"] } } },
- { $project: PublicUserProjection },
- ],
- as: "user",
- },
- },
- {
- $unwind: "$user",
+ },
+ { $sort: { position: 1 } },
+ {
+ $lookup: {
+ from: "members",
+ let: { id: "$id" },
+ pipeline: [
+ { $match: { $expr: { $in: ["$$id", "$roles"] } } },
+ { $limit: 100 },
+ {
+ $lookup: {
+ from: "users",
+ let: { user_id: "$id" },
+ pipeline: [
+ { $match: { $expr: { $eq: ["$id", "$$user_id"] } } },
+ { $project: PublicUserProjection },
+ ],
+ as: "user",
},
- ],
- as: "members",
- },
+ },
+ {
+ $unwind: "$user",
+ },
+ ],
+ as: "members",
},
- ])
- .toArray()
- );
+ },
+ ])
+ .toArray();
const groups = roles.map((x) => ({ id: x.id === guild_id ? "online" : x.id, count: x.members.length }));
const member_count = roles.reduce((a, b) => b.members.length + a, 0);
diff --git a/gateway/src/schema/Activity.ts b/gateway/src/schema/Activity.ts
index d7e0a30b..f1665efd 100644
--- a/gateway/src/schema/Activity.ts
+++ b/gateway/src/schema/Activity.ts
@@ -1,10 +1,47 @@
-import { ActivityBodySchema } from "@fosscord/util";
import { EmojiSchema } from "./Emoji";
export const ActivitySchema = {
afk: Boolean,
status: String,
- $activities: [ActivityBodySchema],
+ $activities: [
+ {
+ name: String,
+ type: Number,
+ $url: String,
+ $created_at: Date,
+ $timestamps: [
+ {
+ $start: Number,
+ $end: Number,
+ },
+ ],
+ $application_id: String,
+ $details: String,
+ $state: String,
+ $emoji: {
+ $name: String,
+ $id: String,
+ $amimated: Boolean,
+ },
+ $party: {
+ $id: String,
+ $size: [Number, Number],
+ },
+ $assets: {
+ $large_image: String,
+ $large_text: String,
+ $small_image: String,
+ $small_text: String,
+ },
+ $secrets: {
+ $join: String,
+ $spectate: String,
+ $match: String,
+ },
+ $instance: Boolean,
+ $flags: String,
+ },
+ ],
$since: Number, // unix time (in milliseconds) of when the client went idle, or null if the client is not idle
};
@@ -42,7 +79,7 @@ export interface ActivitySchema {
match?: string; // the secret for a specific instanced match
};
instance?: boolean;
- flags: bigint; // activity flags OR d together, describes what the payload includes
+ flags: string; // activity flags OR d together, describes what the payload includes
}
];
since?: number; // unix time (in milliseconds) of when the client went idle, or null if the client is not idle
|