fix: do not use service worker for avatar
All checks were successful
Docs / build (push) Successful in 2m27s

This commit is contained in:
alina 🌸 2025-01-25 09:19:21 +03:00
parent e3bbb0c061
commit a3daff891f
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
3 changed files with 36 additions and 77 deletions

View file

@ -1,55 +0,0 @@
import type { BaseTelegramClient } from '@mtcute/web'
import { downloadAsBuffer, getMe } from '@mtcute/web/methods.js'
import { createInternalClient } from '../utils/telegram.ts'
import { timeout } from '../utils/timeout.ts'
import { getCacheStorage } from './cache.ts'
const clients = new Map<string, BaseTelegramClient>()
export async function clearAvatarCache(accountId: string) {
const cacheKey = new URL(`/sw/avatar/${accountId}`, location.origin)
await (await getCacheStorage()).delete(cacheKey)
}
export async function handleAvatarRequest(accountId: string) {
const cacheKey = new URL(`/sw/avatar/${accountId}`, location.origin)
const cache = await getCacheStorage()
try {
const cachedRes = await timeout(cache.match(cacheKey), 10000)
if (cachedRes) {
return cachedRes
}
} catch {}
let client = clients.get(accountId)
if (!client) {
client = createInternalClient(accountId)
await client.prepare()
clients.set(accountId, client)
}
const self = await getMe(client)
if (!self.photo) {
const res = new Response('No photo', { status: 404 })
await client.close()
await cache.put(cacheKey, res.clone())
return res
}
const buf = await downloadAsBuffer(client, self.photo.big)
await client.close()
const res = new Response(buf, {
headers: {
'Content-Type': 'image/jpeg',
'Cache-Control': 'public, max-age=86400',
'Access-Control-Allow-Origin': '*',
},
})
await cache.put(cacheKey, res.clone())
return res
}

View file

@ -1,6 +1,5 @@
import { unknownToError } from '@fuman/utils' import { unknownToError } from '@fuman/utils'
import { IS_SAFARI } from '../utils/env.ts' import { IS_SAFARI } from '../utils/env.ts'
import { clearAvatarCache, handleAvatarRequest } from './avatar.ts'
import { requestCache } from './cache.ts' import { requestCache } from './cache.ts'
import { type DownloadFileParams, handleDownload, handlePort } from './download/handler.ts' import { type DownloadFileParams, handleDownload, handlePort } from './download/handler.ts'
import { clearCache, handleRuntimeRequest } from './runtime.ts' import { clearCache, handleRuntimeRequest } from './runtime.ts'
@ -9,11 +8,6 @@ import { forgetAllScripts, forgetScript, uploadScript } from './scripts.ts'
declare const self: ServiceWorkerGlobalScope declare const self: ServiceWorkerGlobalScope
async function handleSwRequest(_req: Request, url: URL): Promise<Response> { async function handleSwRequest(_req: Request, url: URL): Promise<Response> {
if (url.pathname.startsWith('/sw/avatar/')) {
const accountId = url.pathname.split('/')[3]
return handleAvatarRequest(accountId)
}
if (url.pathname.startsWith('/sw/runtime/')) { if (url.pathname.startsWith('/sw/runtime/')) {
return handleRuntimeRequest(url) return handleRuntimeRequest(url)
} }
@ -62,7 +56,6 @@ self.onoffline = self.ononline = () => {
export type SwMessage = export type SwMessage =
| { event: 'UPLOAD_SCRIPT', name: string, files: Record<string, string> } | { event: 'UPLOAD_SCRIPT', name: string, files: Record<string, string> }
| { event: 'FORGET_SCRIPT', name: string } | { event: 'FORGET_SCRIPT', name: string }
| { event: 'CLEAR_AVATAR_CACHE', accountId: string }
| { event: 'CLEAR_CACHE' } | { event: 'CLEAR_CACHE' }
| { event: 'DOWNLOAD_FILE', id: string, params: DownloadFileParams, port: MessagePort } | { event: 'DOWNLOAD_FILE', id: string, params: DownloadFileParams, port: MessagePort }
@ -81,10 +74,6 @@ async function handleMessage(msg: SwMessage) {
await forgetAllScripts() await forgetAllScripts()
break break
} }
case 'CLEAR_AVATAR_CACHE': {
clearAvatarCache(msg.accountId)
break
}
} }
} }

