import { ReconnectionStrategy } from '@fuman/net'; import { Middleware, Deferred } from '@fuman/utils'; import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'; import { default as Long } from 'long'; import { StorageManager } from '../storage/storage.js'; import { mtp, tl } from '../tl/index.js'; import { ICorePlatform } from '../types/platform.js'; import { DcOptions, ICryptoProvider, Logger } from '../utils/index.js'; import { ConfigManager } from './config-manager.js'; import { TelegramTransport } from './transports/abstract.js'; import { MultiSessionConnection } from './multi-session-connection.js'; export type ConnectionKind = 'main' | 'upload' | 'download' | 'downloadSmall'; /** * Params passed into {@link NetworkManager} by {@link TelegramClient}. * This type is intended for internal usage only. */ export interface NetworkManagerParams { storage: StorageManager; crypto: ICryptoProvider; log: Logger; platform: ICorePlatform; apiId: number; initConnectionOptions?: Partial>; transport: TelegramTransport; reconnectionStrategy?: ReconnectionStrategy; disableUpdates?: boolean; testMode: boolean; layer: number; useIpv6: boolean; readerMap: TlReaderMap; writerMap: TlWriterMap; isPremium: boolean; emitError: (err: Error) => void; onUpdate: (upd: tl.TypeUpdates, fromClient: boolean) => void; onUsable: () => void; onConnecting: () => void; onNetworkChanged: (connected: boolean) => void; stopSignal: AbortSignal; } export type ConnectionCountDelegate = (kind: ConnectionKind, dcId: number, isPremium: boolean) => number; /** * Additional params passed into {@link NetworkManager} by the user * that customize the behavior of the manager */ export interface NetworkManagerExtraParams { /** * Whether to use PFS (Perfect Forward Secrecy) for all connections. * This is disabled by default */ usePfs?: boolean; /** * Connection count for each connection kind. * The function should be pure to avoid unexpected behavior. * * Defaults to TDLib logic: * - main: 0 (which stands for "handle internally, based on tmp_sessions value") * - upload: if premium or dc id is other than 2 or 4, then 8, otherwise 4 * - download: if premium then 8, otherwise 2 * - downloadSmall: 2 * * Non-zero value for `main` is **for advanced users only** * as it may lead to unexpected behavior, and is generally not recommended * because of unnecessary extra load on both the server and the client as well as * increased possibility of encountering AUTH_KEY_DUPLICATED errors. */ connectionCount?: ConnectionCountDelegate; /** * Idle timeout for non-main connections, in ms * * @default 60000 (60 seconds). */ inactivityTimeout?: number; /** * List of middlewares to use for the network manager * * > **Note**: these middlewares apply to **outgoing requests only**. * > If you need to handle incoming updates, use a {@link Dispatcher} instead. */ middlewares?: Middleware[]; /** * Ping interval in milliseconds. * * @default 60000 (1 minute) */ pingInterval?: number; } /** Options that can be customized when making an RPC call */ export interface RpcCallOptions { /** * If the call results in a `FLOOD_WAIT_X` error, * the maximum amount of time to wait before retrying. * * If set to `0`, the call will not be retried. * * Only applies when the flood waiter middleware is enabled. */ floodSleepThreshold?: number; /** * If the call results in an internal server error or a flood wait, * the maximum amount of times to retry the call. * * Only applies when the flood waiter middleware and/or * internal errors handler middleware is enabled. */ maxRetryCount?: number; /** * Timeout for the call, in milliseconds. * * @default Infinity */ timeout?: number; /** * **ADVANCED** * * Kind of connection to use for this call. * * @default 'main' */ kind?: ConnectionKind; /** * **ADVANCED** * * ID of the DC to use for this call */ dcId?: number; /** * **ADVANCED** * * DC connection manager to use for this call. * Overrides `dcId` if set, unless `businessConnectionId` is passed. */ manager?: DcConnectionManager; /** * Abort signal for the call. */ abortSignal?: AbortSignal; /** * Whether we should not retry on -503 errors and throw {@link MtTimeoutError} immediately instead. * * Useful for methods like `messages.getBotCallbackAnswer` that reliably return * -503 in case the upstream bot failed to respond. * * Only applies if the internal error handler middleware is enabled, * otherwise -503 is always thrown. */ throw503?: boolean; /** * Whether the `X_MIGRATE_%d` errors should be handled locally on request level * instead of changing the default datacenter for the entire client. * * Useful for `invokeWithBusinessConnection`, as it returns a `USER_MIGRATE_%d` error * that is in fact not related to the user, but to the specific request. */ localMigrate?: boolean; /** * Business connection on behalf of which this call should be made. * * This wraps the request with `invokeWithBusinessConnection`, * resolves the correct DC automatically, and overrides `dcId`, * `manager` and `localMigrate`. */ businessConnectionId?: string; /** * Some requests should be processed consecutively, and not in parallel. * Using the same `chainId` for multiple requests will ensure that they are processed in the order * of calling `.call()`. * * Particularly useful for `messages.sendMessage` and alike. */ chainId?: string | number; } export interface RpcCallMiddlewareContext { request: tl.RpcMethod; manager: NetworkManager; params?: RpcCallOptions; } export type RpcCallMiddleware = Middleware; /** * Wrapper over all connection pools for a single DC. */ export declare class DcConnectionManager { /** Network manager instance */ readonly manager: NetworkManager; /** DC ID */ readonly dcId: number; /** DC options to use */ readonly _dcs: DcOptions; /** Whether this DC is the primary one */ isPrimary: boolean; private _salts; private _log; /** Main connection pool */ main: MultiSessionConnection; /** Upload connection pool */ upload: MultiSessionConnection; /** Download connection pool */ download: MultiSessionConnection; /** Download connection pool (for small files) */ downloadSmall: MultiSessionConnection; private get _mainCountOverride(); constructor( /** Network manager instance */ manager: NetworkManager, /** DC ID */ dcId: number, /** DC options to use */ _dcs: DcOptions, /** Whether this DC is the primary one */ isPrimary?: boolean); private _setupMulti; setIsPrimary(isPrimary: boolean): void; setIsPremium(isPremium: boolean): void; loadKeys(forcePfs?: boolean): Promise; setMainConnectionCount(count: number): void; destroy(): Promise; } /** * Class that manages all connections to Telegram servers. */ export declare class NetworkManager { readonly params: NetworkManagerParams & NetworkManagerExtraParams; readonly config: ConfigManager; readonly _log: Logger; readonly _storage: StorageManager; readonly _initConnectionParams: tl.RawInitConnectionRequest; readonly _transport: TelegramTransport; readonly _reconnectionStrategy: ReconnectionStrategy; readonly _connectionCount: ConnectionCountDelegate; protected readonly _dcConnections: Map; protected _primaryDc?: DcConnectionManager; protected _primaryDcRecreationPromise?: Deferred; private _updateHandler; constructor(params: NetworkManagerParams & NetworkManagerExtraParams, config: ConfigManager); private _findDcOptions; private _resetOnNetworkChange?; private _switchPrimaryDc; private _dcCreationPromise; _getOtherDc(dcId: number): Promise; /** * Perform initial connection to the default DC * * @param defaultDcs Default DCs to connect to */ connect(defaultDcs: DcOptions): Promise; private _pendingExports; private _exportAuthTo; setIsPremium(isPremium: boolean): void; notifyLoggedIn(auth: tl.auth.TypeAuthorization | tl.RawUser): tl.RawUser; notifyLoggedOut(): void; notifyNetworkChanged(connected: boolean): void; resetSessions(): void; private _onConfigChanged; changePrimaryDc(newDc: number): Promise; readonly call: (message: T, params?: RpcCallOptions) => Promise; private _businessConnectionDcs; private _getBusinessConnectionDcId; private _composeCall; private _call; changeTransport(transport: TelegramTransport): Promise; getPoolSize(kind: ConnectionKind, dcId?: number): number; getPrimaryDcId(): number; destroy(): Promise; getMtprotoMessageId(): Long; recreateDc(dcId: number): Promise; }