import type { EventBuilder } from "../events/common" ; import { Api } from "../tl" ; import type { TelegramClient } from "../" ; import bigInt from "big-integer" ; import { UpdateConnectionState } from "../network" ; import type { Raw } from "../events" ; import { utils } from "../index" ; import { getRandomInt , returnBigInt , sleep } from "../Helpers" ; const PING_INTERVAL = 9000 ; const PING_TIMEOUT = 10000 ; const PING_FAIL_ATTEMPTS = 3 ; const PING_FAIL_INTERVAL = 100 ; const PING_DISCONNECT_DELAY = 60000 ; /**
 If this exception is raised in any of the handlers for a given event,
 it will stop the execution of all other registered event handlers.
 It can be seen as the ``StopIteration`` in a for loop but for events.
 */ export class StopPropagation extends Error { } hidden export function on ( client , event ? ) { return ( f ) => { client . addEventHandler ( f , event ) ; return f ; } ; } hidden export function addEventHandler ( client , callback , event ? ) { if ( event == undefined ) { const raw = require ( "../events/Raw" ) . Raw ; event = new raw ( { } ) as Raw ; } event . client = client ; client . _eventBuilders . push ( [ event , callback ] ) ; } hidden export function removeEventHandler ( client , callback , event ) { client . _eventBuilders = client . _eventBuilders . filter ( function ( item ) { return item [ 0 ] !== event && item [ 1 ] !== callback ; } ) ; } hidden export function listEventHandlers ( client ) { return client . _eventBuilders ; } hidden export function catchUp ( ) { } hidden export function _handleUpdate ( client , update ) { if ( typeof update === "number" ) { if ( [ - 1 , 0 , 1 ] . includes ( update ) ) { _dispatchUpdate ( client , { update : new UpdateConnectionState ( update ) , } ) ; return ; } } client . _entityCache . add ( update ) ; client . session . processEntities ( update ) ; if ( update instanceof Api . Updates || update instanceof Api . UpdatesCombined ) { const entities = new Map ( ) ; for ( const x of [ ... update . users , ... update . chats ] ) { entities . set ( utils . getPeerId ( x ) , x ) ; } for ( const u of update . updates ) { _processUpdate ( client , u , update . updates , entities ) ; } } else if ( update instanceof Api . UpdateShort ) { _processUpdate ( client , update . update , null ) ; } else { _processUpdate ( client , update , null ) ; } } hidden export function _processUpdate ( client , update , others , entities ? ) { update . _entities = entities || new Map ( ) ; const args = { update : update , others : others , } ; _dispatchUpdate ( client , args ) ; } hidden export async function _dispatchUpdate ( client , args ) { for ( const [ builder , callback ] of client . _eventBuilders ) { if ( ! builder . resolved ) { await builder . resolve ( client ) ; } let event = args . update ; if ( event ) { if ( ! client . _selfInputPeer ) { client . getMe ( true ) . catch ( ( ) => { } ) ; } if ( ! ( event instanceof UpdateConnectionState ) ) { } event = builder . build ( event , callback , client . _selfInputPeer ? returnBigInt ( client . _selfInputPeer . userId ) : undefined ) ; if ( event ) { if ( "_eventName" in event ) { event . _setClient ( client ) ; event . originalUpdate = args . update ; event . _entities = args . update . _entities ; } const filter = await builder . filter ( event ) ; if ( ! filter ) { continue ; } try { await callback ( event ) ; } catch ( e ) { if ( e instanceof StopPropagation ) { break ; } console . error ( e ) ; } } } } } hidden export async function _updateLoop ( client ) { while ( ! client . _destroyed ) { await sleep ( PING_INTERVAL ) ; if ( client . _reconnecting ) { continue ; } try { await attempts ( ( ) => { return timeout ( client . _sender ! . send ( new Api . PingDelayDisconnect ( { pingId : bigInt ( getRandomInt ( Number . MIN_SAFE_INTEGER , Number . MAX_SAFE_INTEGER ) ) , disconnectDelay : PING_DISCONNECT_DELAY , } ) ) , PING_TIMEOUT ) ; } , PING_FAIL_ATTEMPTS , PING_FAIL_INTERVAL ) ; } catch ( err ) { client . _log . error ( err ) ; if ( client . _reconnecting ) { continue ; } await client . disconnect ( ) ; await client . connect ( ) ; } if ( new Date ( ) . getTime ( ) - ( client . _lastRequest || 0 ) > 30 * 60 * 1000 ) { try { await client . invoke ( new Api . updates . GetState ( ) ) ; } catch ( e ) { } } } await client . disconnect ( ) ; } hidden async function attempts ( cb , times , pause ) { for ( let i = 0 ; i < times ; i ++ ) { try { return await cb ( ) ; } catch ( err ) { if ( i === times - 1 ) { throw err ; } await sleep ( pause ) ; } } return undefined ; } hidden function timeout ( promise , ms ) { return Promise . race ( [ promise , sleep ( ms ) . then ( ( ) => Promise . reject ( new Error ( "TIMEOUT" ) ) ) , ] ) ; }