import { getPermission , Permissions , RabbitMQ , listenEvent , EventOpts , ListenEventOpts , Member , EVENTEnum , Relationship , RelationshipType , } from "@fosscord/util" ; import { OPCODES } from "../util/Constants" ; import { Send } from "../util/Send" ; import { WebSocket } from "@fosscord/gateway" ; import "missing-native-js-functions" ; import { Channel as AMQChannel } from "amqplib" ; import { Recipient } from "@fosscord/util" ; export function handlePresenceUpdate ( this , { event , acknowledge , data } ) { acknowledge ?. ( ) ; if ( event === EVENTEnum . PresenceUpdate ) { return Send ( this , { op : OPCODES . Dispatch , t : event , d : data , s : this . sequence ++ , } ) ; } } export async function setupListener ( this ) { const [ members , recipients , relationships ] = await Promise . all ( [ Member . find ( { where : { id : this . user_id } , relations : [ "guild" , "guild.channels" ] , } ) , Recipient . find ( { where : { user_id : this . user_id , closed : false } , relations : [ "channel" ] , } ) , Relationship . find ( { from_id : this . user_id , type : RelationshipType . friends , } ) , ] ) ; const guilds = members . map ( ( x ) => x . guild ) ; const dm_channels = recipients . map ( ( x ) => x . channel ) ; const opts = { acknowledge : true , } ; this . listen_options = opts ; const consumer = consume . bind ( this ) ; if ( RabbitMQ . connection ) { opts . channel = await RabbitMQ . connection . createChannel ( ) ; opts . channel . queues = { } ; } this . events [ this . user_id ] = await listenEvent ( this . user_id , consumer , opts ) ; relationships . forEach ( async ( relationship ) => { this . events [ relationship . to_id ] = await listenEvent ( relationship . to_id , handlePresenceUpdate . bind ( this ) , opts ) ; } ) ; dm_channels . forEach ( async ( channel ) => { this . events [ channel . id ] = await listenEvent ( channel . id , consumer , opts ) ; } ) ; guilds . forEach ( async ( guild ) => { const permission = await getPermission ( this . user_id , guild . id ) ; this . permissions [ guild . id ] = permission ; this . events [ guild . id ] = await listenEvent ( guild . id , consumer , opts ) ; guild . channels . forEach ( async ( channel ) => { if ( permission . overwriteChannel ( channel . permission_overwrites ! ) . has ( "VIEW_CHANNEL" ) ) { this . events [ channel . id ] = await listenEvent ( channel . id , consumer , opts ) ; } } ) ; } ) ; this . once ( "close" , ( ) => { if ( opts . channel ) opts . channel . close ( ) ; else { Object . values ( this . events ) . forEach ( ( x ) => x ( ) ) ; Object . values ( this . member_events ) . forEach ( ( x ) => x ( ) ) ; } } ) ; } async function consume ( this , opts ) { const { data , event } = opts ; let id = data . id as string ; const permission = this . permissions [ id ] || new Permissions ( "ADMINISTRATOR" ) ; const consumer = consume . bind ( this ) ; const listenOpts = opts as ListenEventOpts ; opts . acknowledge ?. ( ) ; switch ( event ) { case "GUILD_MEMBER_REMOVE" : this . member_events [ data . user . id ] ?. ( ) ; delete this . member_events [ data . user . id ] ; case "GUILD_MEMBER_ADD" : if ( this . member_events [ data . user . id ] ) break ; this . member_events [ data . user . id ] = await listenEvent ( data . user . id , handlePresenceUpdate . bind ( this ) , this . listen_options ) ; break ; case "GUILD_MEMBER_REMOVE" : if ( ! this . member_events [ data . user . id ] ) break ; this . member_events [ data . user . id ] ( ) ; break ; case "RELATIONSHIP_REMOVE" : case "CHANNEL_DELETE" : case "GUILD_DELETE" : delete this . events [ id ] ; opts . cancel ( ) ; break ; case "CHANNEL_CREATE" : if ( ! permission . overwriteChannel ( data . permission_overwrites ) . has ( "VIEW_CHANNEL" ) ) { return ; } this . events [ id ] = await listenEvent ( id , consumer , listenOpts ) ; break ; case "RELATIONSHIP_ADD" : this . events [ data . user . id ] = await listenEvent ( data . user . id , handlePresenceUpdate . bind ( this ) , this . listen_options ) ; break ; case "GUILD_CREATE" : this . events [ id ] = await listenEvent ( id , consumer , listenOpts ) ; break ; case "CHANNEL_UPDATE" : const exists = this . events [ id ] ; if ( permission . overwriteChannel ( data . permission_overwrites ) . has ( "VIEW_CHANNEL" ) ) { if ( exists ) break ; this . events [ id ] = await listenEvent ( id , consumer , listenOpts ) ; } else { if ( ! exists ) return ; opts . cancel ( id ) ; delete this . events [ id ] ; } break ; } switch ( event ) { case "INVITE_CREATE" : case "INVITE_DELETE" : case "GUILD_INTEGRATIONS_UPDATE" : if ( ! permission . has ( "MANAGE_GUILD" ) ) return ; break ; case "WEBHOOKS_UPDATE" : if ( ! permission . has ( "MANAGE_WEBHOOKS" ) ) return ; break ; case "GUILD_MEMBER_ADD" : case "GUILD_MEMBER_REMOVE" : case "GUILD_MEMBER_UPDATE" : case "PRESENCE_UPDATE" : break ; case "GUILD_BAN_ADD" : case "GUILD_BAN_REMOVE" : if ( ! permission . has ( "BAN_MEMBERS" ) ) break ; break ; case "VOICE_STATE_UPDATE" : case "MESSAGE_CREATE" : case "MESSAGE_DELETE" : case "MESSAGE_DELETE_BULK" : case "MESSAGE_UPDATE" : case "CHANNEL_PINS_UPDATE" : case "MESSAGE_REACTION_ADD" : case "MESSAGE_REACTION_REMOVE" : case "MESSAGE_REACTION_REMOVE_ALL" : case "MESSAGE_REACTION_REMOVE_EMOJI" : case "TYPING_START" : if ( ! permission . has ( "VIEW_CHANNEL" ) ) return ; break ; case "GUILD_CREATE" : case "GUILD_DELETE" : case "GUILD_UPDATE" : case "GUILD_ROLE_CREATE" : case "GUILD_ROLE_UPDATE" : case "GUILD_ROLE_DELETE" : case "CHANNEL_CREATE" : case "CHANNEL_DELETE" : case "CHANNEL_UPDATE" : case "GUILD_EMOJIS_UPDATE" : case "READY" : case "USER_UPDATE" : case "APPLICATION_COMMAND_CREATE" : case "APPLICATION_COMMAND_DELETE" : case "APPLICATION_COMMAND_UPDATE" : default : break ; } Send ( this , { op : OPCODES . Dispatch , t : event , d : data , s : this . sequence ++ , } ) ; }