chore(core): various improvements
This commit is contained in:
parent
886858d9de
commit
7a0d8ecef2
3 changed files with 189 additions and 187 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
173
packages/core/src/base-client.types.ts
Normal file
173
packages/core/src/base-client.types.ts
Normal 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
|
||||||
|
}
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in a new issue