✨ Member List
This commit is contained in:
		
							parent
							
								
									671091a13f
								
							
						
					
					
						commit
						e434334a21
					
				
							
								
								
									
										14
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -9,7 +9,7 @@ | ||||
| 			"version": "1.0.0", | ||||
| 			"license": "ISC", | ||||
| 			"dependencies": { | ||||
| 				"@fosscord/server-util": "^1.0.7", | ||||
| 				"@fosscord/server-util": "^1.2.1", | ||||
| 				"dotenv": "^8.2.0", | ||||
| 				"jsonwebtoken": "^8.5.1", | ||||
| 				"lambert-server": "^1.1.7", | ||||
| @ -30,9 +30,9 @@ | ||||
| 			} | ||||
| 		}, | ||||
| 		"node_modules/@fosscord/server-util": { | ||||
| 			"version": "1.0.7", | ||||
| 			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.0.7.tgz", | ||||
| 			"integrity": "sha512-3vBPCt+lwMS7wk+iRvv+V8qBSnEdNifpPxX97Lfjje/TSWI17Kg29y3BmcGJRC5TwIHTLFtgpNLmZmruhv7ziQ==", | ||||
| 			"version": "1.2.1", | ||||
| 			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.2.1.tgz", | ||||
| 			"integrity": "sha512-NAAmwDizkjR52O6ZUds+XOH8ydjo///T2EH0scuFF3HtAMjD8Yphgo7+GIKrNt5FfkTR3ma0ycrZLZe0TBE+1A==", | ||||
| 			"dependencies": { | ||||
| 				"@types/jsonwebtoken": "^8.5.0", | ||||
| 				"@types/mongoose-autopopulate": "^0.10.1", | ||||
| @ -2134,9 +2134,9 @@ | ||||
| 	}, | ||||
| 	"dependencies": { | ||||
| 		"@fosscord/server-util": { | ||||
| 			"version": "1.0.7", | ||||
| 			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.0.7.tgz", | ||||
| 			"integrity": "sha512-3vBPCt+lwMS7wk+iRvv+V8qBSnEdNifpPxX97Lfjje/TSWI17Kg29y3BmcGJRC5TwIHTLFtgpNLmZmruhv7ziQ==", | ||||
| 			"version": "1.2.1", | ||||
| 			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.2.1.tgz", | ||||
| 			"integrity": "sha512-NAAmwDizkjR52O6ZUds+XOH8ydjo///T2EH0scuFF3HtAMjD8Yphgo7+GIKrNt5FfkTR3ma0ycrZLZe0TBE+1A==", | ||||
| 			"requires": { | ||||
| 				"@types/jsonwebtoken": "^8.5.0", | ||||
| 				"@types/mongoose-autopopulate": "^0.10.1", | ||||
|  | ||||
| @ -5,16 +5,15 @@ | ||||
| 	"main": "index.js", | ||||
| 	"scripts": { | ||||
| 		"test": "echo \"Error: no test specified\" && exit 1", | ||||
| 		"start": "npm run build:util && npm run build && node dist/", | ||||
| 		"start": "npm run build && node dist/", | ||||
| 		"build": "npx tsc -b .", | ||||
| 		"build:util": "npx tsc -b ./node_modules/@fosscord/server-util/", | ||||
| 		"dev": "tsnd --respawn src/index.ts" | ||||
| 	}, | ||||
| 	"keywords": [], | ||||
| 	"author": "Fosscord", | ||||
| 	"license": "ISC", | ||||
| 	"dependencies": { | ||||
| 		"@fosscord/server-util": "^1.0.7", | ||||
| 		"@fosscord/server-util": "^1.2.1", | ||||
| 		"dotenv": "^8.2.0", | ||||
| 		"jsonwebtoken": "^8.5.1", | ||||
| 		"lambert-server": "^1.1.7", | ||||
|  | ||||
| @ -6,6 +6,9 @@ import { Server as WebSocketServer } from "ws"; | ||||
| import { Connection } from "./events/Connection"; | ||||
| import Config from "./util/Config"; | ||||
| 
 | ||||
| // TODO: only listen/start the server if everything got initalized
 | ||||
| // https://www.npmjs.com/package/ws use "External HTTP/S server" and listen manually at the end of listen()
 | ||||
| 
 | ||||
| var port = Number(process.env.PORT); | ||||
| if (isNaN(port)) port = 3002; | ||||
| 
 | ||||
| @ -14,6 +17,7 @@ export class Server { | ||||
| 	constructor() { | ||||
| 		this.ws = new WebSocketServer({ | ||||
| 			port, | ||||
| 
 | ||||
| 			maxPayload: 4096, | ||||
| 			// perMessageDeflate: {
 | ||||
| 			// 	zlibDeflateOptions: {
 | ||||
|  | ||||
| @ -17,7 +17,7 @@ export interface DispatchOpts { | ||||
| 	guilds: Array<string>; | ||||
| } | ||||
| 
 | ||||
| function getPipeline(this: WebSocket, guilds: string[], channels: string[]) { | ||||
| function getPipeline(this: WebSocket, guilds: string[], channels: string[] = []) { | ||||
| 	if (this.shard_count) { | ||||
| 		guilds = guilds.filter((x) => (BigInt(x) >> 22n) % this.shard_count === this.shard_id); | ||||
| 	} | ||||
| @ -54,12 +54,7 @@ export async function setupListener(this: WebSocket) { | ||||
| export async function dispatch(this: WebSocket, document: Event, { eventStream, guilds }: DispatchOpts) { | ||||
| 	var permission = new Permissions("ADMINISTRATOR"); // default permission for dms
 | ||||
| 	console.log("event", document); | ||||
| 
 | ||||
| 	if (document.guild_id) { | ||||
| 		if (!this.intents.has("GUILDS")) return; | ||||
| 		const channel_id = document.channel_id || document.data?.channel_id; | ||||
| 		permission = await getPermission(this.user_id, document.guild_id, channel_id); | ||||
| 	} | ||||
| 	var channel_id = document.channel_id || document.data?.channel_id; | ||||
| 
 | ||||
| 	if (document.event === "GUILD_CREATE") { | ||||
| 		guilds.push(document.data.id); | ||||
| @ -67,12 +62,19 @@ export async function dispatch(this: WebSocket, document: Event, { eventStream, | ||||
| 	} else if (document.event === "GUILD_DELETE") { | ||||
| 		guilds.remove(document.guild_id); | ||||
| 		eventStream.changeStream(getPipeline.call(this, guilds)); | ||||
| 	} else if (document.event === "CHANNEL_DELETE") channel_id = null; | ||||
| 	if (document.guild_id && !this.intents.has("GUILDS")) return; | ||||
| 
 | ||||
| 	try { | ||||
| 		permission = await getPermission(this.user_id, document.guild_id, channel_id); | ||||
| 	} catch (e) { | ||||
| 		permission = new Permissions(); | ||||
| 	} | ||||
| 
 | ||||
| 	// check intents: https://discord.com/developers/docs/topics/gateway#gateway-intents
 | ||||
| 	switch (document.event) { | ||||
| 		case "GUILD_CREATE": | ||||
| 		case "GUILD_DELETE": | ||||
| 		case "GUILD_CREATE": | ||||
| 		case "GUILD_UPDATE": | ||||
| 		case "GUILD_ROLE_CREATE": | ||||
| 		case "GUILD_ROLE_UPDATE": | ||||
|  | ||||
| @ -1,5 +1,13 @@ | ||||
| // @ts-nocheck WIP
 | ||||
| import { db, getPermission, MemberModel, MongooseCache, PublicUserProjection, RoleModel } from "@fosscord/server-util"; | ||||
| import { | ||||
| 	db, | ||||
| 	getPermission, | ||||
| 	MemberModel, | ||||
| 	MongooseCache, | ||||
| 	PublicUserProjection, | ||||
| 	RoleModel, | ||||
| 	toObject, | ||||
| } from "@fosscord/server-util"; | ||||
| import { LazyRequest } from "../schema/LazyRequest"; | ||||
| import { OPCODES, Payload } from "../util/Constants"; | ||||
| import { Send } from "../util/Send"; | ||||
| @ -9,7 +17,6 @@ import { check } from "./instanceOf"; | ||||
| // TODO: config: if want to list all members (even those who are offline) sorted by role, or just those who are online
 | ||||
| 
 | ||||
| export async function onLazyRequest(this: WebSocket, { d }: Payload) { | ||||
| 	return; // WIP
 | ||||
| 	// TODO: check data
 | ||||
| 	check.call(this, LazyRequest, d); | ||||
| 	const { guild_id, typing, channels, activities } = d as LazyRequest; | ||||
| @ -17,37 +24,63 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) { | ||||
| 	const permissions = await getPermission(this.user_id, guild_id); | ||||
| 
 | ||||
| 	// MongoDB query to retrieve all hoisted roles and join them with the members and users collection
 | ||||
| 	const roles = await db | ||||
| 		.collection("roles") | ||||
| 		.aggregate([ | ||||
| 			{ $match: { guild_id, hoist: true } }, | ||||
| 			{ $sort: { position: 1 } }, | ||||
| 			{ | ||||
| 				$lookup: { | ||||
| 					from: "members", | ||||
| 					let: { id: "$id" }, | ||||
| 					pipeline: [ | ||||
| 						{ $match: { $expr: { $in: ["$$id", "$roles"] } } }, | ||||
| 						{ $limit: 1 }, | ||||
| 						{ | ||||
| 							$lookup: { | ||||
| 								from: "users", | ||||
| 								let: { user_id: "$id" }, | ||||
| 								pipeline: [ | ||||
| 									{ $match: { $expr: { $eq: ["$id", "$$user_id"] } } }, | ||||
| 									{ $project: PublicUserProjection }, | ||||
| 								], | ||||
| 								as: "user", | ||||
| 							}, | ||||
| 						}, | ||||
| 					], | ||||
| 					as: "members", | ||||
| 	const roles = toObject( | ||||
| 		await db | ||||
| 			.collection("roles") | ||||
| 			.aggregate([ | ||||
| 				{ | ||||
| 					$match: { | ||||
| 						guild_id, | ||||
| 						// hoist: true // TODO: also match @everyone role
 | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		]) | ||||
| 		.toArray(); | ||||
| 				{ $sort: { position: 1 } }, | ||||
| 				{ | ||||
| 					$lookup: { | ||||
| 						from: "members", | ||||
| 						let: { id: "$id" }, | ||||
| 						pipeline: [ | ||||
| 							{ $match: { $expr: { $in: ["$$id", "$roles"] } } }, | ||||
| 							{ $limit: 1 }, | ||||
| 							{ | ||||
| 								$lookup: { | ||||
| 									from: "users", | ||||
| 									let: { user_id: "$id" }, | ||||
| 									pipeline: [ | ||||
| 										{ $match: { $expr: { $eq: ["$id", "$$user_id"] } } }, | ||||
| 										{ $project: PublicUserProjection }, | ||||
| 									], | ||||
| 									as: "user", | ||||
| 								}, | ||||
| 							}, | ||||
| 							{ | ||||
| 								$unwind: "$user", | ||||
| 							}, | ||||
| 						], | ||||
| 						as: "members", | ||||
| 					}, | ||||
| 				}, | ||||
| 			]) | ||||
| 			.toArray() | ||||
| 	); | ||||
| 
 | ||||
| 	Send(this, { | ||||
| 	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); | ||||
| 	const items = []; | ||||
| 
 | ||||
| 	for (const role of roles) { | ||||
| 		items.push({ | ||||
| 			group: { | ||||
| 				count: role.members.length, | ||||
| 				id: role.id, | ||||
| 			}, | ||||
| 		}); | ||||
| 		for (const member of role.members) { | ||||
| 			items.push({ member }); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return Send(this, { | ||||
| 		op: OPCODES.Dispatch, | ||||
| 		s: this.sequence++, | ||||
| 		t: "GUILD_MEMBER_LIST_UPDATE", | ||||
| @ -56,14 +89,14 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) { | ||||
| 				{ | ||||
| 					range: [0, 99], | ||||
| 					op: "SYNC", | ||||
| 					items: [{ group: { id: "online", count: 0 } }], | ||||
| 					items: items, | ||||
| 				}, | ||||
| 			], | ||||
| 			online_count: 1, | ||||
| 			member_count: 1, | ||||
| 			online_count: member_count, // TODO count online count
 | ||||
| 			member_count, | ||||
| 			id: "everyone", | ||||
| 			guild_id, | ||||
| 			groups: [{ id: "online", count: 1 }], | ||||
| 			groups, | ||||
| 		}, | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,14 @@ | ||||
| import { CLOSECODES, Payload } from "../util/Constants"; | ||||
| import { Send } from "../util/Send"; | ||||
| 
 | ||||
| import WebSocket from "../util/WebSocket"; | ||||
| 
 | ||||
| export function onResume(this: WebSocket, data: Payload) { | ||||
| 	return this.close(CLOSECODES.Invalid_session); | ||||
| export async function onResume(this: WebSocket, data: Payload) { | ||||
| 	console.log("Got Resume -> cancel not implemented"); | ||||
| 	await Send(this, { | ||||
| 		op: 9, | ||||
| 		d: false, | ||||
| 	}); | ||||
| 
 | ||||
| 	// return this.close(CLOSECODES.Invalid_session);
 | ||||
| } | ||||
|  | ||||
| @ -1,15 +1,17 @@ | ||||
| export interface LazyRequest { | ||||
| 	activities: boolean; | ||||
| 	channels: Record<string, [number, number]>; | ||||
| 	guild_id: string; | ||||
| 	threads: boolean; | ||||
| 	typing: true; | ||||
| 	channels?: Record<string, [number, number]>; | ||||
| 	activities?: boolean; | ||||
| 	threads?: boolean; | ||||
| 	typing?: true; | ||||
| 	members?: any[]; | ||||
| } | ||||
| 
 | ||||
| export const LazyRequest = { | ||||
| 	activities: Boolean, | ||||
| 	channels: Object, | ||||
| 	guild_id: String, | ||||
| 	threads: Boolean, | ||||
| 	typing: Boolean, | ||||
| 	$activities: Boolean, | ||||
| 	$channels: Object, | ||||
| 	$typing: Boolean, | ||||
| 	$threads: Boolean, | ||||
| 	$members: [] as any[], | ||||
| }; | ||||
|  | ||||
| @ -3,6 +3,7 @@ export const VoiceStateUpdateSchema = { | ||||
| 	channel_id: String, | ||||
| 	self_mute: Boolean, | ||||
| 	self_deaf: Boolean, | ||||
| 	self_video: Boolean, | ||||
| }; | ||||
| 
 | ||||
| export interface VoiceStateUpdateSchema { | ||||
| @ -10,4 +11,5 @@ export interface VoiceStateUpdateSchema { | ||||
| 	channel_id: string; | ||||
| 	self_mute: boolean; | ||||
| 	self_deaf: boolean; | ||||
| 	self_video: boolean; | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Flam3rboy
						Flam3rboy