import { Database } from './../database' ; import { Log } from './../log' ; import { PrivateChannel } from './private-channel' ; export class PresenceChannel extends PrivateChannel { /**
     * Database instance.
     */ db : Database ; param { any } io param { any } stats param { any } options constructor ( protected io , protected stats , protected options ) { super ( io , stats , options ) ; this . db = new Database ( options ) ; } param { string } channel param { any [ ] } members param { any } socket return { Promise < any > } protected removeInactive ( channel , members , socket ) { return new Promise ( ( resolve , reject ) => { this . io . of ( this . getNspForSocket ( socket ) ) . in ( channel ) . allSockets ( ) . then ( clients => { members = members || [ ] ; members = members . filter ( member => { return clients . has ( member . socketId ) ; } ) ; this . db . set ( `${ this . getNspForSocket ( socket ) }:${ channel }:members` , members ) ; resolve ( members ) ; } , error => Log . error ( error ) ) ; } ) ; } param { any } socket param { any } data return { Promise < any > } join ( socket , data ) { return this . signatureIsValid ( socket , data ) . then ( isValid => { if ( ! isValid ) { return ; } let member = data . channel_data ; try { member = JSON . parse ( member ) ; } catch ( e ) { } if ( ! member ) { if ( this . options . development ) { Log . error ( 'Unable to join channel. Member data for presence channel missing. Maybe the authentication host and/or url is not right?' ) ; } return ; } socket . join ( data . channel ) ; this . isMember ( data . channel , member , socket ) . then ( isMember => { this . getMembers ( this . getNspForSocket ( socket ) , data . channel ) . then ( members => { members = members || [ ] ; member . socketId = socket . id ; if ( ! isMember ) { members . push ( member ) ; this . db . set ( `${ this . getNspForSocket ( socket ) }:${ data . channel }:members` , members ) ; members = [ ... members . reduce ( ( map , member ) => map . set ( member . user_id , member ) , new Map ) . values ( ) ] ; this . onSubscribed ( socket , data . channel , members ) ; this . onJoin ( socket , data . channel , member ) ; } return member ; } , error => Log . error ( error ) ) ; } , ( ) => Log . error ( 'Error retrieving pressence channel members.' ) ) ; } ) ; } param { any } socket param { string } channel return { void } leave ( socket , channel ) { this . getMembers ( this . getNspForSocket ( socket ) , channel ) . then ( members => { members = members || [ ] ; let currentMember = members . find ( member => member . socketId === socket . id ) ; if ( currentMember ) { let otherMembers = members . filter ( member => member . socketId !== currentMember . socketId ) ; delete currentMember . socketId ; this . db . set ( `${ this . getNspForSocket ( socket ) }:${ channel }:members` , otherMembers ) ; this . onLeave ( socket , channel , currentMember ) ; } } , error => Log . error ( error ) ) ; } param { any } socket param { string } channel param { any } member return { void } onJoin ( socket , channel , member ) { super . onJoin ( socket , channel , member ) ; this . io . of ( this . getNspForSocket ( socket ) ) . sockets . get ( socket . id ) . broadcast . to ( channel ) . emit ( 'presence:joining' , channel , member ) ; } param { any } socket param { string } channel param { any } member return { void } onLeave ( socket , channel , member ) { this . io . of ( this . getNspForSocket ( socket ) ) . to ( channel ) . emit ( 'presence:leaving' , channel , member ) ; } param { any } socket param { string } channel param { any [ ] } members return { void } onSubscribed ( socket , channel , members ) { this . io . of ( this . getNspForSocket ( socket ) ) . to ( socket . id ) . emit ( 'presence:subscribed' , channel , members ) ; } param { string } namespace param { string } channel return { Promise < any > } getMembers ( namespace , channel ) { return this . db . get ( `${ namespace }:${ channel }:members` ) ; } param { string } channel param { any } member param { any } socket return { Promise < boolean > } isMember ( channel , member , socket ) { return new Promise ( ( resolve , reject ) => { this . getMembers ( this . getNspForSocket ( socket ) , channel ) . then ( members => { this . removeInactive ( channel , members , socket ) . then ( members => { let search = members . filter ( m => m . user_id === member . user_id ) ; if ( search && search . length ) { resolve ( true ) ; } resolve ( false ) ; } ) ; } , error => Log . error ( error ) ) ; } ) ; } param { any } socket param { any } data return { string } protected getDataToSignForToken ( socket , data ) { return `${ socket . id }:${ data . channel }:${ data . channel_data }` ; } }