diff --git a/packages/bun/src/client.ts b/packages/bun/src/client.ts index 90d83193..180a2690 100644 --- a/packages/bun/src/client.ts +++ b/packages/bun/src/client.ts @@ -11,19 +11,18 @@ import { BaseTelegramClient as BaseTelegramClientBase, TelegramClient as TelegramClientBase, } from '@mtcute/core/client.js' -import { setPlatform } from '@mtcute/core/platform.js' import { downloadToFile } from './methods/download-file.js' import { downloadAsNodeStream } from './methods/download-node-stream.js' -import { BunPlatform } from './platform.js' import { SqliteStorage } from './sqlite/index.js' import { BunCryptoProvider } from './utils/crypto.js' import { TcpTransport } from './utils/tcp.js' +import { BunPlatform } from './platform.js' export type { TelegramClientOptions } export interface BaseTelegramClientOptions - extends PartialOnly, 'transport' | 'crypto'> { + extends PartialOnly, 'transport' | 'crypto' | 'platform'> { /** * Storage to use for this client. * @@ -33,23 +32,14 @@ export interface BaseTelegramClientOptions * @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 BunPlatform()) - super({ crypto: new BunCryptoProvider(), transport: TcpTransport, + platform: new BunPlatform(), ...opts, storage: typeof opts.storage === 'string' diff --git a/packages/bun/src/sqlite/sqlite.test.ts b/packages/bun/src/sqlite/sqlite.test.ts index bc6504a8..84c32ed7 100644 --- a/packages/bun/src/sqlite/sqlite.test.ts +++ b/packages/bun/src/sqlite/sqlite.test.ts @@ -1,6 +1,7 @@ import { afterAll, beforeAll, describe } from 'vitest' import { LogManager } from '@mtcute/core/utils.js' import { + defaultPlatform, testAuthKeysRepository, testKeyValueRepository, testPeersRepository, @@ -14,7 +15,7 @@ if (import.meta.env.TEST_ENV === 'bun') { const storage = new SqliteStorage(':memory:') beforeAll(async () => { - storage.driver.setup(new LogManager()) + storage.driver.setup(new LogManager(undefined, defaultPlatform), defaultPlatform) await storage.driver.load() }) diff --git a/packages/bun/src/worker.ts b/packages/bun/src/worker.ts index 477e87e0..a3edd1a3 100644 --- a/packages/bun/src/worker.ts +++ b/packages/bun/src/worker.ts @@ -1,13 +1,11 @@ import { Worker, parentPort } from 'node:worker_threads' -import { setPlatform } from '@mtcute/core/platform.js' import type { ClientMessageHandler, RespondFn, SendFn, SomeWorker, TelegramWorkerOptions, - TelegramWorkerPortOptions, WorkerCustomMethods, WorkerMessageHandler, } from '@mtcute/core/worker.js' @@ -16,9 +14,13 @@ import { TelegramWorkerPort as TelegramWorkerPortBase, } from '@mtcute/core/worker.js' -import { BunPlatform } from './platform.js' +import { BunPlatform } from './platform' -export type { TelegramWorkerOptions, TelegramWorkerPortOptions, WorkerCustomMethods } +export type { TelegramWorkerOptions, WorkerCustomMethods } + +export interface TelegramWorkerPortOptions { + worker: SomeWorker +} let _registered = false @@ -45,9 +47,11 @@ export class TelegramWorker extends TelegramWorke } export class TelegramWorkerPort extends TelegramWorkerPortBase { - constructor(readonly options: TelegramWorkerPortOptions) { - setPlatform(new BunPlatform()) - super(options) + constructor(options: TelegramWorkerPortOptions) { + super({ + worker: options.worker, + platform: new BunPlatform(), + }) } connectToWorker(worker: SomeWorker, handler: ClientMessageHandler): [SendFn, () => void] { diff --git a/packages/convert/package.json b/packages/convert/package.json index f02a51dc..7a4b2f4d 100644 --- a/packages/convert/package.json +++ b/packages/convert/package.json @@ -14,7 +14,7 @@ "dependencies": { "@mtcute/core": "workspace:^", "@fuman/utils": "workspace:^", - "@fuman/ip": "workspace:^" + "@fuman/net": "workspace:^" }, "devDependencies": { "@mtcute/test": "workspace:^" diff --git a/packages/convert/src/telethon/parse.ts b/packages/convert/src/telethon/parse.ts index c5df6f20..e4a4cc5e 100644 --- a/packages/convert/src/telethon/parse.ts +++ b/packages/convert/src/telethon/parse.ts @@ -1,6 +1,6 @@ import { MtArgumentError } from '@mtcute/core' import { base64, typed } from '@fuman/utils' -import { ip } from '@fuman/ip' +import { ip } from '@fuman/net' import type { TelethonSession } from './types.js' diff --git a/packages/convert/src/telethon/serialize.ts b/packages/convert/src/telethon/serialize.ts index 6ba34d69..8bb5a27b 100644 --- a/packages/convert/src/telethon/serialize.ts +++ b/packages/convert/src/telethon/serialize.ts @@ -1,6 +1,6 @@ import { MtArgumentError } from '@mtcute/core' import { base64, typed } from '@fuman/utils' -import { ip } from '@fuman/ip' +import { ip } from '@fuman/net' import type { TelethonSession } from './types.js' diff --git a/packages/core/package.json b/packages/core/package.json index aa532dcb..067763f3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -12,8 +12,7 @@ "./utils.js": "./src/utils/index.ts", "./client.js": "./src/highlevel/client.ts", "./worker.js": "./src/highlevel/worker/index.ts", - "./methods.js": "./src/highlevel/methods.ts", - "./platform.js": "./src/platform.ts" + "./methods.js": "./src/highlevel/methods.ts" }, "scripts": { "build": "pnpm run -w build-package core", diff --git a/packages/core/src/highlevel/base.ts b/packages/core/src/highlevel/base.ts index 25270074..9d5ebbc4 100644 --- a/packages/core/src/highlevel/base.ts +++ b/packages/core/src/highlevel/base.ts @@ -23,6 +23,7 @@ import { writeStringSession, } from '../utils/index.js' import { LogManager } from '../utils/logger.js' +import type { ICorePlatform } from '../types/platform' import type { ConnectionState, ITelegramClient, ServerUpdateHandler } from './client.types.js' import { AppConfigManager } from './managers/app-config-manager.js' @@ -57,9 +58,11 @@ export class BaseTelegramClient implements ITelegramClient { readonly mt: MtClient readonly crypto: ICryptoProvider readonly storage: TelegramStorageManager + readonly platform: ICorePlatform constructor(readonly params: BaseTelegramClientOptions) { - this.log = this.params.logger ?? new LogManager('client') + this.log = this.params.logger ?? new LogManager('client', params.platform) + this.platform = this.params.platform this.mt = new MtClient({ ...this.params, logger: this.log.create('mtproto'), @@ -238,11 +241,12 @@ export class BaseTelegramClient implements ITelegramClient { if (defaultDcAuthKey && !force) return const data = typeof session === 'string' ? readStringSession(session) : session + const testMode = data.primaryDcs.main.testMode - if (data.testMode && !this.params.testMode) { + if (testMode && !this.params.testMode) { throw new Error( 'This session string is not for the current backend. ' - + `Session is ${data.testMode ? 'test' : 'prod'}, ` + + `Session is ${testMode ? 'test' : 'prod'}, ` + `but the client is ${this.params.testMode ? 'test' : 'prod'}`, ) } @@ -285,7 +289,6 @@ export class BaseTelegramClient implements ITelegramClient { return writeStringSession({ version: 3, self: await this.storage.self.fetch(), - testMode: Boolean(this.params.testMode), primaryDcs, authKey, }) diff --git a/packages/core/src/highlevel/client.ts b/packages/core/src/highlevel/client.ts index afa68454..f683e224 100644 --- a/packages/core/src/highlevel/client.ts +++ b/packages/core/src/highlevel/client.ts @@ -281,7 +281,7 @@ import { withParams } from './methods/misc/with-params.js' // from methods/_init.ts // @copy type TelegramClientOptions = ( - | (PartialOnly, 'transport' | 'crypto'> & { + | (PartialOnly, 'transport' | 'crypto' | 'platform'> & { /** * Storage to use for this client. * diff --git a/packages/core/src/highlevel/client.types.ts b/packages/core/src/highlevel/client.types.ts index 4a3ff48d..70c7b9a0 100644 --- a/packages/core/src/highlevel/client.types.ts +++ b/packages/core/src/highlevel/client.types.ts @@ -4,6 +4,7 @@ import type Long from 'long' import type { ConnectionKind, RpcCallOptions } from '../network/index.js' import type { MustEqual, PublicPart } from '../types/utils.js' import type { Logger } from '../utils/logger.js' +import type { ICorePlatform } from '../types/platform' import type { AppConfigManager } from './managers/app-config-manager.js' import type { TelegramStorageManager } from './storage/storage.js' @@ -35,6 +36,7 @@ export interface ITelegramClient { readonly storage: PublicPart readonly appConfig: PublicPart readonly stopSignal: AbortSignal + readonly platform: ICorePlatform prepare(): Promise connect(): Promise diff --git a/packages/core/src/highlevel/methods/_init.ts b/packages/core/src/highlevel/methods/_init.ts index 5e702d14..cc192351 100644 --- a/packages/core/src/highlevel/methods/_init.ts +++ b/packages/core/src/highlevel/methods/_init.ts @@ -15,7 +15,7 @@ import { makeParsedUpdateHandler } from '../updates/parsed.js' // @copy type TelegramClientOptions = ( - | (PartialOnly, 'transport' | 'crypto'> & { + | (PartialOnly, 'transport' | 'crypto' | 'platform'> & { /** * Storage to use for this client. * diff --git a/packages/core/src/highlevel/methods/files/normalize-input-media.ts b/packages/core/src/highlevel/methods/files/normalize-input-media.ts index 1380b6c9..6282a7b9 100644 --- a/packages/core/src/highlevel/methods/files/normalize-input-media.ts +++ b/packages/core/src/highlevel/methods/files/normalize-input-media.ts @@ -2,7 +2,6 @@ import Long from 'long' import { parseFileId, tdFileId } from '@mtcute/file-id' import { tl } from '@mtcute/tl' -import { getPlatform } from '../../../platform.js' import { assertTypeIs } from '../../../utils/type-assertions.js' import type { ITelegramClient } from '../../client.types.js' import { isUploadedFile } from '../../types/files/uploaded-file.js' @@ -321,7 +320,7 @@ export async function _normalizeInputMedia( } else if (typeof input === 'string' && input.match(/^file:/)) { await upload(input.substring(5)) } else { - const parsed = typeof input === 'string' ? parseFileId(getPlatform(), input) : input + const parsed = typeof input === 'string' ? parseFileId(input) : input if (parsed.location._ === 'photo') { return { diff --git a/packages/core/src/highlevel/methods/files/upload-file.ts b/packages/core/src/highlevel/methods/files/upload-file.ts index 113d2a40..f29b5211 100644 --- a/packages/core/src/highlevel/methods/files/upload-file.ts +++ b/packages/core/src/highlevel/methods/files/upload-file.ts @@ -3,7 +3,6 @@ import type { IReadable } from '@fuman/io' import { read } from '@fuman/io' import { AsyncLock } from '@fuman/utils' -import { getPlatform } from '../../../platform.js' import { MtArgumentError } from '../../../types/errors.js' import { randomLong } from '../../../utils/long-utils.js' import type { ITelegramClient } from '../../client.types.js' @@ -111,10 +110,8 @@ export async function uploadFile( let fileName = params.fileName let fileMime = params.fileMime - const platform = getPlatform() - - if (platform.normalizeFile) { - const res = await platform.normalizeFile(file) + if (client.platform.normalizeFile) { + const res = await client.platform.normalizeFile(file) if (res?.file) { file = res.file diff --git a/packages/core/src/highlevel/types/media/document.ts b/packages/core/src/highlevel/types/media/document.ts index 8b66274b..9f1218bc 100644 --- a/packages/core/src/highlevel/types/media/document.ts +++ b/packages/core/src/highlevel/types/media/document.ts @@ -1,7 +1,6 @@ import { tdFileId as td, toFileId, toUniqueFileId } from '@mtcute/file-id' import type { tl } from '@mtcute/tl' -import { getPlatform } from '../../../platform.js' import { makeInspectable } from '../../utils/index.js' import { memoizeGetters } from '../../utils/memoize.js' import { FileLocation } from '../files/index.js' @@ -125,7 +124,7 @@ export abstract class RawDocument extends FileLocation { * representing this document. */ get fileId(): string { - return toFileId(getPlatform(), { + return toFileId({ type: this._fileIdType(), dcId: this.raw.dcId, fileReference: this.raw.fileReference, @@ -141,7 +140,7 @@ export abstract class RawDocument extends FileLocation { * Get a unique File ID representing this document. */ get uniqueFileId(): string { - return toUniqueFileId(getPlatform(), td.FileType.Document, { + return toUniqueFileId(td.FileType.Document, { _: 'common', id: this.raw.id, }) diff --git a/packages/core/src/highlevel/types/media/thumbnail.ts b/packages/core/src/highlevel/types/media/thumbnail.ts index 3bfd54d7..b4f4aad6 100644 --- a/packages/core/src/highlevel/types/media/thumbnail.ts +++ b/packages/core/src/highlevel/types/media/thumbnail.ts @@ -2,7 +2,6 @@ import Long from 'long' import { tdFileId as td, toFileId, toUniqueFileId } from '@mtcute/file-id' import type { tl } from '@mtcute/tl' -import { getPlatform } from '../../../platform.js' import { MtArgumentError, MtTypeAssertionError } from '../../../types/errors.js' import { assertTypeIs } from '../../../utils/type-assertions.js' import { inflateSvgPath, strippedPhotoToJpg, svgPathToFile } from '../../utils/file-utils.js' @@ -204,7 +203,7 @@ export class Thumbnail extends FileLocation { } if (this._media._ === 'stickerSet') { - return toFileId(getPlatform(), { + return toFileId({ type: td.FileType.Thumbnail, dcId: this.dcId!, fileReference: null, @@ -222,7 +221,7 @@ export class Thumbnail extends FileLocation { }) } - return toFileId(getPlatform(), { + return toFileId({ type: this._media._ === 'photo' ? td.FileType.Photo : td.FileType.Thumbnail, dcId: this.dcId!, fileReference: this._media.fileReference, @@ -251,7 +250,7 @@ export class Thumbnail extends FileLocation { } if (this._media._ === 'stickerSet') { - return toUniqueFileId(getPlatform(), td.FileType.Thumbnail, { + return toUniqueFileId(td.FileType.Thumbnail, { _: 'photo', id: Long.ZERO, source: { @@ -263,7 +262,7 @@ export class Thumbnail extends FileLocation { }) } - return toUniqueFileId(getPlatform(), this._media._ === 'photo' ? td.FileType.Photo : td.FileType.Thumbnail, { + return toUniqueFileId(this._media._ === 'photo' ? td.FileType.Photo : td.FileType.Thumbnail, { _: 'photo', id: this._media.id, source: { diff --git a/packages/core/src/highlevel/types/peers/chat-photo.ts b/packages/core/src/highlevel/types/peers/chat-photo.ts index bbc6463a..a907314e 100644 --- a/packages/core/src/highlevel/types/peers/chat-photo.ts +++ b/packages/core/src/highlevel/types/peers/chat-photo.ts @@ -2,7 +2,6 @@ import Long from 'long' import { tdFileId, toFileId, toUniqueFileId } from '@mtcute/file-id' import type { tl } from '@mtcute/tl' -import { getPlatform } from '../../../platform.js' import { MtArgumentError } from '../../../types/errors.js' import { toggleChannelIdMark } from '../../../utils/peer-utils.js' import { strippedPhotoToJpg } from '../../utils/file-utils.js' @@ -62,7 +61,7 @@ export class ChatPhotoSize extends FileLocation { throw new MtArgumentError('Input peer was invalid') } - return toFileId(getPlatform(), { + return toFileId({ dcId: this.obj.dcId, type: tdFileId.FileType.ProfilePhoto, fileReference: null, @@ -84,7 +83,7 @@ export class ChatPhotoSize extends FileLocation { * TDLib and Bot API compatible unique File ID representing this size */ get uniqueFileId(): string { - return toUniqueFileId(getPlatform(), tdFileId.FileType.ProfilePhoto, { + return toUniqueFileId(tdFileId.FileType.ProfilePhoto, { _: 'photo', id: this.obj.photoId, // eslint-disable-next-line ts/no-unsafe-assignment diff --git a/packages/core/src/highlevel/utils/convert-file-id.ts b/packages/core/src/highlevel/utils/convert-file-id.ts index 6b739f48..4a334b5d 100644 --- a/packages/core/src/highlevel/utils/convert-file-id.ts +++ b/packages/core/src/highlevel/utils/convert-file-id.ts @@ -3,7 +3,6 @@ import { parseFileId, tdFileId as td } from '@mtcute/file-id' import type { tl } from '@mtcute/tl' import { parseMarkedPeerId } from '../../utils/peer-utils.js' -import { getPlatform } from '../../platform.js' import { assertNever } from '../../types/utils.js' import FileType = td.FileType @@ -45,7 +44,7 @@ function dialogPhotoToInputPeer( * @param fileId File ID, either parsed or as a string */ export function fileIdToInputWebFileLocation(fileId: string | FileId): tl.RawInputWebFileLocation { - if (typeof fileId === 'string') fileId = parseFileId(getPlatform(), fileId) + if (typeof fileId === 'string') fileId = parseFileId(fileId) if (fileId.location._ !== 'web') { throw new td.ConversionError('inputWebFileLocation') @@ -65,7 +64,7 @@ export function fileIdToInputWebFileLocation(fileId: string | FileId): tl.RawInp * @param fileId File ID, either parsed or as a string */ export function fileIdToInputFileLocation(fileId: string | FileId): tl.TypeInputFileLocation { - if (typeof fileId === 'string') fileId = parseFileId(getPlatform(), fileId) + if (typeof fileId === 'string') fileId = parseFileId(fileId) const loc = fileId.location @@ -219,7 +218,7 @@ export function fileIdToInputFileLocation(fileId: string | FileId): tl.TypeInput * @param fileId File ID, either parsed or as a string */ export function fileIdToInputDocument(fileId: string | FileId): tl.RawInputDocument { - if (typeof fileId === 'string') fileId = parseFileId(getPlatform(), fileId) + if (typeof fileId === 'string') fileId = parseFileId(fileId) if ( fileId.location._ !== 'common' @@ -256,7 +255,7 @@ export function fileIdToInputDocument(fileId: string | FileId): tl.RawInputDocum * @param fileId File ID, either parsed or as a string */ export function fileIdToInputPhoto(fileId: string | FileId): tl.RawInputPhoto { - if (typeof fileId === 'string') fileId = parseFileId(getPlatform(), fileId) + if (typeof fileId === 'string') fileId = parseFileId(fileId) if (fileId.location._ !== 'photo') { throw new td.ConversionError('inputPhoto') @@ -281,7 +280,7 @@ export function fileIdToInputPhoto(fileId: string | FileId): tl.RawInputPhoto { * @param fileId File ID, either parsed or as a string */ export function fileIdToEncryptedFile(fileId: string | FileId): tl.RawInputEncryptedFile { - if (typeof fileId === 'string') fileId = parseFileId(getPlatform(), fileId) + if (typeof fileId === 'string') fileId = parseFileId(fileId) if (fileId.location._ !== 'common' || fileId.type !== FileType.Encrypted) { throw new td.ConversionError('inputEncryptedFile') @@ -301,7 +300,7 @@ export function fileIdToEncryptedFile(fileId: string | FileId): tl.RawInputEncry * @param fileId File ID, either parsed or as a string */ export function fileIdToSecureFile(fileId: string | FileId): tl.RawInputSecureFile { - if (typeof fileId === 'string') fileId = parseFileId(getPlatform(), fileId) + if (typeof fileId === 'string') fileId = parseFileId(fileId) if (fileId.location._ !== 'common' || (fileId.type !== FileType.Secure && fileId.type !== FileType.SecureRaw)) { throw new td.ConversionError('inputSecureFile') diff --git a/packages/core/src/highlevel/utils/query-batcher.test.ts b/packages/core/src/highlevel/utils/query-batcher.test.ts index 17b32dad..f4585ac6 100644 --- a/packages/core/src/highlevel/utils/query-batcher.test.ts +++ b/packages/core/src/highlevel/utils/query-batcher.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { StubTelegramClient } from '@mtcute/test' +import { sleep } from '@fuman/utils' -import { sleep } from '../../utils/misc-utils.js' import type { ITelegramClient } from '../client.types.js' import { batchedQuery } from './query-batcher.js' diff --git a/packages/core/src/highlevel/worker/port.ts b/packages/core/src/highlevel/worker/port.ts index 4c72a1fc..8c2688ba 100644 --- a/packages/core/src/highlevel/worker/port.ts +++ b/packages/core/src/highlevel/worker/port.ts @@ -6,6 +6,7 @@ import { LogManager } from '../../utils/logger.js' import type { ConnectionState, ITelegramClient, ServerUpdateHandler } from '../client.types.js' import { PeersIndex } from '../types/peers/peers-index.js' import type { RawUpdateHandler } from '../updates/types.js' +import type { ICorePlatform } from '../../types/platform' import { AppConfigManagerProxy } from './app-config.js' import { WorkerInvoker } from './invoker.js' @@ -15,10 +16,12 @@ import { TelegramStorageProxy } from './storage.js' export interface TelegramWorkerPortOptions { worker: SomeWorker + platform: ICorePlatform } export abstract class TelegramWorkerPort implements ITelegramClient { readonly log: LogManager + readonly platform: ICorePlatform private _connection private _invoker @@ -51,7 +54,8 @@ export abstract class TelegramWorkerPort imp readonly stopSignal: AbortSignal = this._abortController.signal constructor(readonly options: TelegramWorkerPortOptions) { - this.log = new LogManager('worker') + this.log = new LogManager('worker', options.platform) + this.platform = options.platform this._connection = this.connectToWorker(this.options.worker, this._onMessage) this._invoker = new WorkerInvoker(this._connection[0]) diff --git a/packages/core/src/network/auth-key.test.ts b/packages/core/src/network/auth-key.test.ts index 53182feb..5c137f17 100644 --- a/packages/core/src/network/auth-key.test.ts +++ b/packages/core/src/network/auth-key.test.ts @@ -1,6 +1,6 @@ import Long from 'long' import { describe, expect, it, vi } from 'vitest' -import { defaultTestCryptoProvider } from '@mtcute/test' +import { defaultPlatform, defaultTestCryptoProvider } from '@mtcute/test' import type { TlBinaryReader, TlReaderMap } from '@mtcute/tl-runtime' import { hex, utf8 } from '@fuman/utils' @@ -16,7 +16,7 @@ for (let i = 0; i < 256; i += 32) { describe('AuthKey', () => { async function create() { - const logger = new LogManager() + const logger = new LogManager(undefined, defaultPlatform) const readerMap: TlReaderMap = {} const crypto = await defaultTestCryptoProvider() diff --git a/packages/core/src/network/client.ts b/packages/core/src/network/client.ts index 19246b30..928e5c1c 100644 --- a/packages/core/src/network/client.ts +++ b/packages/core/src/network/client.ts @@ -26,6 +26,7 @@ import { defaultTestIpv6Dc, isTlRpcError, } from '../utils/index.js' +import type { ICorePlatform } from '../types/platform.js' import { ConfigManager } from './config-manager.js' import type { NetworkManagerExtraParams, RpcCallOptions } from './network-manager.js' @@ -57,6 +58,8 @@ export interface MtClientOptions { */ crypto: ICryptoProvider + platform: ICorePlatform + /** * Whether to use IPv6 datacenters * (IPv6 will be preferred when choosing a DC by id) @@ -223,7 +226,7 @@ export class MtClient extends EventEmitter { constructor(readonly params: MtClientOptions) { super() - this.log = params.logger ?? new LogManager() + this.log = params.logger ?? new LogManager(undefined, params.platform) if (params.logLevel !== undefined) { this.log.mgr.level = params.logLevel @@ -256,6 +259,7 @@ export class MtClient extends EventEmitter { log: this.log, readerMap: this._readerMap, writerMap: this._writerMap, + platform: params.platform, ...params.storageOptions, }) @@ -282,6 +286,7 @@ export class MtClient extends EventEmitter { onNetworkChanged: connected => this.emit('networkChanged', connected), onUpdate: upd => this.emit('update', upd), stopSignal: this.stopSignal, + platform: params.platform, ...params.network, }, this._config, diff --git a/packages/core/src/network/network-manager.ts b/packages/core/src/network/network-manager.ts index c239075c..363da5a1 100644 --- a/packages/core/src/network/network-manager.ts +++ b/packages/core/src/network/network-manager.ts @@ -4,13 +4,13 @@ import type Long from 'long' import { type ReconnectionStrategy, defaultReconnectionStrategy } from '@fuman/net' import { Deferred } from '@fuman/utils' -import { getPlatform } from '../platform.js' import type { StorageManager } from '../storage/storage.js' import { MtArgumentError, MtUnsupportedError, MtcuteError } from '../types/index.js' import type { ComposedMiddleware, Middleware } from '../utils/composer.js' import { composeMiddlewares } from '../utils/composer.js' import type { DcOptions, ICryptoProvider, Logger } from '../utils/index.js' import { assertTypeIs, isTlRpcError } from '../utils/type-assertions.js' +import type { ICorePlatform } from '../types/platform' import type { ConfigManager } from './config-manager.js' import { basic as defaultMiddlewares } from './middlewares/default.js' @@ -29,6 +29,7 @@ export interface NetworkManagerParams { storage: StorageManager crypto: ICryptoProvider log: Logger + platform: ICorePlatform enableErrorReporting: boolean apiId: number @@ -253,6 +254,7 @@ export class DcConnectionManager { inactivityTimeout: this.manager.params.inactivityTimeout ?? 60_000, enableErrorReporting: this.manager.params.enableErrorReporting, salts: this._salts, + platform: this.manager.params.platform, }) const mainParams = baseConnectionParams() @@ -485,7 +487,7 @@ export class NetworkManager { readonly params: NetworkManagerParams & NetworkManagerExtraParams, readonly config: ConfigManager, ) { - const deviceModel = `mtcute on ${getPlatform().getDeviceModel()}` + const deviceModel = `mtcute on ${params.platform.getDeviceModel()}` this._initConnectionParams = { _: 'initConnection', @@ -616,7 +618,7 @@ export class NetworkManager { throw new MtArgumentError('DC manager already exists') } - this._resetOnNetworkChange = getPlatform().onNetworkChanged?.(this.notifyNetworkChanged.bind(this)) + this._resetOnNetworkChange = this.params.platform.onNetworkChanged?.(this.notifyNetworkChanged.bind(this)) const dc = new DcConnectionManager(this, defaultDcs.main.id, defaultDcs, true) this._dcConnections.set(defaultDcs.main.id, dc) diff --git a/packages/core/src/network/persistent-connection.ts b/packages/core/src/network/persistent-connection.ts index 3c9663fd..a1f83dc6 100644 --- a/packages/core/src/network/persistent-connection.ts +++ b/packages/core/src/network/persistent-connection.ts @@ -149,6 +149,8 @@ export abstract class PersistentConnection extends EventEmitter { private async _onError(err: Error) { this._updateLogPrefix() this.onError(err) + + return 'reconnect' as const } async changeTransport(transport: TelegramTransport): Promise { diff --git a/packages/core/src/network/session-connection.ts b/packages/core/src/network/session-connection.ts index 20476498..14b5fee1 100644 --- a/packages/core/src/network/session-connection.ts +++ b/packages/core/src/network/session-connection.ts @@ -5,7 +5,6 @@ import type { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime' import { TlBinaryReader, TlBinaryWriter, TlSerializationCounter } from '@mtcute/tl-runtime' import { Deferred, u8 } from '@fuman/utils' -import { getPlatform } from '../platform.js' import { MtArgumentError, MtTimeoutError, MtcuteError } from '../types/index.js' import { createAesIgeForMessageOld } from '../utils/crypto/mtproto.js' import type { ICryptoProvider } from '../utils/index.js' @@ -16,6 +15,7 @@ import { removeFromLongArray, timers, } from '../utils/index.js' +import type { ICorePlatform } from '../types/platform' import { doAuthorization } from './authorization.js' import type { MtprotoSession, PendingMessage, PendingRpc } from './mtproto-session.js' @@ -39,6 +39,7 @@ export interface SessionConnectionParams extends PersistentConnectionParams { readerMap: TlReaderMap writerMap: TlWriterMap + platform: ICorePlatform } const TEMP_AUTH_KEY_EXPIRY = 86400 // 24 hours @@ -97,7 +98,7 @@ export class SessionConnection extends PersistentConnection { this._handleRawMessage = this._handleRawMessage.bind(this) this._usePfs = this.params.usePfs ?? false - this._online = getPlatform().isOnline?.() ?? true + this._online = params.platform.isOnline?.() ?? true } private _online diff --git a/packages/core/src/network/transports/obfuscated.test.ts b/packages/core/src/network/transports/obfuscated.test.ts index f11afed4..9d6fdd47 100644 --- a/packages/core/src/network/transports/obfuscated.test.ts +++ b/packages/core/src/network/transports/obfuscated.test.ts @@ -1,23 +1,20 @@ import { describe, expect, it, vi } from 'vitest' -import { defaultTestCryptoProvider } from '@mtcute/test' +import { defaultPlatform, defaultTestCryptoProvider } from '@mtcute/test' import { Bytes } from '@fuman/io' import { hex } from '@fuman/utils' -import { getPlatform } from '../../platform.js' import { LogManager } from '../../utils/index.js' import { IntermediatePacketCodec } from './intermediate.js' import type { MtProxyInfo } from './obfuscated.js' import { ObfuscatedPacketCodec } from './obfuscated.js' -import { TransportError } from './abstract' - -const p = getPlatform() +import { TransportError } from './abstract.js' describe('ObfuscatedPacketCodec', () => { const create = async (randomSource?: string, proxy?: MtProxyInfo) => { const codec = new ObfuscatedPacketCodec(new IntermediatePacketCodec(), proxy) const crypto = await defaultTestCryptoProvider(randomSource) - codec.setup(crypto, new LogManager()) + codec.setup(crypto, new LogManager(undefined, defaultPlatform)) return [codec, crypto] as const } @@ -191,7 +188,7 @@ describe('ObfuscatedPacketCodec', () => { const spyInnerReset = vi.spyOn(inner, 'reset') const codec = new ObfuscatedPacketCodec(inner) - codec.setup(await defaultTestCryptoProvider(), new LogManager()) + codec.setup(await defaultTestCryptoProvider(), new LogManager(undefined, defaultPlatform)) await codec.tag() diff --git a/packages/core/src/platform.ts b/packages/core/src/platform.ts deleted file mode 100644 index 15f005fe..00000000 --- a/packages/core/src/platform.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { UploadFileLike } from './highlevel/types/files/utils.js' -import { MtUnsupportedError } from './types/errors.js' -import type { MaybePromise } from './types/index.js' - -// todo: can we make this non-global? - -export interface ICorePlatform { - beforeExit: (fn: () => void) => () => void - log: (color: number, level: number, tag: string, fmt: string, args: unknown[]) => void - getDefaultLogLevel: () => number | null - getDeviceModel: () => string - normalizeFile?: (file: UploadFileLike) => MaybePromise<{ - file?: UploadFileLike - fileSize?: number - fileName?: string - } | null> - onNetworkChanged?: (fn: (connected: boolean) => void) => () => void - isOnline?: () => boolean -} - -// NB: when using with some bundlers (e.g. vite) re-importing this module will not return the same object -// so we need to store the platform in a global object to be able to survive hot-reloads etc. -// try to use Symbol if available, otherwise fallback to a string -const platformKey = typeof Symbol !== 'undefined' ? Symbol.for('mtcute.platform') : '__MTCUTE_PLATFORM__' - -// eslint-disable-next-line -let _platform: ICorePlatform | null = (globalThis as any)?.[platformKey] ?? null - -export function setPlatform(platform: ICorePlatform): void { - if (_platform) { - if (_platform.constructor !== platform.constructor) { - throw new MtUnsupportedError('Platform may not be changed at runtime!') - } - - return - } - - _platform = platform - - ;(globalThis as any)[platformKey] = platform -} - -export function getPlatform(): ICorePlatform { - if (!_platform) { - throw new MtUnsupportedError('Platform is not set! Have you instantiated the client?') - } - - return _platform -} diff --git a/packages/core/src/storage/driver.ts b/packages/core/src/storage/driver.ts index cb5432c4..a90f6b2c 100644 --- a/packages/core/src/storage/driver.ts +++ b/packages/core/src/storage/driver.ts @@ -1,3 +1,4 @@ +import type { ICorePlatform } from '../types/platform' import type { MaybePromise } from '../types/utils.js' import type { Logger } from '../utils/logger.js' @@ -37,7 +38,7 @@ export interface IStorageDriver { * Setup the driver, passing the logger instance, * in case your driver needs it */ - setup?: (log: Logger) => void + setup?: (log: Logger, platform: ICorePlatform) => void } /** @@ -53,9 +54,11 @@ export abstract class BaseStorageDriver implements IStorageDriver { private _destroyed = false protected _log!: Logger + protected _platform!: ICorePlatform - setup(log: Logger): void { + setup(log: Logger, platform: ICorePlatform): void { this._log = log.create('sqlite') + this._platform = platform } protected get loaded(): boolean { diff --git a/packages/core/src/storage/service/utils.test-utils.ts b/packages/core/src/storage/service/utils.test-utils.ts index abd40a43..445c3ffc 100644 --- a/packages/core/src/storage/service/utils.test-utils.ts +++ b/packages/core/src/storage/service/utils.test-utils.ts @@ -1,5 +1,6 @@ import { __tlReaderMap } from '@mtcute/tl/binary/reader.js' import { __tlWriterMap } from '@mtcute/tl/binary/writer.js' +import { defaultPlatform } from '@mtcute/test' import { LogManager } from '../../utils/logger.js' import { MemoryStorageDriver } from '../memory/driver.js' @@ -7,7 +8,7 @@ import { MemoryStorageDriver } from '../memory/driver.js' import type { ServiceOptions } from './base.js' export function testServiceOptions(): ServiceOptions { - const logger = new LogManager() + const logger = new LogManager(undefined, defaultPlatform) logger.level = 0 return { diff --git a/packages/core/src/storage/sqlite/driver.ts b/packages/core/src/storage/sqlite/driver.ts index 323f3fde..6a8a8616 100644 --- a/packages/core/src/storage/sqlite/driver.ts +++ b/packages/core/src/storage/sqlite/driver.ts @@ -1,4 +1,3 @@ -import { getPlatform } from '../../platform.js' import { BaseStorageDriver } from '../driver.js' import type { ISqliteDatabase, ISqliteStatement } from './types.js' @@ -136,7 +135,7 @@ export abstract class BaseSqliteStorageDriver extends BaseStorageDriver { this.db.transaction(() => this._initialize())() - this._cleanup = getPlatform().beforeExit(() => { + this._cleanup = this._platform.beforeExit(() => { this._save() this._destroy() }) diff --git a/packages/core/src/storage/storage.ts b/packages/core/src/storage/storage.ts index 11b3dde9..6006cbec 100644 --- a/packages/core/src/storage/storage.ts +++ b/packages/core/src/storage/storage.ts @@ -1,8 +1,8 @@ import type { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime' -import { getPlatform } from '../platform.js' import { asyncResettable } from '../utils/index.js' import type { Logger } from '../utils/logger.js' +import type { ICorePlatform } from '../types/platform' import type { IMtStorageProvider } from './provider.js' import { AuthKeysService } from './service/auth-keys.js' @@ -13,6 +13,7 @@ import type { IStorageDriver } from './driver.js' interface StorageManagerOptions { provider: IMtStorageProvider + platform: ICorePlatform log: Logger readerMap: TlReaderMap writerMap: TlWriterMap @@ -44,6 +45,7 @@ export interface StorageManagerExtraOptions { export class StorageManager { readonly provider: IMtStorageProvider readonly driver: IStorageDriver + readonly platform: ICorePlatform readonly log: Logger readonly dcs: DefaultDcsService readonly salts: FutureSaltsService @@ -51,6 +53,7 @@ export class StorageManager { constructor(readonly options: StorageManagerOptions & StorageManagerExtraOptions) { this.provider = this.options.provider + this.platform = this.options.platform this.driver = this.provider.driver this.log = this.options.log.create('storage') @@ -69,10 +72,10 @@ export class StorageManager { private _cleanupRestore?: () => void private _load = asyncResettable(async () => { - this.driver.setup?.(this.log) + this.driver.setup?.(this.log, this.platform) if (this.options.cleanup ?? true) { - this._cleanupRestore = getPlatform().beforeExit(() => { + this._cleanupRestore = this.platform.beforeExit(() => { this._destroy().catch(err => this.log.error('cleanup error: %e', err)) }) } diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts index a7b27468..3931f831 100644 --- a/packages/core/src/types/index.ts +++ b/packages/core/src/types/index.ts @@ -1,3 +1,4 @@ export * from './errors.js' export * from './peers.js' export * from './utils.js' +export * from './platform.js' diff --git a/packages/core/src/types/platform.ts b/packages/core/src/types/platform.ts new file mode 100644 index 00000000..f1611180 --- /dev/null +++ b/packages/core/src/types/platform.ts @@ -0,0 +1,17 @@ +import type { UploadFileLike } from '../highlevel/types/files/utils.js' + +import type { MaybePromise } from './index.js' + +export interface ICorePlatform { + beforeExit: (fn: () => void) => () => void + log: (color: number, level: number, tag: string, fmt: string, args: unknown[]) => void + getDefaultLogLevel: () => number | null + getDeviceModel: () => string + normalizeFile?: (file: UploadFileLike) => MaybePromise<{ + file?: UploadFileLike + fileSize?: number + fileName?: string + } | null> + onNetworkChanged?: (fn: (connected: boolean) => void) => () => void + isOnline?: () => boolean +} diff --git a/packages/core/src/utils/logger.test.ts b/packages/core/src/utils/logger.test.ts index 3ed825b7..90a117bc 100644 --- a/packages/core/src/utils/logger.test.ts +++ b/packages/core/src/utils/logger.test.ts @@ -1,12 +1,13 @@ import Long from 'long' import { describe, expect, it, vi } from 'vitest' import { tl } from '@mtcute/tl' +import { defaultPlatform } from '@mtcute/test' import { LogManager } from './logger.js' describe('logger', () => { const createManager = () => { - const mgr = new LogManager() + const mgr = new LogManager(undefined, defaultPlatform) mgr.level = LogManager.INFO const spy = vi.fn() diff --git a/packages/core/src/utils/logger.ts b/packages/core/src/utils/logger.ts index 763d3aef..78d34180 100644 --- a/packages/core/src/utils/logger.ts +++ b/packages/core/src/utils/logger.ts @@ -1,8 +1,7 @@ import { tl } from '@mtcute/tl' import { hex } from '@fuman/utils' -import type { ICorePlatform } from '../platform.js' -import { getPlatform } from '../platform.js' +import type { ICorePlatform } from '../types/platform.js' import { isTlRpcError } from './type-assertions.js' @@ -160,19 +159,17 @@ export class LogManager extends Logger { static DEBUG = 4 static VERBOSE = 5 - readonly platform: ICorePlatform level: number handler: (color: number, level: number, tag: string, fmt: string, args: unknown[]) => void - constructor(tag = 'base') { + constructor(tag = 'base', platform: ICorePlatform) { // workaround because we cant pass this to super // eslint-disable-next-line ts/no-unsafe-argument super(null as any, tag) ;(this as any).mgr = this - this.platform = getPlatform() - this.level = this.platform.getDefaultLogLevel() ?? DEFAULT_LOG_LEVEL - this.handler = this.platform.log.bind(this.platform) + this.level = platform.getDefaultLogLevel() ?? DEFAULT_LOG_LEVEL + this.handler = platform.log.bind(platform) } private _filter: (tag: string) => boolean = defaultFilter diff --git a/packages/deno/src/client.ts b/packages/deno/src/client.ts index edd02cd5..3b729b78 100644 --- a/packages/deno/src/client.ts +++ b/packages/deno/src/client.ts @@ -11,17 +11,17 @@ import { BaseTelegramClient as BaseTelegramClientBase, TelegramClient as TelegramClientBase, } 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, 'transport' | 'crypto'> { + extends PartialOnly, 'transport' | 'crypto' | 'platform'> { /** * Storage to use for this client. * @@ -31,23 +31,14 @@ export interface BaseTelegramClientOptions * @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: {} as any, // todo + transport: TcpTransport, + platform: new DenoPlatform(), ...opts, storage: typeof opts.storage === 'string' diff --git a/packages/deno/src/platform.ts b/packages/deno/src/platform.ts index 4f8f4200..70af8609 100644 --- a/packages/deno/src/platform.ts +++ b/packages/deno/src/platform.ts @@ -1,4 +1,4 @@ -import type { ICorePlatform } from '@mtcute/core/platform.js' +import type { ICorePlatform } from '@mtcute/core' import { defaultLoggingHandler } from './common-internals-web/logging.js' import { beforeExit } from './utils/exit-hook.js' diff --git a/packages/deno/src/sqlite/sqlite.test.ts b/packages/deno/src/sqlite/sqlite.test.ts index fc5ec5fd..bc78ecf4 100644 --- a/packages/deno/src/sqlite/sqlite.test.ts +++ b/packages/deno/src/sqlite/sqlite.test.ts @@ -1,6 +1,7 @@ import { afterAll, beforeAll, describe } from 'vitest' import { LogManager } from '@mtcute/core/utils.js' import { + defaultPlatform, testAuthKeysRepository, testKeyValueRepository, testPeersRepository, @@ -17,7 +18,7 @@ if (import.meta.env.TEST_ENV === 'deno') { const storage = new SqliteStorage(':memory:') beforeAll(async () => { - storage.driver.setup(new LogManager()) + storage.driver.setup(new LogManager(undefined, defaultPlatform), defaultPlatform) await storage.driver.load() }) diff --git a/packages/deno/src/worker.ts b/packages/deno/src/worker.ts index dfa2782d..3cf4ef50 100644 --- a/packages/deno/src/worker.ts +++ b/packages/deno/src/worker.ts @@ -1,11 +1,9 @@ -import { setPlatform } from '@mtcute/core/platform.js' import type { ClientMessageHandler, RespondFn, SendFn, SomeWorker, TelegramWorkerOptions, - TelegramWorkerPortOptions, WorkerCustomMethods, WorkerMessageHandler, } from '@mtcute/core/worker.js' @@ -16,8 +14,10 @@ import { import { DenoPlatform } from './platform.js' -export type { TelegramWorkerOptions, TelegramWorkerPortOptions, WorkerCustomMethods } - +export type { TelegramWorkerOptions, WorkerCustomMethods } +export interface TelegramWorkerPortOptions { + worker: SomeWorker +} let _registered = false export class TelegramWorker extends TelegramWorkerBase { @@ -44,9 +44,11 @@ export class TelegramWorker extends TelegramWorke const platform = new DenoPlatform() export class TelegramWorkerPort extends TelegramWorkerPortBase { - constructor(readonly options: TelegramWorkerPortOptions) { - setPlatform(platform) - super(options) + constructor(options: TelegramWorkerPortOptions) { + super({ + worker: options.worker, + platform, + }) } connectToWorker(worker: SomeWorker, handler: ClientMessageHandler): [SendFn, () => void] { diff --git a/packages/node/src/client.ts b/packages/node/src/client.ts index 7c563f96..07e06905 100644 --- a/packages/node/src/client.ts +++ b/packages/node/src/client.ts @@ -11,15 +11,13 @@ import { BaseTelegramClient as BaseTelegramClientBase, TelegramClient as TelegramClientBase, } from '@mtcute/core/client.js' -import { setPlatform } from '@mtcute/core/platform.js' -import { NodePlatform } from './common-internals-node/platform.js' import { downloadToFile } from './methods/download-file.js' import { downloadAsNodeStream } from './methods/download-node-stream.js' import { SqliteStorage } from './sqlite/index.js' import { NodeCryptoProvider } from './utils/crypto.js' import { TcpTransport } from './utils/tcp.js' -// import { TcpTransport } from './utils/tcp.js' +import { NodePlatform } from './common-internals-node/platform.js' export type { TelegramClientOptions } @@ -34,7 +32,7 @@ try { } catch {} export interface BaseTelegramClientOptions - extends PartialOnly, 'transport' | 'crypto'> { + extends PartialOnly, 'transport' | 'crypto' | 'platform'> { /** * Storage to use for this client. * @@ -45,23 +43,15 @@ export interface BaseTelegramClientOptions */ 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 NodePlatform()) - super({ // eslint-disable-next-line crypto: nativeCrypto ? new nativeCrypto() : new NodeCryptoProvider(), transport: TcpTransport, + platform: new NodePlatform(), ...opts, storage: typeof opts.storage === 'string' diff --git a/packages/node/src/common-internals-node/platform.ts b/packages/node/src/common-internals-node/platform.ts index 06ac456a..e626d1bd 100644 --- a/packages/node/src/common-internals-node/platform.ts +++ b/packages/node/src/common-internals-node/platform.ts @@ -1,14 +1,12 @@ import * as os from 'node:os' -import type { ICorePlatform } from '@mtcute/core/platform.js' +import type { ICorePlatform } from '@mtcute/core' import { normalizeFile } from '../utils/normalize-file.js' import { beforeExit } from './exit-hook.js' import { defaultLoggingHandler } from './logging.js' -const toBuffer = (buf: Uint8Array): Buffer => Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength) - export class NodePlatform implements ICorePlatform { // ICorePlatform declare log: typeof defaultLoggingHandler diff --git a/packages/node/src/sqlite/sqlite.test.ts b/packages/node/src/sqlite/sqlite.test.ts index 4a356f39..dbafe56a 100644 --- a/packages/node/src/sqlite/sqlite.test.ts +++ b/packages/node/src/sqlite/sqlite.test.ts @@ -1,6 +1,7 @@ import { afterAll, beforeAll, describe } from 'vitest' import { LogManager } from '@mtcute/core/utils.js' import { + defaultPlatform, testAuthKeysRepository, testKeyValueRepository, testPeersRepository, @@ -14,7 +15,7 @@ if (import.meta.env.TEST_ENV === 'node') { const storage = new SqliteStorage(':memory:') beforeAll(async () => { - storage.driver.setup(new LogManager()) + storage.driver.setup(new LogManager(undefined, defaultPlatform), defaultPlatform) await storage.driver.load() }) diff --git a/packages/node/src/worker.ts b/packages/node/src/worker.ts index cbffe1e8..f5e9ae5b 100644 --- a/packages/node/src/worker.ts +++ b/packages/node/src/worker.ts @@ -1,13 +1,11 @@ import { Worker, parentPort } from 'node:worker_threads' -import { setPlatform } from '@mtcute/core/platform.js' import type { ClientMessageHandler, RespondFn, SendFn, SomeWorker, TelegramWorkerOptions, - TelegramWorkerPortOptions, WorkerCustomMethods, WorkerMessageHandler, } from '@mtcute/core/worker.js' @@ -18,7 +16,11 @@ import { import { NodePlatform } from './common-internals-node/platform.js' -export type { TelegramWorkerOptions, TelegramWorkerPortOptions, WorkerCustomMethods } +export type { TelegramWorkerOptions, WorkerCustomMethods } + +export interface TelegramWorkerPortOptions { + worker: SomeWorker +} let _registered = false @@ -45,9 +47,11 @@ export class TelegramWorker extends TelegramWorke } export class TelegramWorkerPort extends TelegramWorkerPortBase { - constructor(readonly options: TelegramWorkerPortOptions) { - setPlatform(new NodePlatform()) - super(options) + constructor(options: TelegramWorkerPortOptions) { + super({ + worker: options.worker, + platform: new NodePlatform(), + }) } connectToWorker(worker: SomeWorker, handler: ClientMessageHandler): [SendFn, () => void] { diff --git a/packages/test/src/client.test.ts b/packages/test/src/client.test.ts index 074305f4..b07a1882 100644 --- a/packages/test/src/client.test.ts +++ b/packages/test/src/client.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { getPlatform } from '@mtcute/core/platform.js' +import { hex } from '@fuman/utils' import { StubTelegramClient } from './client.js' import { createStub } from './stub.js' @@ -25,7 +25,7 @@ describe('client stub', () => { const client = new StubTelegramClient() client.onRawMessage((msg) => { - log.push(`message ctor=${getPlatform().hexEncode(msg.subarray(0, 4))}`) + log.push(`message ctor=${hex.encode(msg.subarray(0, 4))}`) client.close().catch(() => {}) }) diff --git a/packages/test/src/client.ts b/packages/test/src/client.ts index cc600ed8..f099855c 100644 --- a/packages/test/src/client.ts +++ b/packages/test/src/client.ts @@ -3,7 +3,7 @@ import { IntermediatePacketCodec, tl } from '@mtcute/core' import type { BaseTelegramClientOptions } from '@mtcute/core/client.js' import { BaseTelegramClient } from '@mtcute/core/client.js' -import { defaultCryptoProvider } from './platform.js' +import { defaultCryptoProvider, defaultPlatform } from './platform.js' import { StubMemoryTelegramStorage } from './storage.js' // import { StubTelegramTransport } from './transport.js' import type { InputResponder } from './types.js' @@ -57,6 +57,7 @@ export class StubTelegramClient extends BaseTelegramClient { packetCodec: () => new IntermediatePacketCodec(), }, crypto: defaultCryptoProvider, + platform: defaultPlatform, ...params, }) } diff --git a/packages/web/src/client.ts b/packages/web/src/client.ts index 9e35b1ab..5b463cc6 100644 --- a/packages/web/src/client.ts +++ b/packages/web/src/client.ts @@ -7,17 +7,16 @@ import { BaseTelegramClient as BaseTelegramClientBase, TelegramClient as TelegramClientBase, } from '@mtcute/core/client.js' -import { setPlatform } from '@mtcute/core/platform.js' import { WebCryptoProvider } from './crypto.js' import { IdbStorage } from './idb/index.js' -import { WebPlatform } from './platform.js' import { WebSocketTransport } from './websocket.js' +import { WebPlatform } from './platform.js' export type { TelegramClientOptions } export interface BaseTelegramClientOptions - extends PartialOnly, 'transport' | 'crypto'> { + extends PartialOnly, 'transport' | 'crypto' | 'platform'> { /** * Storage to use for this client. * @@ -27,23 +26,14 @@ export interface BaseTelegramClientOptions * @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 WebPlatform()) - super({ crypto: new WebCryptoProvider(), transport: new WebSocketTransport(), + platform: new WebPlatform(), ...opts, storage: typeof opts.storage === 'string' diff --git a/packages/web/src/platform.ts b/packages/web/src/platform.ts index 25583d63..26fadf86 100644 --- a/packages/web/src/platform.ts +++ b/packages/web/src/platform.ts @@ -1,4 +1,4 @@ -import type { ICorePlatform } from '@mtcute/core/platform.js' +import type { ICorePlatform } from '@mtcute/core' import { defaultLoggingHandler } from './common-internals-web/logging.js' import { beforeExit } from './exit-hook.js' diff --git a/packages/web/src/worker.ts b/packages/web/src/worker.ts index b7b2d2da..c3636fb7 100644 --- a/packages/web/src/worker.ts +++ b/packages/web/src/worker.ts @@ -1,12 +1,10 @@ /* eslint-disable no-restricted-globals */ -import { setPlatform } from '@mtcute/core/platform.js' import type { ClientMessageHandler, RespondFn, SendFn, SomeWorker, TelegramWorkerOptions, - TelegramWorkerPortOptions, WorkerCustomMethods, WorkerMessageHandler, } from '@mtcute/core/worker.js' @@ -17,8 +15,10 @@ import { import { WebPlatform } from './platform.js' -export type { TelegramWorkerOptions, TelegramWorkerPortOptions, WorkerCustomMethods } - +export type { TelegramWorkerOptions, WorkerCustomMethods } +export interface TelegramWorkerPortOptions { + worker: SomeWorker +} let _registered = false export class TelegramWorker extends TelegramWorkerBase { @@ -103,12 +103,14 @@ export class TelegramWorker extends TelegramWorke } } -const platform = new WebPlatform() +const platform = /* #__PURE__ */ new WebPlatform() export class TelegramWorkerPort extends TelegramWorkerPortBase { - constructor(readonly options: TelegramWorkerPortOptions) { - setPlatform(platform) - super(options) + constructor(options: TelegramWorkerPortOptions) { + super({ + worker: options.worker, + platform, + }) } connectToWorker(worker: SomeWorker, handler: ClientMessageHandler): [SendFn, () => void] { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0321e78..208717ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -132,9 +132,9 @@ importers: packages/convert: dependencies: - '@fuman/ip': + '@fuman/net': specifier: workspace:^ - version: link:../../private/fuman/packages/ip + version: link:../../private/fuman/packages/net '@fuman/utils': specifier: workspace:^ version: link:../../private/fuman/packages/utils