View file

@ -4,13 +4,11 @@ import type { CustomApiFields, TelegramAccount } from '../store/accounts.ts'
import { assert, hex } from '@fuman/utils' import { assert, hex } from '@fuman/utils'
import { DC_MAPPING_PROD, DC_MAPPING_TEST } from '@mtcute/convert' import { DC_MAPPING_PROD, DC_MAPPING_TEST } from '@mtcute/convert'
import { tl } from '@mtcute/web' import { tl } from '@mtcute/web'
import { checkPassword, getMe, resendCode, sendCode, signIn, signInBot, signInQr } from '@mtcute/web/methods.js' import { checkPassword, downloadAsBuffer, getMe, resendCode, sendCode, signIn, signInBot, signInQr } from '@mtcute/web/methods.js'
import { readStringSession } from '@mtcute/web/utils.js' import { readStringSession } from '@mtcute/web/utils.js'
import { nanoid } from 'nanoid' import { nanoid } from 'nanoid'
import { renderSVG } from 'uqr' import { renderSVG } from 'uqr'
import { $accounts, $activeAccountId } from '../store/accounts.ts' import { $accounts, $activeAccountId } from '../store/accounts.ts'
import { swInvokeMethod } from '../sw/client.ts'
import { waitForServiceWorkerInit } from '../sw/register.ts'
import { createInternalClient, deleteAccount, importAccount } from '../utils/telegram.ts' import { createInternalClient, deleteAccount, importAccount } from '../utils/telegram.ts'
import { emitEvent } from './utils.ts' import { emitEvent } from './utils.ts'
@ -40,6 +38,8 @@ function getTmpClient(accountId: string): [BaseTelegramClient, () => Promise<voi
} }
} }
let avatarCache: Cache | undefined
async function handleAuthSuccess(accountId: string, user: User) { async function handleAuthSuccess(accountId: string, user: User) {
const client = getClient(accountId) const client = getClient(accountId)
const dcs = await client.mt.storage.dcs.fetch() const dcs = await client.mt.storage.dcs.fetch()
@ -221,13 +221,34 @@ export class ReplWorkerTelegram {
} }
async fetchAvatar(accountId: string) { async fetchAvatar(accountId: string) {
await waitForServiceWorkerInit() if (!avatarCache) {
const res = await fetch(`/sw/avatar/${accountId}/avatar.jpg`) avatarCache = await caches.open('mtcute-repl-avatars')
if (!res.ok) {
return null
} else {
return new Uint8Array(await res.arrayBuffer())
} }
const req = new Request(`/${accountId}.jpg`)
const cached = await avatarCache.match(req)
if (cached) {
if (!cached.ok) return null
return new Uint8Array(await cached.arrayBuffer())
}
const [client, cleanup] = getTmpClient(accountId)
const self = await getMe(client)
let response: Response
let result: Uint8Array | null = null
if (!self.photo) {
response = new Response('No photo', { status: 404 })
result = null
} else {
const buf = await downloadAsBuffer(client, self.photo.big)
response = new Response(buf)
result = buf
}
await cleanup()
await avatarCache.put(req, response)
return result
} }
async importAuthKey(params: { async importAuthKey(params: {
@ -400,12 +421,16 @@ export class ReplWorkerTelegram {
}) { }) {
const { accountId } = params const { accountId } = params
if (!avatarCache) {
avatarCache = await caches.open('mtcute-repl-avatars')
}
await avatarCache.delete(new Request(`/${accountId}.jpg`))
const [client, cleanup] = getTmpClient(accountId) const [client, cleanup] = getTmpClient(accountId)
const self = await getMe(client) const self = await getMe(client)
await cleanup() await cleanup()
await swInvokeMethod({ event: 'CLEAR_AVATAR_CACHE', accountId })
$accounts.set($accounts.get().map((it) => { $accounts.set($accounts.get().map((it) => {
if (it.id === accountId) { if (it.id === accountId) {
return { return {