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

/*
* 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();