@@ -3,7 +3,7 @@ import { redisClient } from '../common/redis';
33import { UserStatus } from '../types/User' ;
44import { getSuspensionDetails , getUserWithAccount , isIpBanned } from '../services/User/User' ;
55import { USER_CACHE_KEY_STRING , ALLOWED_IP_KEY_SET , CONNECTED_SOCKET_ID_KEY_SET , CONNECTED_USER_ID_KEY_STRING , GOOGLE_DRIVE_ACCESS_TOKEN , USER_PRESENCE_KEY_STRING , SESSION_ID_TO_USER_ID } from './CacheKeys' ;
6- import { prisma } from '../common/database' ;
6+ import { prisma , publicUserExcludeFields } from '../common/database' ;
77import { generateId } from '../common/flakeId' ;
88import { removeDuplicates } from '../common/utils' ;
99import { hasBit , USER_BADGES } from '../common/Bitwise' ;
@@ -38,6 +38,100 @@ interface GetUserPresencesOpts {
3838 limitActivities ?: boolean ;
3939}
4040
41+ export const getServerMembersOnline = async ( userId : string , serverIds : string [ ] , currentServerId ?: string ) => {
42+ const selfMembers = await prisma . serverMember . findMany ( {
43+ where : {
44+ serverId : { in : serverIds } ,
45+ userId,
46+ } ,
47+ include : {
48+ user : {
49+ select : {
50+ ...publicUserExcludeFields ,
51+ profile : { select : { font : true , clan : { select : { tag : true , icon : true , serverId : true } } } } ,
52+ lastOnlineAt : true ,
53+ lastOnlineStatus : true ,
54+ } ,
55+ } ,
56+ } ,
57+ } ) ;
58+
59+ const processedUserIds = new Set < string > ( ) ;
60+ const membersList = [ ] ;
61+
62+ if ( currentServerId ) {
63+ const currentServerMembers = await prisma . serverMember . findMany ( {
64+ where : {
65+ serverId : currentServerId ,
66+ userId : { not : userId } ,
67+ } ,
68+ include : {
69+ user : {
70+ select : {
71+ ...publicUserExcludeFields ,
72+ profile : { select : { font : true , clan : { select : { tag : true , icon : true , serverId : true } } } } ,
73+ lastOnlineAt : true ,
74+ lastOnlineStatus : true ,
75+ } ,
76+ } ,
77+ } ,
78+ } ) ;
79+
80+ membersList . push ( ...currentServerMembers ) ;
81+
82+ for ( const member of currentServerMembers ) {
83+ processedUserIds . add ( member . userId ) ;
84+ }
85+ }
86+
87+ const backgroundServerIds = currentServerId ? serverIds . filter ( ( id ) => id !== currentServerId ) : serverIds ;
88+
89+ if ( ! backgroundServerIds . length ) {
90+ return [ ...selfMembers , ...membersList ] ;
91+ }
92+
93+ let cursor = 0 ;
94+
95+ do {
96+ const { cursor : nextCursor , keys } = await redisClient . scan ( cursor , {
97+ MATCH : USER_PRESENCE_KEY_STRING ( '*' ) ,
98+ COUNT : 500 ,
99+ } ) ;
100+ cursor = Number ( nextCursor ) ;
101+
102+ if ( ! keys . length ) continue ;
103+
104+ const onlineUserIds = keys . map ( ( key ) => key . replace ( 'user:presence:' , '' ) ) . filter ( ( id ) => id !== userId && ! processedUserIds . has ( id ) ) ;
105+
106+ if ( ! onlineUserIds . length ) continue ;
107+
108+ for ( const id of onlineUserIds ) {
109+ processedUserIds . add ( id ) ;
110+ }
111+
112+ const batch = await prisma . serverMember . findMany ( {
113+ where : {
114+ serverId : { in : backgroundServerIds } ,
115+ userId : { in : onlineUserIds } ,
116+ } ,
117+ include : {
118+ user : {
119+ select : {
120+ ...publicUserExcludeFields ,
121+ profile : { select : { font : true , clan : { select : { tag : true , icon : true , serverId : true } } } } ,
122+ lastOnlineAt : true ,
123+ lastOnlineStatus : true ,
124+ } ,
125+ } ,
126+ } ,
127+ } ) ;
128+
129+ membersList . push ( ...batch ) ;
130+ } while ( cursor !== 0 ) ;
131+
132+ return [ ...selfMembers , ...membersList ] ;
133+ } ;
134+
41135export async function getUserPresences ( opts : GetUserPresencesOpts ) : Promise < Presence [ ] > {
42136 const userIds = opts . userIds ;
43137 const includeSocketId = opts . includeSocketId === undefined ? false : opts . includeSocketId ;
0 commit comments