mtcute/packages/deno/src/client.ts

146 lines
4.2 KiB
TypeScript
Raw Normal View History

2024-04-28 22:41:28 +03:00
import { createInterface, Interface as RlInterface } from 'node:readline'
import { Readable, Writable } from 'node:stream'
import { FileDownloadLocation, FileDownloadParameters, ITelegramStorageProvider, PartialOnly, User } from '@mtcute/core'
import {
BaseTelegramClient as BaseTelegramClientBase,
BaseTelegramClientOptions as BaseTelegramClientOptionsBase,
TelegramClient as TelegramClientBase,
TelegramClientOptions,
} from '@mtcute/core/client.js'
import { setPlatform } from '@mtcute/core/platform.js'
import { downloadToFile } from './methods/download-file.js'
import { DenoPlatform } from './platform.js'
import { SqliteStorage } from './sqlite/index.js'
import { DenoCryptoProvider } from './utils/crypto.js'
import { TcpTransport } from './utils/tcp.js'
export type { TelegramClientOptions }
export interface BaseTelegramClientOptions
extends PartialOnly<Omit<BaseTelegramClientOptionsBase, 'storage'>, 'transport' | 'crypto'> {
/**
* Storage to use for this client.
*
* If a string is passed, it will be used as
* a name for an SQLite database file.
*
* @default `"client.session"`
*/
storage?: string | ITelegramStorageProvider
/**
* **ADVANCED USE ONLY**
*
* Whether to not set up the platform.
* This is useful if you call `setPlatform` yourself.
*/
platformless?: boolean
}
export class BaseTelegramClient extends BaseTelegramClientBase {
constructor(opts: BaseTelegramClientOptions) {
if (!opts.platformless) setPlatform(new DenoPlatform())
super({
crypto: new DenoCryptoProvider(),
transport: () => new TcpTransport(),
...opts,
storage:
typeof opts.storage === 'string' ?
new SqliteStorage(opts.storage) :
opts.storage ?? new SqliteStorage('client.session'),
})
}
}
/**
2024-04-29 16:42:58 +03:00
* Telegram client for use in Deno
2024-04-28 22:41:28 +03:00
*/
export class TelegramClient extends TelegramClientBase {
constructor(opts: TelegramClientOptions) {
if ('client' in opts) {
super(opts)
return
}
super({
client: new BaseTelegramClient(opts),
})
}
private _rl?: RlInterface
/**
* Tiny wrapper over Node `readline` package
* for simpler user input for `.run()` method.
*
* Associated `readline` interface is closed
* after `run()` returns, or with the client.
*
* @param text Text of the question
*/
input(text: string): Promise<string> {
if (!this._rl) {
this._rl = createInterface({
// eslint-disable-next-line
input: Readable.fromWeb(Deno.stdin.readable as any),
// eslint-disable-next-line
output: Writable.fromWeb(Deno.stdout.writable as any),
2024-04-28 22:41:28 +03:00
})
}
return new Promise((res) => this._rl?.question(text, res))
}
close(): Promise<void> {
this._rl?.close()
return super.close()
}
start(params: Parameters<TelegramClientBase['start']>[0] = {}): Promise<User> {
if (!params.botToken) {
if (!params.phone) params.phone = () => this.input('phone > ')
if (!params.code) params.code = () => this.input('code > ')
if (!params.password) {
params.password = () => this.input('2fa password > ')
}
}
return super.start(params).then((user) => {
if (this._rl) {
this._rl.close()
delete this._rl
}
return user
})
}
run(
params: Parameters<TelegramClient['start']>[0] | ((user: User) => void | Promise<void>),
then?: (user: User) => void | Promise<void>,
): void {
if (typeof params === 'function') {
then = params
params = {}
}
this.start(params)
.then(then)
.catch((err) => this.emitError(err))
}
downloadToFile(
filename: string,
location: FileDownloadLocation,
params?: FileDownloadParameters | undefined,
): Promise<void> {
return downloadToFile(this, filename, location, params)
}
}