feat(core): qr code login
This commit is contained in:
parent
9daa551e33
commit
e2464f7f3f
13 changed files with 311 additions and 35 deletions
|
@ -743,6 +743,8 @@ withParams(params: RpcCallOptions): this\n`)
|
|||
'computeSrpParams',
|
||||
'computeNewPasswordHash',
|
||||
'onConnectionState',
|
||||
'getServerUpdateHandler',
|
||||
'changePrimaryDc',
|
||||
].forEach((name) => {
|
||||
output.write(
|
||||
`TelegramClient.prototype.${name} = function(...args) {\n` +
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
writeStringSession,
|
||||
} from '../utils/index.js'
|
||||
import { LogManager } from '../utils/logger.js'
|
||||
import { ConnectionState, ITelegramClient } from './client.types.js'
|
||||
import { ConnectionState, ITelegramClient, ServerUpdateHandler } from './client.types.js'
|
||||
import { AppConfigManager } from './managers/app-config-manager.js'
|
||||
import { ITelegramStorageProvider } from './storage/provider.js'
|
||||
import { TelegramStorageManager, TelegramStorageManagerExtraOptions } from './storage/storage.js'
|
||||
|
@ -30,7 +30,7 @@ export interface BaseTelegramClientOptions extends MtClientOptions {
|
|||
|
||||
export class BaseTelegramClient implements ITelegramClient {
|
||||
readonly updates?: UpdatesManager
|
||||
private _serverUpdatesHandler: (updates: tl.TypeUpdates) => void = () => {}
|
||||
private _serverUpdatesHandler: ServerUpdateHandler = () => {}
|
||||
private _connectionStateHandler: (state: ConnectionState) => void = () => {}
|
||||
|
||||
readonly log
|
||||
|
@ -276,10 +276,14 @@ export class BaseTelegramClient implements ITelegramClient {
|
|||
this.updates?.handleClientUpdate(updates, noDispatch)
|
||||
}
|
||||
|
||||
onServerUpdate(handler: (update: tl.TypeUpdates) => void): void {
|
||||
onServerUpdate(handler: ServerUpdateHandler): void {
|
||||
this._serverUpdatesHandler = handler
|
||||
}
|
||||
|
||||
getServerUpdateHandler(): ServerUpdateHandler {
|
||||
return this._serverUpdatesHandler
|
||||
}
|
||||
|
||||
onUpdate(handler: RawUpdateHandler): void {
|
||||
if (!this.updates) {
|
||||
throw new MtArgumentError('Updates manager is disabled')
|
||||
|
@ -325,4 +329,8 @@ export class BaseTelegramClient implements ITelegramClient {
|
|||
get stopSignal(): AbortSignal {
|
||||
return this.mt.stopSignal
|
||||
}
|
||||
|
||||
changePrimaryDc(dcId: number): Promise<void> {
|
||||
return this.mt.network.changePrimaryDc(dcId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import { sendCode } from './methods/auth/send-code.js'
|
|||
import { sendRecoveryCode } from './methods/auth/send-recovery-code.js'
|
||||
import { signIn } from './methods/auth/sign-in.js'
|
||||
import { signInBot } from './methods/auth/sign-in-bot.js'
|
||||
import { signInQr } from './methods/auth/sign-in-qr.js'
|
||||
import { start } from './methods/auth/start.js'
|
||||
import { startTest } from './methods/auth/start-test.js'
|
||||
import { isSelfPeer } from './methods/auth/utils.js'
|
||||
|
@ -262,6 +263,7 @@ import {
|
|||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
BusinessCallbackQuery,
|
||||
BusinessChatLink,
|
||||
BusinessConnection,
|
||||
BusinessMessage,
|
||||
|
@ -455,6 +457,13 @@ export interface TelegramClient extends ITelegramClient {
|
|||
* @param handler Inline callback query handler
|
||||
*/
|
||||
on(name: 'inline_callback_query', handler: (upd: InlineCallbackQuery) => void): this
|
||||
/**
|
||||
* Register a business callback query handler
|
||||
*
|
||||
* @param name Event name
|
||||
* @param handler Business callback query handler
|
||||
*/
|
||||
on(name: 'business_callback_query', handler: (upd: BusinessCallbackQuery) => void): this
|
||||
/**
|
||||
* Register a poll update handler
|
||||
*
|
||||
|
@ -647,6 +656,9 @@ export interface TelegramClient extends ITelegramClient {
|
|||
|
||||
/** Confirmation code identifier from {@link SentCode} */
|
||||
phoneCodeHash: string
|
||||
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
}): Promise<SentCode>
|
||||
/**
|
||||
* Simple wrapper that calls {@link start} and then
|
||||
|
@ -678,6 +690,9 @@ export interface TelegramClient extends ITelegramClient {
|
|||
|
||||
/** Additional code settings to pass to the server */
|
||||
codeSettings?: Omit<tl.RawCodeSettings, '_' | 'logoutTokens'>
|
||||
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
}): Promise<SentCode>
|
||||
/**
|
||||
* Send a code to email needed to recover your password
|
||||
|
@ -697,6 +712,29 @@ export interface TelegramClient extends ITelegramClient {
|
|||
* @throws BadRequestError In case the bot token is invalid
|
||||
*/
|
||||
signInBot(token: string): Promise<User>
|
||||
|
||||
/**
|
||||
* Execute the [QR login flow](https://core.telegram.org/api/qr-login).
|
||||
*
|
||||
* This method will resolve once the authorization is complete,
|
||||
* returning the authorized user.
|
||||
* **Available**: 👤 users only
|
||||
*
|
||||
*/
|
||||
signInQr(params: {
|
||||
/**
|
||||
* Function that will be called whenever the login URL is changed.
|
||||
*
|
||||
* The app is expected to display `url` as a QR code to the user
|
||||
*/
|
||||
onUrlUpdated: (url: string, expires: Date) => void
|
||||
|
||||
/** Password for 2FA */
|
||||
password?: MaybeDynamic<string>
|
||||
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
}): Promise<User>
|
||||
/**
|
||||
* Authorize a user in Telegram with a valid confirmation code.
|
||||
*
|
||||
|
@ -713,6 +751,8 @@ export interface TelegramClient extends ITelegramClient {
|
|||
phoneCodeHash: string
|
||||
/** The confirmation code that was received */
|
||||
phoneCode: string
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
}): Promise<User>
|
||||
/**
|
||||
* Utility function to quickly authorize on test DC
|
||||
|
@ -778,6 +818,15 @@ export interface TelegramClient extends ITelegramClient {
|
|||
*/
|
||||
sessionForce?: boolean
|
||||
|
||||
/**
|
||||
* When passed, [QR login flow](https://core.telegram.org/api/qr-login)
|
||||
* will be used instead of the regular login flow.
|
||||
*
|
||||
* This function will be called whenever the login URL is changed,
|
||||
* and the app is expected to display it as a QR code to the user.
|
||||
*/
|
||||
qrCodeHandler?: (url: string, expires: Date) => void
|
||||
|
||||
/**
|
||||
* Phone number of the account.
|
||||
* If account does not exist, it will be created
|
||||
|
@ -830,6 +879,9 @@ export interface TelegramClient extends ITelegramClient {
|
|||
|
||||
/** Additional code settings to pass to the server */
|
||||
codeSettings?: Omit<tl.RawCodeSettings, '_' | 'logoutTokens'>
|
||||
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
}): Promise<User>
|
||||
/**
|
||||
* Check if the given peer/input peer is referring to the current user
|
||||
|
@ -5613,6 +5665,9 @@ TelegramClient.prototype.sendRecoveryCode = function (...args) {
|
|||
TelegramClient.prototype.signInBot = function (...args) {
|
||||
return signInBot(this._client, ...args)
|
||||
}
|
||||
TelegramClient.prototype.signInQr = function (...args) {
|
||||
return signInQr(this._client, ...args)
|
||||
}
|
||||
TelegramClient.prototype.signIn = function (...args) {
|
||||
return signIn(this._client, ...args)
|
||||
}
|
||||
|
@ -6428,6 +6483,12 @@ TelegramClient.prototype.computeNewPasswordHash = function (...args) {
|
|||
TelegramClient.prototype.onConnectionState = function (...args) {
|
||||
return this._client.onConnectionState(...args)
|
||||
}
|
||||
TelegramClient.prototype.getServerUpdateHandler = function (...args) {
|
||||
return this._client.getServerUpdateHandler(...args)
|
||||
}
|
||||
TelegramClient.prototype.changePrimaryDc = function (...args) {
|
||||
return this._client.changePrimaryDc(...args)
|
||||
}
|
||||
TelegramClient.prototype.onServerUpdate = function () {
|
||||
throw new Error('onServerUpdate is not available for TelegramClient, use .on() methods instead')
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import type { StringSessionData } from './utils/string-session.js'
|
|||
*/
|
||||
export type ConnectionState = 'offline' | 'connecting' | 'updating' | 'connected'
|
||||
|
||||
export type ServerUpdateHandler = (update: tl.TypeUpdates) => void
|
||||
|
||||
// NB: when adding new methods, don't forget to add them to:
|
||||
// - worker/port.ts
|
||||
// - generate-client script
|
||||
|
@ -51,7 +53,8 @@ export interface ITelegramClient {
|
|||
emitError(err: unknown): void
|
||||
handleClientUpdate(updates: tl.TypeUpdates, noDispatch?: boolean): void
|
||||
|
||||
onServerUpdate(handler: (update: tl.TypeUpdates) => void): void
|
||||
onServerUpdate(handler: ServerUpdateHandler): void
|
||||
getServerUpdateHandler(): ServerUpdateHandler
|
||||
onUpdate(handler: RawUpdateHandler): void
|
||||
onConnectionState(handler: (state: ConnectionState) => void): void
|
||||
|
||||
|
@ -61,6 +64,7 @@ export interface ITelegramClient {
|
|||
// or at least load this once at startup (and then these methods can be made sync)
|
||||
getPoolSize(kind: ConnectionKind, dcId?: number): Promise<number>
|
||||
getPrimaryDcId(): Promise<number>
|
||||
changePrimaryDc(newDc: number): Promise<void>
|
||||
|
||||
computeSrpParams(request: tl.account.RawPassword, password: string): Promise<tl.RawInputCheckPasswordSRP>
|
||||
computeNewPasswordHash(algo: tl.TypePasswordKdfAlgo, password: string): Promise<Uint8Array>
|
||||
|
|
|
@ -10,6 +10,7 @@ export { sendCode } from './methods/auth/send-code.js'
|
|||
export { sendRecoveryCode } from './methods/auth/send-recovery-code.js'
|
||||
export { signIn } from './methods/auth/sign-in.js'
|
||||
export { signInBot } from './methods/auth/sign-in-bot.js'
|
||||
export { signInQr } from './methods/auth/sign-in-qr.js'
|
||||
export { start } from './methods/auth/start.js'
|
||||
export { startTest } from './methods/auth/start-test.js'
|
||||
export { isSelfPeer } from './methods/auth/utils.js'
|
||||
|
|
|
@ -26,6 +26,7 @@ import {
|
|||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
BusinessCallbackQuery,
|
||||
BusinessChatLink,
|
||||
BusinessConnection,
|
||||
BusinessMessage,
|
||||
|
|
|
@ -17,15 +17,21 @@ export async function resendCode(
|
|||
|
||||
/** Confirmation code identifier from {@link SentCode} */
|
||||
phoneCodeHash: string
|
||||
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
},
|
||||
): Promise<SentCode> {
|
||||
const { phone, phoneCodeHash } = params
|
||||
const { phone, phoneCodeHash, abortSignal } = params
|
||||
|
||||
const res = await client.call({
|
||||
const res = await client.call(
|
||||
{
|
||||
_: 'auth.resendCode',
|
||||
phoneNumber: normalizePhoneNumber(phone),
|
||||
phoneCodeHash,
|
||||
})
|
||||
},
|
||||
{ abortSignal },
|
||||
)
|
||||
|
||||
assertTypeIs('sendCode', res, 'auth.sentCode')
|
||||
|
||||
|
|
|
@ -21,13 +21,17 @@ export async function sendCode(
|
|||
|
||||
/** Additional code settings to pass to the server */
|
||||
codeSettings?: Omit<tl.RawCodeSettings, '_' | 'logoutTokens'>
|
||||
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
},
|
||||
): Promise<SentCode> {
|
||||
const phone = normalizePhoneNumber(params.phone)
|
||||
|
||||
const { id, hash } = await client.getApiCrenetials()
|
||||
|
||||
const res = await client.call({
|
||||
const res = await client.call(
|
||||
{
|
||||
_: 'auth.sendCode',
|
||||
phoneNumber: phone,
|
||||
apiId: id,
|
||||
|
@ -37,7 +41,9 @@ export async function sendCode(
|
|||
logoutTokens: params.futureAuthTokens,
|
||||
...params.codeSettings,
|
||||
},
|
||||
})
|
||||
},
|
||||
{ abortSignal: params.abortSignal },
|
||||
)
|
||||
|
||||
assertTypeIs('sendCode', res, 'auth.sentCode')
|
||||
|
||||
|
|
141
packages/core/src/highlevel/methods/auth/sign-in-qr.ts
Normal file
141
packages/core/src/highlevel/methods/auth/sign-in-qr.ts
Normal file
|
@ -0,0 +1,141 @@
|
|||
import { tl } from '@mtcute/tl'
|
||||
|
||||
import { getPlatform } from '../../../platform.js'
|
||||
import { ControllablePromise, createControllablePromise } from '../../../utils/controllable-promise.js'
|
||||
import { sleepWithAbort } from '../../../utils/misc-utils.js'
|
||||
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||
import { ITelegramClient, ServerUpdateHandler } from '../../client.types.js'
|
||||
import { MaybeDynamic, User } from '../../types/index.js'
|
||||
import { resolveMaybeDynamic } from '../../utils/misc-utils.js'
|
||||
import { checkPassword } from './check-password.js'
|
||||
|
||||
// @available=user
|
||||
/**
|
||||
* Execute the [QR login flow](https://core.telegram.org/api/qr-login).
|
||||
*
|
||||
* This method will resolve once the authorization is complete,
|
||||
* returning the authorized user.
|
||||
*/
|
||||
export async function signInQr(
|
||||
client: ITelegramClient,
|
||||
params: {
|
||||
/**
|
||||
* Function that will be called whenever the login URL is changed.
|
||||
*
|
||||
* The app is expected to display `url` as a QR code to the user
|
||||
*/
|
||||
onUrlUpdated: (url: string, expires: Date) => void
|
||||
|
||||
/** Password for 2FA */
|
||||
password?: MaybeDynamic<string>
|
||||
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
},
|
||||
): Promise<User> {
|
||||
const { onUrlUpdated, abortSignal } = params
|
||||
|
||||
let waiter: ControllablePromise<void> | undefined
|
||||
|
||||
// crutch – we need to wait for the updateLoginToken update.
|
||||
// we replace the server update handler temporarily because:
|
||||
// - updates manager may be disabled, in which case `onUpdate` will never be called
|
||||
// - even if the updates manager is enabled, it won't start until we're logged in
|
||||
//
|
||||
// todo: how can we make this more clean?
|
||||
const originalHandler = client.getServerUpdateHandler()
|
||||
|
||||
const onUpdate: ServerUpdateHandler = (upd) => {
|
||||
if (upd._ === 'updateShort' && upd.update._ === 'updateLoginToken') {
|
||||
waiter?.resolve()
|
||||
client.onServerUpdate(originalHandler)
|
||||
}
|
||||
}
|
||||
|
||||
client.onServerUpdate(onUpdate)
|
||||
|
||||
abortSignal?.addEventListener('abort', () => {
|
||||
client.onServerUpdate(originalHandler)
|
||||
waiter?.reject(abortSignal.reason)
|
||||
})
|
||||
|
||||
try {
|
||||
const { id, hash } = await client.getApiCrenetials()
|
||||
const platform = getPlatform()
|
||||
|
||||
loop: while (true) {
|
||||
let res: tl.auth.TypeLoginToken
|
||||
|
||||
try {
|
||||
res = await client.call(
|
||||
{
|
||||
_: 'auth.exportLoginToken',
|
||||
apiId: id,
|
||||
apiHash: hash,
|
||||
exceptIds: [],
|
||||
},
|
||||
{ abortSignal },
|
||||
)
|
||||
} catch (e) {
|
||||
if (tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED') && params.password) {
|
||||
return checkPassword(client, await resolveMaybeDynamic(params.password))
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
switch (res._) {
|
||||
case 'auth.loginToken':
|
||||
onUrlUpdated(
|
||||
`tg://login?token=${platform.base64Encode(res.token, true)}`,
|
||||
new Date(res.expires * 1000),
|
||||
)
|
||||
|
||||
waiter = createControllablePromise()
|
||||
await Promise.race([waiter, sleepWithAbort(res.expires * 1000 - Date.now(), client.stopSignal)])
|
||||
break
|
||||
case 'auth.loginTokenMigrateTo': {
|
||||
await client.changePrimaryDc(res.dcId)
|
||||
|
||||
let res2: tl.auth.TypeLoginToken
|
||||
|
||||
try {
|
||||
res2 = await client.call(
|
||||
{
|
||||
_: 'auth.importLoginToken',
|
||||
token: res.token,
|
||||
},
|
||||
{ abortSignal },
|
||||
)
|
||||
} catch (e) {
|
||||
if (tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED') && params.password) {
|
||||
return checkPassword(client, await resolveMaybeDynamic(params.password))
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
assertTypeIs('auth.importLoginToken', res2, 'auth.loginTokenSuccess')
|
||||
break loop
|
||||
}
|
||||
case 'auth.loginTokenSuccess':
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
const [self] = await client.call(
|
||||
{
|
||||
_: 'users.getUsers',
|
||||
id: [{ _: 'inputUserSelf' }],
|
||||
},
|
||||
{ abortSignal },
|
||||
)
|
||||
assertTypeIs('users.getUsers', self, 'user')
|
||||
|
||||
await client.notifyLoggedIn(self)
|
||||
|
||||
return new User(self)
|
||||
} finally {
|
||||
client.onServerUpdate(originalHandler)
|
||||
}
|
||||
}
|
|
@ -19,16 +19,21 @@ export async function signIn(
|
|||
phoneCodeHash: string
|
||||
/** The confirmation code that was received */
|
||||
phoneCode: string
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
},
|
||||
): Promise<User> {
|
||||
const { phone, phoneCodeHash, phoneCode } = params
|
||||
const { phone, phoneCodeHash, phoneCode, abortSignal } = params
|
||||
|
||||
const res = await client.call({
|
||||
const res = await client.call(
|
||||
{
|
||||
_: 'auth.signIn',
|
||||
phoneNumber: normalizePhoneNumber(phone),
|
||||
phoneCodeHash,
|
||||
phoneCode,
|
||||
})
|
||||
},
|
||||
{ abortSignal },
|
||||
)
|
||||
|
||||
return _onAuthorization(client, res)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import { resendCode } from './resend-code.js'
|
|||
import { sendCode } from './send-code.js'
|
||||
import { signIn } from './sign-in.js'
|
||||
import { signInBot } from './sign-in-bot.js'
|
||||
import { signInQr } from './sign-in-qr.js'
|
||||
|
||||
// @available=both
|
||||
/**
|
||||
|
@ -48,6 +49,15 @@ export async function start(
|
|||
*/
|
||||
sessionForce?: boolean
|
||||
|
||||
/**
|
||||
* When passed, [QR login flow](https://core.telegram.org/api/qr-login)
|
||||
* will be used instead of the regular login flow.
|
||||
*
|
||||
* This function will be called whenever the login URL is changed,
|
||||
* and the app is expected to display it as a QR code to the user.
|
||||
*/
|
||||
qrCodeHandler?: (url: string, expires: Date) => void
|
||||
|
||||
/**
|
||||
* Phone number of the account.
|
||||
* If account does not exist, it will be created
|
||||
|
@ -100,12 +110,17 @@ export async function start(
|
|||
|
||||
/** Additional code settings to pass to the server */
|
||||
codeSettings?: Omit<tl.RawCodeSettings, '_' | 'logoutTokens'>
|
||||
|
||||
/** Abort signal */
|
||||
abortSignal?: AbortSignal
|
||||
},
|
||||
): Promise<User> {
|
||||
if (params.session) {
|
||||
await client.importSession(params.session, params.sessionForce)
|
||||
}
|
||||
|
||||
const { abortSignal } = params
|
||||
|
||||
let has2fa = false
|
||||
let sentCode: SentCode | undefined
|
||||
let phone: string | null = null
|
||||
|
@ -128,7 +143,7 @@ export async function start(
|
|||
}
|
||||
|
||||
// if has2fa == true, then we are half-logged in, but need to enter password
|
||||
if (!has2fa) {
|
||||
if (!has2fa && !params.qrCodeHandler) {
|
||||
if (!params.phone && !params.botToken) {
|
||||
throw new MtArgumentError('Neither phone nor bot token were provided')
|
||||
}
|
||||
|
@ -156,6 +171,7 @@ export async function start(
|
|||
phone,
|
||||
futureAuthTokens: params.futureAuthTokens,
|
||||
codeSettings: params.codeSettings,
|
||||
abortSignal,
|
||||
})
|
||||
} catch (e) {
|
||||
if (tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED')) {
|
||||
|
@ -168,7 +184,11 @@ export async function start(
|
|||
|
||||
if (sentCode) {
|
||||
if (params.forceSms && (sentCode.type === 'app' || sentCode.type === 'email')) {
|
||||
sentCode = await resendCode(client, { phone: phone!, phoneCodeHash: sentCode.phoneCodeHash })
|
||||
sentCode = await resendCode(client, {
|
||||
phone: phone!,
|
||||
phoneCodeHash: sentCode.phoneCodeHash,
|
||||
abortSignal,
|
||||
})
|
||||
}
|
||||
|
||||
if (params.codeSentCallback) {
|
||||
|
@ -186,7 +206,12 @@ export async function start(
|
|||
if (!code) throw new tl.RpcError(400, 'PHONE_CODE_EMPTY')
|
||||
|
||||
try {
|
||||
return await signIn(client, { phone: phone!, phoneCodeHash: sentCode.phoneCodeHash, phoneCode: code })
|
||||
return await signIn(client, {
|
||||
phone: phone!,
|
||||
phoneCodeHash: sentCode.phoneCodeHash,
|
||||
phoneCode: code,
|
||||
abortSignal,
|
||||
})
|
||||
} catch (e) {
|
||||
if (!tl.RpcError.is(e)) throw e
|
||||
|
||||
|
@ -245,5 +270,13 @@ export async function start(
|
|||
}
|
||||
}
|
||||
|
||||
if (params.qrCodeHandler) {
|
||||
return await signInQr(client, {
|
||||
onUrlUpdated: params.qrCodeHandler,
|
||||
password: params.password,
|
||||
abortSignal,
|
||||
})
|
||||
}
|
||||
|
||||
throw new MtArgumentError('Failed to log in with provided credentials')
|
||||
}
|
||||
|
|
|
@ -180,6 +180,10 @@ export class UpdatesManager {
|
|||
this._handler = handler
|
||||
}
|
||||
|
||||
getHandler(): RawUpdateHandler {
|
||||
return this._handler
|
||||
}
|
||||
|
||||
onCatchingUp(handler: (catchingUp: boolean) => void): void {
|
||||
this._onCatchingUp = handler
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { tl } from '@mtcute/tl'
|
||||
|
||||
import { LogManager } from '../../utils/logger.js'
|
||||
import { ConnectionState, ITelegramClient } from '../client.types.js'
|
||||
import { ConnectionState, ITelegramClient, ServerUpdateHandler } from '../client.types.js'
|
||||
import { PeersIndex } from '../types/peers/peers-index.js'
|
||||
import { RawUpdateHandler } from '../updates/types.js'
|
||||
import { AppConfigManagerProxy } from './app-config.js'
|
||||
|
@ -37,6 +35,7 @@ export abstract class TelegramWorkerPort<Custom extends WorkerCustomMethods> imp
|
|||
readonly getApiCrenetials
|
||||
readonly getPoolSize
|
||||
readonly getPrimaryDcId
|
||||
readonly changePrimaryDc
|
||||
readonly computeSrpParams
|
||||
readonly computeNewPasswordHash
|
||||
readonly startUpdatesLoop
|
||||
|
@ -71,6 +70,7 @@ export abstract class TelegramWorkerPort<Custom extends WorkerCustomMethods> imp
|
|||
this.getApiCrenetials = bind('getApiCrenetials')
|
||||
this.getPoolSize = bind('getPoolSize')
|
||||
this.getPrimaryDcId = bind('getPrimaryDcId')
|
||||
this.changePrimaryDc = bind('changePrimaryDc')
|
||||
this.computeSrpParams = bind('computeSrpParams')
|
||||
this.computeNewPasswordHash = bind('computeNewPasswordHash')
|
||||
this.startUpdatesLoop = bind('startUpdatesLoop')
|
||||
|
@ -79,11 +79,15 @@ export abstract class TelegramWorkerPort<Custom extends WorkerCustomMethods> imp
|
|||
|
||||
abstract connectToWorker(worker: SomeWorker, handler: ClientMessageHandler): [SendFn, () => void]
|
||||
|
||||
private _serverUpdatesHandler: (updates: tl.TypeUpdates) => void = () => {}
|
||||
onServerUpdate(handler: (updates: tl.TypeUpdates) => void): void {
|
||||
private _serverUpdatesHandler: ServerUpdateHandler = () => {}
|
||||
onServerUpdate(handler: ServerUpdateHandler): void {
|
||||
this._serverUpdatesHandler = handler
|
||||
}
|
||||
|
||||
getServerUpdateHandler(): ServerUpdateHandler {
|
||||
return this._serverUpdatesHandler
|
||||
}
|
||||
|
||||
private _errorHandler: (err: unknown) => void = () => {}
|
||||
onError(handler: (err: unknown) => void): void {
|
||||
this._errorHandler = handler
|
||||
|
|
Loading…
Reference in a new issue