chore(core): various improvements

This commit is contained in:
alina 🌸 2023-12-16 19:52:44 +03:00
parent 886858d9de
commit 7a0d8ecef2
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
3 changed files with 189 additions and 187 deletions

View file

@ -7,16 +7,15 @@ import { __tlReaderMap as defaultReaderMap } from '@mtcute/tl/binary/reader.js'
import { __tlWriterMap as defaultWriterMap } from '@mtcute/tl/binary/writer.js' import { __tlWriterMap as defaultWriterMap } from '@mtcute/tl/binary/writer.js'
import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime' import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'
import { BaseTelegramClientOptions } from './base-client.types.js'
import { ConfigManager } from './network/config-manager.js' import { ConfigManager } from './network/config-manager.js'
import { ReconnectionStrategy, SessionConnection, TransportFactory } from './network/index.js' import { SessionConnection, TransportFactory } from './network/index.js'
import { NetworkManager, NetworkManagerExtraParams, RpcCallOptions } from './network/network-manager.js' import { NetworkManager, RpcCallOptions } from './network/network-manager.js'
import { PersistentConnectionParams } from './network/persistent-connection.js'
import { ITelegramStorage } from './storage/index.js' import { ITelegramStorage } from './storage/index.js'
import { MustEqual } from './types/index.js' import { MustEqual } from './types/index.js'
import { import {
ControllablePromise, ControllablePromise,
createControllablePromise, createControllablePromise,
CryptoProviderFactory,
defaultCryptoProviderFactory, defaultCryptoProviderFactory,
defaultProductionDc, defaultProductionDc,
defaultProductionIpv6Dc, defaultProductionIpv6Dc,
@ -26,176 +25,11 @@ import {
ICryptoProvider, ICryptoProvider,
LogManager, LogManager,
readStringSession, readStringSession,
StringSessionData,
toggleChannelIdMark, toggleChannelIdMark,
writeStringSession, writeStringSession,
} from './utils/index.js' } from './utils/index.js'
/** Options for {@link BaseTelegramClient} */
export interface BaseTelegramClientOptions {
/**
* API ID from my.telegram.org
*/
apiId: number | string
/**
* API hash from my.telegram.org
*/
apiHash: string
/**
* Storage to use for this client.
*/
storage: ITelegramStorage
/**
* Cryptography provider factory to allow delegating
* crypto to native addon, worker, etc.
*/
crypto?: CryptoProviderFactory
/**
* Whether to use IPv6 datacenters
* (IPv6 will be preferred when choosing a DC by id)
* (default: false)
*/
useIpv6?: boolean
/**
* Primary DC to use for initial connection.
* This does not mean this will be the only DC used,
* nor that this DC will actually be primary, this only
* determines the first DC the library will try to connect to.
* Can be used to connect to other networks (like test DCs).
*
* When session already contains primary DC, this parameter is ignored.
*
* @default Production DC 2.
*/
defaultDcs?: ITelegramStorage.DcOptions
/**
* Whether to connect to test servers.
*
* If passed, {@link defaultDc} defaults to Test DC 2.
*
* **Must** be passed if using test servers, even if
* you passed custom {@link defaultDc}
*/
testMode?: boolean
/**
* Additional options for initConnection call.
* `apiId` and `query` are not available and will be ignored.
* Omitted values will be filled with defaults
*/
initConnectionOptions?: Partial<Omit<tl.RawInitConnectionRequest, 'apiId' | 'query'>>
/**
* Transport factory to use in the client.
*
* @default platform-specific transport: WebSocket on the web, TCP in node
*/
transport?: TransportFactory
/**
* Reconnection strategy.
*
* @default simple reconnection strategy: first 0ms, then up to 5s (increasing by 1s)
*/
reconnectionStrategy?: ReconnectionStrategy<PersistentConnectionParams>
/**
* Maximum duration of a flood_wait that will be waited automatically.
* Flood waits above this threshold will throw a FloodWaitError.
* Set to 0 to disable. Can be overridden with `throwFlood` parameter in call() params
*
* @default 10000
*/
floodSleepThreshold?: number
/**
* Maximum number of retries when calling RPC methods.
* Call is retried when InternalError or FloodWaitError is encountered.
* Can be set to Infinity.
*
* @default 5
*/
maxRetryCount?: number
/**
* If true, every single API call will be wrapped with `tl.invokeWithoutUpdates`,
* effectively disabling the server-sent events for the clients.
* May be useful in some cases.
*
* Note that this only wraps calls made with `.call()` within the primary
* connection. Additional connections and direct `.sendForResult()` calls
* must be wrapped manually.
*
* @default false
*/
disableUpdates?: boolean
/**
* mtcute can send all unknown RPC errors to [danog](https://github.com/danog)'s
* [error reporting service](https://rpc.pwrtelegram.xyz/).
*
* This is fully anonymous (except maybe IP) and is only used to improve the library
* and developer experience for everyone working with MTProto. This is fully opt-in,
* and if you're too paranoid, you can disable it by manually passing `enableErrorReporting: false` to the client.
*
* @default false
*/
enableErrorReporting?: boolean
/**
* If true, RPC errors will have a stack trace of the initial `.call()`
* or `.sendForResult()` call position, which drastically improves
* debugging experience.<br>
* If false, they will have a stack trace of mtcute internals.
*
* Internally this creates a stack capture before every RPC call
* and stores it until the result is received. This might
* use a lot more memory than normal, thus can be disabled here.
*
* @default true
*/
niceStacks?: boolean
/**
* Extra parameters for {@link NetworkManager}
*/
network?: NetworkManagerExtraParams
/**
* Set logging level for the client.
*
* See static members of {@link LogManager} for possible values.
*/
logLevel?: number
/**
* **EXPERT USE ONLY!**
*
* Override TL layer used for the connection.
*
* **Does not** change the schema used.
*/
overrideLayer?: number
/**
* **EXPERT USE ONLY**
*
* Override reader map used for the connection.
*/
readerMap?: TlReaderMap
/**
* **EXPERT USE ONLY**
*
* Override writer map used for the connection.
*/
writerMap?: TlWriterMap
}
/** /**
* Basic Telegram client that only implements the bare minimum * Basic Telegram client that only implements the bare minimum
* to make RPC calls and receive low-level updates. * to make RPC calls and receive low-level updates.
@ -248,9 +82,9 @@ export class BaseTelegramClient extends EventEmitter {
// not really connected, but rather "connect() was called" // not really connected, but rather "connect() was called"
private _connected: ControllablePromise<void> | boolean = false private _connected: ControllablePromise<void> | boolean = false
private _onError?: (err: unknown, connection?: SessionConnection) => void _emitError: (err: unknown, connection?: SessionConnection) => void = console.error.bind(console)
private _importFrom?: string private _importFrom?: StringSessionData
private _importForce?: boolean private _importForce?: boolean
readonly log = new LogManager('client') readonly log = new LogManager('client')
@ -372,7 +206,7 @@ export class BaseTelegramClient extends EventEmitter {
const defaultDcAuthKey = await this.storage.getAuthKeyFor(this._defaultDcs.main.id) const defaultDcAuthKey = await this.storage.getAuthKeyFor(this._defaultDcs.main.id)
if ((this._importForce || !defaultDcAuthKey) && this._importFrom) { if ((this._importForce || !defaultDcAuthKey) && this._importFrom) {
const data = readStringSession(this._readerMap, this._importFrom) const data = this._importFrom
if (data.testMode !== this._testMode) { if (data.testMode !== this._testMode) {
throw new Error( throw new Error(
@ -517,7 +351,7 @@ export class BaseTelegramClient extends EventEmitter {
* this was connection-related error. * this was connection-related error.
*/ */
onError(handler: (err: unknown, connection?: SessionConnection) => void): void { onError(handler: (err: unknown, connection?: SessionConnection) => void): void {
this._onError = handler this._emitError = handler
} }
notifyLoggedIn(auth: tl.auth.RawAuthorization): void { notifyLoggedIn(auth: tl.auth.RawAuthorization): void {
@ -525,15 +359,9 @@ export class BaseTelegramClient extends EventEmitter {
this.emit('logged_in', auth) this.emit('logged_in', auth)
} }
_emitError(err: unknown, connection?: SessionConnection): void {
if (this._onError) {
this._onError(err, connection)
} else {
console.error(err)
}
}
/** /**
* **ADVANCED**
*
* Adds all peers from a given object to entity cache in storage. * Adds all peers from a given object to entity cache in storage.
*/ */
async _cachePeersFrom(obj: object): Promise<boolean> { async _cachePeersFrom(obj: object): Promise<boolean> {
@ -634,18 +462,18 @@ export class BaseTelegramClient extends EventEmitter {
/** /**
* Request the session to be imported from the given session string. * Request the session to be imported from the given session string.
* *
* Note that the string will not be parsed and imported right away, * Note that the session will not be imported right away,
* instead, it will be imported when `connect()` is called * instead, it will be imported once `connect()` is called
* *
* Also note that the session will only be imported in case * Also note that the session will only be imported in case
* the storage is missing authorization (i.e. does not contain * the storage is missing authorization (i.e. does not contain
* auth key for the primary DC), otherwise it will be ignored (unless `force). * auth key for the primary DC), otherwise it will be ignored (unless `force`).
* *
* @param session Session string to import * @param session Session string to import
* @param force Whether to overwrite existing session * @param force Whether to overwrite existing session
*/ */
importSession(session: string, force = false): void { importSession(session: string | StringSessionData, force = false): void {
this._importFrom = session this._importFrom = typeof session === 'string' ? readStringSession(this._readerMap, session) : session
this._importForce = force this._importForce = force
} }
} }

View file

@ -0,0 +1,173 @@
import { tl } from '@mtcute/tl'
import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'
import { NetworkManagerExtraParams, ReconnectionStrategy, TransportFactory } from './network/index.js'
import { PersistentConnectionParams } from './network/persistent-connection.js'
import { ITelegramStorage } from './storage/abstract.js'
import { CryptoProviderFactory } from './utils/index.js'
/** Options for {@link BaseTelegramClient} */
export interface BaseTelegramClientOptions {
/**
* API ID from my.telegram.org
*/
apiId: number | string
/**
* API hash from my.telegram.org
*/
apiHash: string
/**
* Storage to use for this client.
*/
storage: ITelegramStorage
/**
* Cryptography provider factory to allow delegating
* crypto to native addon, worker, etc.
*/
crypto?: CryptoProviderFactory
/**
* Whether to use IPv6 datacenters
* (IPv6 will be preferred when choosing a DC by id)
* (default: false)
*/
useIpv6?: boolean
/**
* Primary DC to use for initial connection.
* This does not mean this will be the only DC used,
* nor that this DC will actually be primary, this only
* determines the first DC the library will try to connect to.
* Can be used to connect to other networks (like test DCs).
*
* When session already contains primary DC, this parameter is ignored.
*
* @default Production DC 2.
*/
defaultDcs?: ITelegramStorage.DcOptions
/**
* Whether to connect to test servers.
*
* If passed, {@link defaultDc} defaults to Test DC 2.
*
* **Must** be passed if using test servers, even if
* you passed custom {@link defaultDc}
*/
testMode?: boolean
/**
* Additional options for initConnection call.
* `apiId` and `query` are not available and will be ignored.
* Omitted values will be filled with defaults
*/
initConnectionOptions?: Partial<Omit<tl.RawInitConnectionRequest, 'apiId' | 'query'>>
/**
* Transport factory to use in the client.
*
* @default platform-specific transport: WebSocket on the web, TCP in node
*/
transport?: TransportFactory
/**
* Reconnection strategy.
*
* @default simple reconnection strategy: first 0ms, then up to 5s (increasing by 1s)
*/
reconnectionStrategy?: ReconnectionStrategy<PersistentConnectionParams>
/**
* Maximum duration of a flood_wait that will be waited automatically.
* Flood waits above this threshold will throw a FloodWaitError.
* Set to 0 to disable. Can be overridden with `throwFlood` parameter in call() params
*
* @default 10000
*/
floodSleepThreshold?: number
/**
* Maximum number of retries when calling RPC methods.
* Call is retried when InternalError or FloodWaitError is encountered.
* Can be set to Infinity.
*
* @default 5
*/
maxRetryCount?: number
/**
* If true, every single API call will be wrapped with `tl.invokeWithoutUpdates`,
* effectively disabling the server-sent events for the clients.
* May be useful in some cases.
*
* Note that this only wraps calls made with `.call()` within the primary
* connection. Additional connections and direct `.sendForResult()` calls
* must be wrapped manually.
*
* @default false
*/
disableUpdates?: boolean
/**
* mtcute can send all unknown RPC errors to [danog](https://github.com/danog)'s
* [error reporting service](https://rpc.pwrtelegram.xyz/).
*
* This is fully anonymous (except maybe IP) and is only used to improve the library
* and developer experience for everyone working with MTProto. This is fully opt-in,
* and if you're too paranoid, you can disable it by manually passing `enableErrorReporting: false` to the client.
*
* @default false
*/
enableErrorReporting?: boolean
/**
* If true, RPC errors will have a stack trace of the initial `.call()`
* or `.sendForResult()` call position, which drastically improves
* debugging experience.<br>
* If false, they will have a stack trace of mtcute internals.
*
* Internally this creates a stack capture before every RPC call
* and stores it until the result is received. This might
* use a lot more memory than normal, thus can be disabled here.
*
* @default true
*/
niceStacks?: boolean
/**
* Extra parameters for {@link NetworkManager}
*/
network?: NetworkManagerExtraParams
/**
* Set logging level for the client.
*
* See static members of {@link LogManager} for possible values.
*/
logLevel?: number
/**
* **EXPERT USE ONLY!**
*
* Override TL layer used for the connection.
*
* **Does not** change the schema used.
*/
overrideLayer?: number
/**
* **EXPERT USE ONLY**
*
* Override reader map used for the connection.
*/
readerMap?: TlReaderMap
/**
* **EXPERT USE ONLY**
*
* Override writer map used for the connection.
*/
writerMap?: TlWriterMap
}

View file

@ -1,4 +1,5 @@
export * from './base-client.js' export * from './base-client.js'
export * from './base-client.types.js'
export * from './network/index.js' export * from './network/index.js'
export * from './storage/index.js' export * from './storage/index.js'
export * from './types/index.js' export * from './types/index.js'