Jsr #27

Merged
teidesu merged 10 commits from jsr into master 2024-04-23 22:53:59 +03:00
7 changed files with 129 additions and 70 deletions
Showing only changes of commit ae8ab45a74 - Show all commits

View file

@ -12,13 +12,14 @@ import { StoriesStealthMode } from './stealth-mode.js'
* Returned by {@link TelegramClient.getAllStories} * Returned by {@link TelegramClient.getAllStories}
*/ */
export class AllStories { export class AllStories {
/** Peers index */
readonly _peers
constructor( constructor(
/** Raw TL object */ /** Raw TL object */
readonly raw: tl.stories.RawAllStories, readonly raw: tl.stories.RawAllStories,
) {} ) {
this._peers = PeersIndex.from(this.raw)
/** Peers index */ }
readonly _peers = PeersIndex.from(this.raw)
/** Whether there are more stories to fetch */ /** Whether there are more stories to fetch */
get hasMore(): boolean { get hasMore(): boolean {

View file

@ -129,9 +129,10 @@ export class StoryRepost {
* List of story viewers. * List of story viewers.
*/ */
export class StoryViewersList { export class StoryViewersList {
constructor(readonly raw: tl.stories.RawStoryViewsList) {} readonly _peers: PeersIndex
constructor(readonly raw: tl.stories.RawStoryViewsList) {
readonly _peers = PeersIndex.from(this.raw) this._peers = PeersIndex.from(this.raw)
}
/** Next offset for pagination */ /** Next offset for pagination */
get next(): string | undefined { get next(): string | undefined {

View file

@ -3,10 +3,13 @@ import { AppConfigManager } from '../managers/app-config-manager.js'
import { WorkerInvoker } from './invoker.js' import { WorkerInvoker } from './invoker.js'
export class AppConfigManagerProxy implements PublicPart<AppConfigManager> { export class AppConfigManagerProxy implements PublicPart<AppConfigManager> {
constructor(readonly invoker: WorkerInvoker) {} readonly get: AppConfigManager['get']
readonly getField
private _bind = this.invoker.makeBinder<AppConfigManager>('app-config') constructor(readonly invoker: WorkerInvoker) {
const bind = invoker.makeBinder<AppConfigManager>('app-config')
readonly get = this._bind('get') this.get = bind('get')
readonly getField = this._bind('getField') this.getField = bind('getField')
}
} }

View file

@ -14,12 +14,68 @@ export interface TelegramWorkerPortOptions {
} }
export abstract class TelegramWorkerPort<Custom extends WorkerCustomMethods> implements ITelegramClient { export abstract class TelegramWorkerPort<Custom extends WorkerCustomMethods> implements ITelegramClient {
constructor(readonly options: TelegramWorkerPortOptions) {} readonly log
private _connection
private _invoker
readonly storage
readonly appConfig
// bound methods
readonly prepare
private _connect
readonly close
readonly notifyLoggedIn
readonly notifyLoggedOut
readonly notifyChannelOpened
readonly notifyChannelClosed
readonly call
readonly importSession
readonly exportSession
readonly handleClientUpdate
readonly getApiCrenetials
readonly getPoolSize
readonly getPrimaryDcId
readonly computeSrpParams
readonly computeNewPasswordHash
readonly startUpdatesLoop
readonly stopUpdatesLoop
constructor(readonly options: TelegramWorkerPortOptions) {
this.log = new LogManager('worker')
this._connection = this.connectToWorker(this.options.worker, this._onMessage)
this._invoker = new WorkerInvoker(this._connection[0])
this.storage = new TelegramStorageProxy(this._invoker)
this.appConfig = new AppConfigManagerProxy(this._invoker)
const bind = this._invoker.makeBinder<ITelegramClient>('client')
this.prepare = bind('prepare')
this._connect = bind('connect')
this.close = bind('close')
this.notifyLoggedIn = bind('notifyLoggedIn')
this.notifyLoggedOut = bind('notifyLoggedOut')
this.notifyChannelOpened = bind('notifyChannelOpened')
this.notifyChannelClosed = bind('notifyChannelClosed')
this.call = bind('call')
this.importSession = bind('importSession')
this.exportSession = bind('exportSession')
this.handleClientUpdate = bind('handleClientUpdate', true)
this.getApiCrenetials = bind('getApiCrenetials')
this.getPoolSize = bind('getPoolSize')
this.getPrimaryDcId = bind('getPrimaryDcId')
this.computeSrpParams = bind('computeSrpParams')
this.computeNewPasswordHash = bind('computeNewPasswordHash')
this.startUpdatesLoop = bind('startUpdatesLoop')
this.stopUpdatesLoop = bind('stopUpdatesLoop')
}
abstract connectToWorker(worker: SomeWorker, handler: ClientMessageHandler): [SendFn, () => void] abstract connectToWorker(worker: SomeWorker, handler: ClientMessageHandler): [SendFn, () => void]
readonly log = new LogManager('worker')
private _serverUpdatesHandler: (updates: tl.TypeUpdates) => void = () => {} private _serverUpdatesHandler: (updates: tl.TypeUpdates) => void = () => {}
onServerUpdate(handler: (updates: tl.TypeUpdates) => void): void { onServerUpdate(handler: (updates: tl.TypeUpdates) => void): void {
this._serverUpdatesHandler = handler this._serverUpdatesHandler = handler
@ -69,13 +125,6 @@ export abstract class TelegramWorkerPort<Custom extends WorkerCustomMethods> imp
} }
} }
private _connection = this.connectToWorker(this.options.worker, this._onMessage)
private _invoker = new WorkerInvoker(this._connection[0])
private _bind = this._invoker.makeBinder<ITelegramClient>('client')
readonly storage = new TelegramStorageProxy(this._invoker)
readonly appConfig = new AppConfigManagerProxy(this._invoker)
private _destroyed = false private _destroyed = false
destroy(terminate = false): void { destroy(terminate = false): void {
if (this._destroyed) return if (this._destroyed) return
@ -91,26 +140,8 @@ export abstract class TelegramWorkerPort<Custom extends WorkerCustomMethods> imp
return this._invoker.invoke('custom', method as string, args) as Promise<ReturnType<Custom[T]>> return this._invoker.invoke('custom', method as string, args) as Promise<ReturnType<Custom[T]>>
} }
readonly prepare = this._bind('prepare')
private _connect = this._bind('connect')
async connect(): Promise<void> { async connect(): Promise<void> {
await this._connect() await this._connect()
await this.storage.self.fetch() // force cache self locally await this.storage.self.fetch() // force cache self locally
} }
readonly close = this._bind('close')
readonly notifyLoggedIn = this._bind('notifyLoggedIn')
readonly notifyLoggedOut = this._bind('notifyLoggedOut')
readonly notifyChannelOpened = this._bind('notifyChannelOpened')
readonly notifyChannelClosed = this._bind('notifyChannelClosed')
readonly call = this._bind('call')
readonly importSession = this._bind('importSession')
readonly exportSession = this._bind('exportSession')
readonly handleClientUpdate = this._bind('handleClientUpdate', true)
readonly getApiCrenetials = this._bind('getApiCrenetials')
readonly getPoolSize = this._bind('getPoolSize')
readonly getPrimaryDcId = this._bind('getPrimaryDcId')
readonly computeSrpParams = this._bind('computeSrpParams')
readonly computeNewPasswordHash = this._bind('computeNewPasswordHash')
readonly startUpdatesLoop = this._bind('startUpdatesLoop')
readonly stopUpdatesLoop = this._bind('stopUpdatesLoop')
} }

View file

@ -8,25 +8,32 @@ import { TelegramStorageManager } from '../storage/storage.js'
import { WorkerInvoker } from './invoker.js' import { WorkerInvoker } from './invoker.js'
class CurrentUserServiceProxy implements PublicPart<CurrentUserService> { class CurrentUserServiceProxy implements PublicPart<CurrentUserService> {
constructor(private _invoker: WorkerInvoker) {} private _store
private _bind = this._invoker.makeBinder<CurrentUserService>('storage-self') private _storeFrom
private _fetch
private _update
constructor(invoker: WorkerInvoker) {
const bind = invoker.makeBinder<CurrentUserService>('storage-self')
this._store = bind('store')
this._storeFrom = bind('storeFrom')
this._fetch = bind('fetch')
this._update = bind('update')
}
private _cached?: CurrentUserInfo | null private _cached?: CurrentUserInfo | null
private _store = this._bind('store')
async store(info: CurrentUserInfo | null): Promise<void> { async store(info: CurrentUserInfo | null): Promise<void> {
await this._store(info) await this._store(info)
this._cached = info this._cached = info
} }
private _storeFrom = this._bind('storeFrom')
async storeFrom(user: tl.TypeUser): Promise<CurrentUserInfo> { async storeFrom(user: tl.TypeUser): Promise<CurrentUserInfo> {
this._cached = await this._storeFrom(user) this._cached = await this._storeFrom(user)
return this._cached return this._cached
} }
private _fetch = this._bind('fetch')
async fetch(): Promise<CurrentUserInfo | null> { async fetch(): Promise<CurrentUserInfo | null> {
if (this._cached) return this._cached if (this._cached) return this._cached
@ -45,7 +52,6 @@ class CurrentUserServiceProxy implements PublicPart<CurrentUserService> {
return this._cached return this._cached
} }
private _update = this._bind('update')
async update(params: Parameters<CurrentUserService['update']>[0]): Promise<void> { async update(params: Parameters<CurrentUserService['update']>[0]): Promise<void> {
await this._update(params) await this._update(params)
this._cached = await this._fetch() this._cached = await this._fetch()
@ -53,28 +59,41 @@ class CurrentUserServiceProxy implements PublicPart<CurrentUserService> {
} }
class PeersServiceProxy implements PublicPart<PeersService> { class PeersServiceProxy implements PublicPart<PeersService> {
constructor(private _invoker: WorkerInvoker) {} readonly updatePeersFrom
private _bind = this._invoker.makeBinder<PeersService>('storage-peers') readonly store
readonly getById
readonly getByPhone
readonly getByUsername
readonly getCompleteById
readonly updatePeersFrom = this._bind('updatePeersFrom') constructor(private _invoker: WorkerInvoker) {
readonly store = this._bind('store') const bind = this._invoker.makeBinder<PeersService>('storage-peers')
readonly getById = this._bind('getById')
readonly getByPhone = this._bind('getByPhone') this.updatePeersFrom = bind('updatePeersFrom')
readonly getByUsername = this._bind('getByUsername') this.store = bind('store')
readonly getCompleteById = this._bind('getCompleteById') this.getById = bind('getById')
this.getByPhone = bind('getByPhone')
this.getByUsername = bind('getByUsername')
this.getCompleteById = bind('getCompleteById')
}
} }
export class TelegramStorageProxy implements PublicPart<TelegramStorageManager> { export class TelegramStorageProxy implements PublicPart<TelegramStorageManager> {
constructor(private _invoker: WorkerInvoker) {} readonly self
readonly peers
private _bind = this._invoker.makeBinder<TelegramStorageManager>('storage') readonly clear
constructor(private _invoker: WorkerInvoker) {
const bind = this._invoker.makeBinder<TelegramStorageManager>('storage')
this.self = new CurrentUserServiceProxy(this._invoker)
this.peers = new PeersServiceProxy(this._invoker)
this.clear = bind('clear')
}
// todo - remove once we move these to updates manager // todo - remove once we move these to updates manager
readonly updates = null as never readonly updates = null as never
readonly refMsgs = null as never readonly refMsgs = null as never
readonly self = new CurrentUserServiceProxy(this._invoker)
readonly peers = new PeersServiceProxy(this._invoker)
readonly clear = this._bind('clear')
} }

View file

@ -14,9 +14,12 @@ interface RateLimitDto {
} }
class MemoryStateRepository implements IStateRepository { class MemoryStateRepository implements IStateRepository {
constructor(readonly _driver: MemoryStorageDriver) {} readonly state
readonly rl
readonly state = this._driver.getState<Map<string, StateDto>>('dispatcher_fsm', () => new Map()) constructor(readonly _driver: MemoryStorageDriver) {
this.state = this._driver.getState<Map<string, StateDto>>('dispatcher_fsm', () => new Map())
this.rl = this._driver.getState<Map<string, RateLimitDto>>('rl', () => new Map())
}
setState(key: string, state: string, ttl?: number | undefined): void { setState(key: string, state: string, ttl?: number | undefined): void {
this.state.set(key, { this.state.set(key, {
@ -56,8 +59,6 @@ class MemoryStateRepository implements IStateRepository {
} }
} }
readonly rl = this._driver.getState<Map<string, RateLimitDto>>('rl', () => new Map())
getRateLimit(key: string, now: number, limit: number, window: number): [number, number] { getRateLimit(key: string, now: number, limit: number, window: number): [number, number] {
// leaky bucket // leaky bucket
const item = this.rl.get(key) const item = this.rl.get(key)
@ -97,7 +98,9 @@ class MemoryStateRepository implements IStateRepository {
} }
export class MemoryStateStorage implements IStateStorageProvider { export class MemoryStateStorage implements IStateStorageProvider {
constructor(readonly driver: MemoryStorageDriver = new MemoryStorageDriver()) {} readonly state
readonly state = new MemoryStateRepository(this.driver) constructor(readonly driver: MemoryStorageDriver = new MemoryStorageDriver()) {
this.state = new MemoryStateRepository(this.driver)
}
} }

View file

@ -116,11 +116,12 @@ class SqliteStateRepository implements IStateRepository {
} }
export class SqliteStateStorage implements IStateStorageProvider { export class SqliteStateStorage implements IStateStorageProvider {
constructor(readonly driver: BaseSqliteStorageDriver) {} readonly state
constructor(readonly driver: BaseSqliteStorageDriver) {
this.state = new SqliteStateRepository(driver)
}
static from(provider: BaseSqliteStorage) { static from(provider: BaseSqliteStorage) {
return new SqliteStateStorage(provider.driver) return new SqliteStateStorage(provider.driver)
} }
readonly state = new SqliteStateRepository(this.driver)
} }