mirror of
https://github.com/spacebarchat/server.git
synced 2026-07-28 18:29:26 +00:00
remove first/last
This commit is contained in:
@@ -17,16 +17,7 @@
|
||||
*/
|
||||
|
||||
import { WebSocket } from "@spacebar/gateway";
|
||||
import {
|
||||
emitEvent,
|
||||
PresenceUpdateEvent,
|
||||
PrivateSessionProjection,
|
||||
Session,
|
||||
SessionsReplace,
|
||||
User,
|
||||
VoiceState,
|
||||
VoiceStateUpdateEvent,
|
||||
} from "@spacebar/util";
|
||||
import { emitEvent, PresenceUpdateEvent, PrivateSessionProjection, Session, SessionsReplace, User, VoiceState, VoiceStateUpdateEvent } from "@spacebar/util";
|
||||
|
||||
export async function Close(this: WebSocket, code: number, reason: Buffer) {
|
||||
console.log("[WebSocket] closed", code, reason.toString());
|
||||
@@ -44,11 +35,7 @@ export async function Close(this: WebSocket, code: number, reason: Buffer) {
|
||||
});
|
||||
|
||||
// clear the voice state for this session if user was in voice channel
|
||||
if (
|
||||
voiceState &&
|
||||
voiceState.session_id === this.session_id &&
|
||||
voiceState.channel_id
|
||||
) {
|
||||
if (voiceState && voiceState.session_id === this.session_id && voiceState.channel_id) {
|
||||
const prevGuildId = voiceState.guild_id;
|
||||
const prevChannelId = voiceState.channel_id;
|
||||
|
||||
@@ -83,7 +70,7 @@ export async function Close(this: WebSocket, code: number, reason: Buffer) {
|
||||
user_id: this.user_id,
|
||||
data: sessions,
|
||||
} as SessionsReplace);
|
||||
const session = sessions.first() || {
|
||||
const session = sessions[0] || {
|
||||
activities: [],
|
||||
client_status: {},
|
||||
status: "offline",
|
||||
|
||||
@@ -16,28 +16,11 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
getDatabase,
|
||||
getPermission,
|
||||
listenEvent,
|
||||
Member,
|
||||
Role,
|
||||
Session,
|
||||
User,
|
||||
Presence,
|
||||
Channel,
|
||||
Permissions,
|
||||
} from "@spacebar/util";
|
||||
import {
|
||||
WebSocket,
|
||||
Payload,
|
||||
handlePresenceUpdate,
|
||||
OPCODES,
|
||||
Send,
|
||||
} from "@spacebar/gateway";
|
||||
import { getDatabase, getPermission, listenEvent, Member, Role, Session, User, Presence, Channel, Permissions } from "@spacebar/util";
|
||||
import { WebSocket, Payload, handlePresenceUpdate, OPCODES, Send } from "@spacebar/gateway";
|
||||
import murmur from "murmurhash-js/murmurhash3_gc";
|
||||
import { check } from "./instanceOf";
|
||||
import { LazyRequestSchema } from "@spacebar/schemas"
|
||||
import { LazyRequestSchema } from "@spacebar/schemas";
|
||||
|
||||
// TODO: only show roles/members that have access to this channel
|
||||
// TODO: config: to list all members (even those who are offline) sorted by role, or just those who are online
|
||||
@@ -53,14 +36,10 @@ const getMostRelevantSession = (sessions: Session[]) => {
|
||||
};
|
||||
// sort sessions by relevance
|
||||
sessions = sessions.sort((a, b) => {
|
||||
return (
|
||||
statusMap[a.status] -
|
||||
statusMap[b.status] +
|
||||
((a.activities?.length ?? 0) - (b.activities?.length ?? 0)) * 2
|
||||
);
|
||||
return statusMap[a.status] - statusMap[b.status] + ((a.activities?.length ?? 0) - (b.activities?.length ?? 0)) * 2;
|
||||
});
|
||||
|
||||
return sessions.first();
|
||||
return sessions[0];
|
||||
};
|
||||
|
||||
async function getMembers(guild_id: string, range: [number, number]) {
|
||||
@@ -79,10 +58,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
|
||||
.leftJoinAndSelect("member.user", "user")
|
||||
.leftJoinAndSelect("user.sessions", "session")
|
||||
.addSelect("user.settings")
|
||||
.addSelect(
|
||||
"CASE WHEN session.status IS NULL OR session.status = 'offline' OR session.status = 'invisible' THEN 0 ELSE 1 END",
|
||||
"_status",
|
||||
)
|
||||
.addSelect("CASE WHEN session.status IS NULL OR session.status = 'offline' OR session.status = 'invisible' THEN 0 ELSE 1 END", "_status")
|
||||
.orderBy("_status", "DESC")
|
||||
.addOrderBy("role.position", "DESC")
|
||||
.addOrderBy("user.username", "ASC")
|
||||
@@ -118,9 +94,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
|
||||
const offlineItems = [];
|
||||
|
||||
for (const role of member_roles) {
|
||||
const [role_members, other_members] = members.partition(
|
||||
(m: Member) => !!m.roles.find((r) => r.id === role.id),
|
||||
);
|
||||
const [role_members, other_members] = members.partition((m: Member) => !!m.roles.find((r) => r.id === role.id));
|
||||
const group = {
|
||||
count: role_members.length,
|
||||
id: role.id === guild_id ? "online" : role.id,
|
||||
@@ -130,13 +104,9 @@ async function getMembers(guild_id: string, range: [number, number]) {
|
||||
groups.push(group);
|
||||
|
||||
for (const member of role_members) {
|
||||
const roles = member.roles
|
||||
.filter((x: Role) => x.id !== guild_id)
|
||||
.map((x: Role) => x.id);
|
||||
const roles = member.roles.filter((x: Role) => x.id !== guild_id).map((x: Role) => x.id);
|
||||
|
||||
const session: Session | undefined = getMostRelevantSession(
|
||||
member.user.sessions,
|
||||
);
|
||||
const session: Session | undefined = getMostRelevantSession(member.user.sessions);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
@@ -157,11 +127,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
|
||||
},
|
||||
};
|
||||
|
||||
if (
|
||||
!session ||
|
||||
session.status == "invisible" ||
|
||||
session.status == "offline"
|
||||
) {
|
||||
if (!session || session.status == "invisible" || session.status == "offline") {
|
||||
item.member.presence.status = "offline";
|
||||
offlineItems.push(item);
|
||||
group.count--;
|
||||
@@ -188,24 +154,14 @@ async function getMembers(guild_id: string, range: [number, number]) {
|
||||
items,
|
||||
groups,
|
||||
range,
|
||||
members: items
|
||||
.map((x) =>
|
||||
"member" in x
|
||||
? { ...x.member, settings: undefined }
|
||||
: undefined,
|
||||
)
|
||||
.filter((x) => !!x),
|
||||
members: items.map((x) => ("member" in x ? { ...x.member, settings: undefined } : undefined)).filter((x) => !!x),
|
||||
};
|
||||
}
|
||||
|
||||
async function subscribeToMemberEvents(this: WebSocket, user_id: string) {
|
||||
if (this.events[user_id]) return false; // already subscribed as friend
|
||||
if (this.member_events[user_id]) return false; // already subscribed in member list
|
||||
this.member_events[user_id] = await listenEvent(
|
||||
user_id,
|
||||
handlePresenceUpdate.bind(this),
|
||||
this.listen_options,
|
||||
);
|
||||
this.member_events[user_id] = await listenEvent(user_id, handlePresenceUpdate.bind(this), this.listen_options);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -213,8 +169,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
|
||||
const startTime = Date.now();
|
||||
// TODO: check data
|
||||
check.call(this, LazyRequestSchema, d);
|
||||
const { guild_id, typing, channels, activities, members } =
|
||||
d as LazyRequestSchema;
|
||||
const { guild_id, typing, channels, activities, members } = d as LazyRequestSchema;
|
||||
|
||||
if (members) {
|
||||
// Client has requested a PRESENCE_UPDATE for specific member
|
||||
@@ -222,10 +177,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
|
||||
await Promise.all([
|
||||
members.map(async (x) => {
|
||||
if (!x) return;
|
||||
const didSubscribe = await subscribeToMemberEvents.call(
|
||||
this,
|
||||
x,
|
||||
);
|
||||
const didSubscribe = await subscribeToMemberEvents.call(this, x);
|
||||
if (!didSubscribe) return;
|
||||
|
||||
// if we didn't subscribe just now, this is a new subscription
|
||||
@@ -257,7 +209,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
|
||||
|
||||
if (!channels) throw new Error("Must provide channel ranges");
|
||||
|
||||
const channel_id = Object.keys(channels || {}).first();
|
||||
const channel_id = Object.keys(channels || {})[0];
|
||||
if (!channel_id) return;
|
||||
|
||||
const permissions = await getPermission(this.user_id, guild_id, channel_id);
|
||||
@@ -267,9 +219,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
|
||||
if (!Array.isArray(ranges)) throw new Error("Not a valid Array");
|
||||
|
||||
const member_count = await Member.count({ where: { guild_id } });
|
||||
const ops = await Promise.all(
|
||||
ranges.map((x) => getMembers(guild_id, x as [number, number])),
|
||||
);
|
||||
const ops = await Promise.all(ranges.map((x) => getMembers(guild_id, x as [number, number])));
|
||||
|
||||
let list_id = "everyone";
|
||||
|
||||
@@ -282,10 +232,8 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
|
||||
channel.permission_overwrites.forEach((overwrite) => {
|
||||
const { id, allow, deny } = overwrite;
|
||||
|
||||
if (BigInt(allow) & Permissions.FLAGS.VIEW_CHANNEL)
|
||||
perms.push(`allow:${id}`);
|
||||
else if (BigInt(deny) & Permissions.FLAGS.VIEW_CHANNEL)
|
||||
perms.push(`deny:${id}`);
|
||||
if (BigInt(allow) & Permissions.FLAGS.VIEW_CHANNEL) perms.push(`allow:${id}`);
|
||||
else if (BigInt(deny) & Permissions.FLAGS.VIEW_CHANNEL) perms.push(`deny:${id}`);
|
||||
});
|
||||
|
||||
if (perms.length > 0) {
|
||||
@@ -317,9 +265,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
|
||||
op: "SYNC",
|
||||
range: x.range,
|
||||
})),
|
||||
online_count:
|
||||
member_count -
|
||||
(groups.find((x) => x.id == "offline")?.count ?? 0),
|
||||
online_count: member_count - (groups.find((x) => x.id == "offline")?.count ?? 0),
|
||||
member_count,
|
||||
id: list_id,
|
||||
guild_id,
|
||||
@@ -327,7 +273,5 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
|
||||
},
|
||||
});
|
||||
|
||||
console.log(
|
||||
`[Gateway] LAZY_REQUEST ${guild_id} ${channel_id} took ${Date.now() - startTime}ms`,
|
||||
);
|
||||
console.log(`[Gateway] LAZY_REQUEST ${guild_id} ${channel_id} took ${Date.now() - startTime}ms`);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import moduleAlias from "module-alias";
|
||||
moduleAlias();
|
||||
import './Array';
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import "./Array";
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
describe("Array extensions", () => {
|
||||
|
||||
it("containsAll", () => {
|
||||
const arr = [1, 2, 3, 4, 5];
|
||||
assert(arr.containsAll([1, 2]));
|
||||
@@ -27,8 +26,14 @@ describe("Array extensions", () => {
|
||||
|
||||
it("single", () => {
|
||||
const arr = [1, 2, 3, 4, 5];
|
||||
assert.strictEqual(arr.single((n) => n === 3), 3);
|
||||
assert.strictEqual(arr.single((n) => n === 6), null);
|
||||
assert.strictEqual(
|
||||
arr.single((n) => n === 3),
|
||||
3,
|
||||
);
|
||||
assert.strictEqual(
|
||||
arr.single((n) => n === 6),
|
||||
null,
|
||||
);
|
||||
assert.throws(() => arr.single((n) => n > 2));
|
||||
});
|
||||
|
||||
@@ -55,18 +60,6 @@ describe("Array extensions", () => {
|
||||
assert.deepEqual(arr, [1, 2, 4, 5]);
|
||||
});
|
||||
|
||||
it("first", () => {
|
||||
const arr = [1, 2, 3];
|
||||
assert.strictEqual(arr.first(), 1);
|
||||
assert.strictEqual([].first(), undefined);
|
||||
});
|
||||
|
||||
it("last", () => {
|
||||
const arr = [1, 2, 3];
|
||||
assert.strictEqual(arr.last(), 3);
|
||||
assert.strictEqual([].last(), undefined);
|
||||
});
|
||||
|
||||
it("distinct", () => {
|
||||
const arr = [1, 2, 2, 3, 3, 3];
|
||||
assert.deepEqual(arr.distinct(), [1, 2, 3]);
|
||||
@@ -75,8 +68,14 @@ describe("Array extensions", () => {
|
||||
|
||||
it("distinctBy", () => {
|
||||
const arr = [{ id: 1 }, { id: 2 }, { id: 1 }, { id: 3 }];
|
||||
assert.deepEqual(arr.distinctBy((x) => x.id), [{ id: 1 }, { id: 2 }, { id: 3 }]);
|
||||
assert.deepEqual([].distinctBy((x) => x), []);
|
||||
assert.deepEqual(
|
||||
arr.distinctBy((x) => x.id),
|
||||
[{ id: 1 }, { id: 2 }, { id: 3 }],
|
||||
);
|
||||
assert.deepEqual(
|
||||
[].distinctBy((x) => x),
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
it("intersect", () => {
|
||||
@@ -98,5 +97,4 @@ describe("Array extensions", () => {
|
||||
// @ts-expect-error
|
||||
assert.deepEqual([].except(arr2), []);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,8 +24,6 @@ declare global {
|
||||
forEachAsync(callback: (elem: T, index: number, array: T[]) => Promise<void>): Promise<void>;
|
||||
filterAsync(callback: (elem: T, index: number, array: T[]) => Promise<boolean>): Promise<T[]>;
|
||||
remove(item: T): void;
|
||||
first(): T | undefined;
|
||||
last(): T | undefined;
|
||||
distinct(): T[];
|
||||
distinctBy<K>(key: (elem: T) => K): T[];
|
||||
intersect(other: T[]): T[];
|
||||
@@ -126,21 +124,14 @@ if (!Array.prototype.remove)
|
||||
Array.prototype.remove = function <T>(this: T[], item: T) {
|
||||
return arrayRemove.call(this, item);
|
||||
};
|
||||
if (!Array.prototype.first)
|
||||
Array.prototype.first = function <T>(this: T[]) {
|
||||
return arrayFirst.call(this);
|
||||
};
|
||||
if (!Array.prototype.last)
|
||||
Array.prototype.last = function <T>(this: T[]) {
|
||||
return arrayLast.call(this);
|
||||
};
|
||||
|
||||
if (!Array.prototype.distinct)
|
||||
Array.prototype.distinct = function <T>(this: T[]) {
|
||||
return arrayDistinct.call(this);
|
||||
};
|
||||
if (!Array.prototype.distinctBy)
|
||||
Array.prototype.distinctBy = function <T, K>(this: T[], key: (elem: T) => K) {
|
||||
return arrayDistinctBy.call(this, key as ((elem: unknown) => unknown));
|
||||
return arrayDistinctBy.call(this, key as (elem: unknown) => unknown);
|
||||
};
|
||||
if (!Array.prototype.intersect)
|
||||
Array.prototype.intersect = function <T>(this: T[], other: T[]) {
|
||||
@@ -149,4 +140,4 @@ if (!Array.prototype.intersect)
|
||||
if (!Array.prototype.except)
|
||||
Array.prototype.except = function <T>(this: T[], other: T[]) {
|
||||
return arrayExcept.call(this, other);
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user