Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
5.0 KiB
176 lines
5.0 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
/// #if MTPROTO_SW |
|
import '../mtproto/mtproto.worker'; |
|
/// #endif |
|
|
|
import type { Modify, WorkerTaskTemplate, WorkerTaskVoidTemplate } from '../../types'; |
|
import type { WebPushApiManager } from '../mtproto/webPushApiManager'; |
|
import type { PushNotificationObject } from './push'; |
|
import type { ToggleStorageTask } from '../mtproto/mtprotoworker'; |
|
import type { MyUploadFile } from '../mtproto/apiFileManager'; |
|
import { logger, LogTypes } from '../logger'; |
|
import { CancellablePromise } from '../../helpers/cancellablePromise'; |
|
import { CACHE_ASSETS_NAME, requestCache } from './cache'; |
|
import onStreamFetch from './stream'; |
|
import { closeAllNotifications, onPing } from './push'; |
|
import CacheStorageController from '../cacheStorage'; |
|
import { IS_SAFARI } from '../../environment/userAgent'; |
|
|
|
export const log = logger('SW', LogTypes.Error | LogTypes.Debug | LogTypes.Log | LogTypes.Warn); |
|
const ctx = self as any as ServiceWorkerGlobalScope; |
|
export const deferredPromises: Map<WindowClient['id'], {[taskId: string]: CancellablePromise<any>}> = new Map(); |
|
|
|
export interface RequestFilePartTask extends Modify<WorkerTaskTemplate, {id: string}> { |
|
type: 'requestFilePart', |
|
payload: { |
|
docId: DocId, |
|
dcId: number, |
|
offset: number, |
|
limit: number |
|
} |
|
}; |
|
|
|
export interface RequestFilePartTaskResponse extends Modify<WorkerTaskTemplate, {id: string}> { |
|
type: 'requestFilePart', |
|
payload?: MyUploadFile, |
|
originalPayload?: RequestFilePartTask['payload'] |
|
}; |
|
|
|
export interface ServiceWorkerPingTask extends WorkerTaskVoidTemplate { |
|
type: 'ping', |
|
payload: { |
|
localNotifications: boolean, |
|
lang: { |
|
push_action_mute1d: string |
|
push_action_settings: string |
|
push_message_nopreview: string |
|
}, |
|
settings: WebPushApiManager['settings'] |
|
} |
|
}; |
|
|
|
export interface ServiceWorkerNotificationsClearTask extends WorkerTaskVoidTemplate { |
|
type: 'notifications_clear' |
|
}; |
|
|
|
export interface ServiceWorkerPushClickTask extends WorkerTaskVoidTemplate { |
|
type: 'push_click', |
|
payload: PushNotificationObject |
|
}; |
|
|
|
export type ServiceWorkerTask = RequestFilePartTaskResponse | ServiceWorkerPingTask | ServiceWorkerNotificationsClearTask | ToggleStorageTask; |
|
|
|
/// #if !MTPROTO_SW |
|
const taskListeners: { |
|
[type in ServiceWorkerTask['type']]: (task: any, event: ExtendableMessageEvent) => void |
|
} = { |
|
notifications_clear: () => { |
|
closeAllNotifications(); |
|
}, |
|
ping: (task: ServiceWorkerPingTask, event) => { |
|
onPing(task, event); |
|
}, |
|
requestFilePart: (task: RequestFilePartTaskResponse, e: ExtendableMessageEvent) => { |
|
const windowClient = e.source as WindowClient; |
|
const promises = deferredPromises.get(windowClient.id); |
|
if(!promises) { |
|
return; |
|
} |
|
|
|
const promise = promises[task.id]; |
|
if(promise) { |
|
if(task.error) { |
|
promise.reject(task.error); |
|
} else { |
|
promise.resolve(task.payload); |
|
} |
|
|
|
delete promises[task.id]; |
|
} |
|
}, |
|
toggleStorages: (task: ToggleStorageTask) => { |
|
const {enabled, clearWrite} = task.payload; |
|
CacheStorageController.toggleStorage(enabled, clearWrite); |
|
} |
|
}; |
|
ctx.addEventListener('message', (e) => { |
|
const task = e.data as ServiceWorkerTask; |
|
const callback = taskListeners[task.type]; |
|
if(callback) { |
|
callback(task, e); |
|
} |
|
}); |
|
/// #endif |
|
|
|
//const cacheStorage = new CacheStorageController('cachedAssets'); |
|
/* let taskId = 0; |
|
|
|
export function getTaskId() { |
|
return taskId; |
|
} |
|
|
|
export function incrementTaskId() { |
|
return taskId++; |
|
} */ |
|
|
|
const onFetch = (event: FetchEvent): void => { |
|
/// #if !DEBUG |
|
if( |
|
!IS_SAFARI && |
|
event.request.url.indexOf(location.origin + '/') === 0 && |
|
event.request.url.match(/\.(js|css|jpe?g|json|wasm|png|mp3|svg|tgs|ico|woff2?|ttf|webmanifest?)(?:\?.*)?$/) |
|
) { |
|
return event.respondWith(requestCache(event)); |
|
} |
|
/// #endif |
|
|
|
try { |
|
const [, url, scope, params] = /http[:s]+\/\/.*?(\/(.*?)(?:$|\/(.*)$))/.exec(event.request.url) || []; |
|
|
|
//log.debug('[fetch]:', event); |
|
|
|
switch(scope) { |
|
case 'stream': { |
|
onStreamFetch(event, params); |
|
break; |
|
} |
|
} |
|
} catch(err) { |
|
event.respondWith(new Response('', { |
|
status: 500, |
|
statusText: 'Internal Server Error', |
|
})); |
|
} |
|
}; |
|
|
|
const onChangeState = () => { |
|
ctx.onfetch = onFetch; |
|
}; |
|
|
|
ctx.addEventListener('install', (event) => { |
|
log('installing'); |
|
event.waitUntil(ctx.skipWaiting()); // Activate worker immediately |
|
}); |
|
|
|
ctx.addEventListener('activate', (event) => { |
|
log('activating', ctx); |
|
event.waitUntil(ctx.caches.delete(CACHE_ASSETS_NAME)); |
|
event.waitUntil(ctx.clients.claim()); |
|
}); |
|
|
|
ctx.onerror = (error) => { |
|
log.error('error:', error); |
|
}; |
|
|
|
ctx.onunhandledrejection = (error) => { |
|
log.error('onunhandledrejection:', error); |
|
}; |
|
|
|
ctx.onoffline = ctx.ononline = onChangeState; |
|
|
|
onChangeState();
|
|
|