1
0
mirror of https://github.com/spacebarchat/server.git synced 2024-11-21 18:02:33 +01:00

attempt to implement requestguildmembers

This commit is contained in:
Puyodead1 2023-12-07 23:12:46 -05:00
parent c4701a3299
commit 8313367fdb
No known key found for this signature in database
GPG Key ID: A4FA4FEC0DD353FC
6 changed files with 4388 additions and 4 deletions

File diff suppressed because it is too large Load Diff

View File

@ -82,6 +82,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
const identify: IdentifySchema = data.d;
this.capabilities = new Capabilities(identify.capabilities || 0);
this.large_threshold = identify.large_threshold || 250;
const user = await tryGetUserFromToken(identify.token, {
relations: ["relationships", "relationships.to", "settings"],

View File

@ -16,8 +16,128 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { WebSocket } from "@spacebar/gateway";
import { OPCODES, Payload, Send, WebSocket } from "@spacebar/gateway";
import { Member, RequestGuildMembersSchema, getDatabase } from "@spacebar/util";
import { check } from "./instanceOf";
export function onRequestGuildMembers(this: WebSocket) {
// return this.close(CLOSECODES.Unknown_error);
function partition(members: Member[], size: number) {
const chunks = [];
for (let i = 0; i < members.length; i += size) {
chunks.push(members.slice(i, i + size));
}
return chunks;
}
export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) {
check.call(this, RequestGuildMembersSchema, d);
const { guild_id, query, limit, presences, user_ids, nonce } =
d as RequestGuildMembersSchema;
if (query && user_ids) {
throw new Error("Cannot query and provide user ids");
}
if (query && !limit) {
throw new Error("Must provide limit when querying");
}
const takeLimit =
(query && query !== "") || user_ids
? limit && limit !== 0 && limit <= 1000
? limit
: 100
: undefined;
const member_count = await Member.count({
where: {
guild_id,
},
});
// TODO: if member count is >75k, only return members in voice plus the connecting users member object
// TODO: if member count is >large_threshold, send members who are online, have a role, have a nickname, or are in a voice channel
// TODO: if member count is <large_threshold, send all members
let members: Member[] = [];
if (member_count > 75000) {
// since we dont have voice channels yet, just return the connecting users member object
members = await Member.find({
where: {
guild_id,
user: {
id: this.user_id,
},
},
relations: ["user", "roles"],
});
} else if (member_count > this.large_threshold) {
try {
// find all members who are online, have a role, have a nickname, or are in a voice channel, as well as respecting the query and user_ids
const db = getDatabase();
if (!db) throw new Error("Database not initialized");
const repo = db.getRepository(Member);
const q = repo
.createQueryBuilder("member")
.where("member.guild_id = :guild_id", { guild_id })
.leftJoinAndSelect("member.roles", "role")
.leftJoinAndSelect("member.user", "user")
.leftJoinAndSelect("user.sessions", "session")
.andWhere(
`',' || member.roles || ',' NOT LIKE :everyoneRoleIdList`,
{ everyoneRoleIdList: `%,${guild_id},%` },
)
.andWhere("session.status != 'offline'")
.addOrderBy("user.username", "ASC")
.limit(takeLimit);
if (query && query !== "") {
q.andWhere(`user.username ILIKE :query`, {
query: `${query}%`,
});
} else if (user_ids) {
q.andWhere(`user.id IN (:...user_ids)`, { user_ids });
}
members = await q.getMany();
} catch (e) {
console.error(`request guild members`, e);
}
} else {
members = await Member.find({
where: {
guild_id,
...(user_ids && { user_id: user_ids }),
...(query && { username: { startsWith: query } }),
},
take: takeLimit,
relations: ["user", "roles"],
});
}
const chunks = partition(members, 1000);
for (const [i, chunk] of chunks.entries()) {
await Send(this, {
op: OPCODES.Dispatch,
s: this.sequence++,
t: "GUILD_MEMBERS_CHUNK",
d: {
guild_id,
members: chunk.map((member) => ({
...member,
roles: member.roles.map((role) => role.id),
user: member.user.toPublicUser(),
})),
chunk_index: i + 1,
chunk_count: chunks.length,
// not_found: []
// presences: []
nonce,
},
});
}
}

View File

@ -17,8 +17,8 @@
*/
import { Intents, ListenEventOpts, Permissions } from "@spacebar/util";
import WS from "ws";
import { Deflate, Inflate } from "fast-zlib";
import WS from "ws";
import { Capabilities } from "./Capabilities";
// import { Client } from "@spacebar/webrtc";
@ -43,4 +43,5 @@ export interface WebSocket extends WS {
listen_options: ListenEventOpts;
capabilities?: Capabilities;
// client?: Client;
large_threshold: number;
}

View File

@ -0,0 +1,35 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export interface RequestGuildMembersSchema {
guild_id: string;
query?: string;
limit?: number;
presences?: boolean;
user_ids?: string[];
nonce?: string;
}
export const RequestGuildMembersSchema = {
guild_id: String,
$query: String,
$limit: Number,
$presences: Boolean,
$user_ids: [] as string[],
$nonce: String,
};

View File

@ -58,6 +58,7 @@ export * from "./PurgeSchema";
export * from "./RegisterSchema";
export * from "./RelationshipPostSchema";
export * from "./RelationshipPutSchema";
export * from "./RequestGuildMembersSchema";
export * from "./RoleModifySchema";
export * from "./RolePositionUpdateSchema";
export * from "./SelectProtocolSchema";