tweb/public/sw.js.map
morethanwords b7792aabf1 Build
2022-01-15 03:22:12 +04:00

1 line
99 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/config/modes.ts","webpack:///./src/config/debug.ts","webpack:///./src/environment/ctx.ts","webpack:///./src/environment/userAgent.ts","webpack:///./src/helpers/context.ts","webpack:///./src/lib/logger.ts","webpack:///./src/lib/serviceWorker/cache.ts","webpack:///./src/helpers/schedulers/pause.ts","webpack:///./src/helpers/blob.ts","webpack:///./src/helpers/noop.ts","webpack:///./src/lib/filemanager.ts","webpack:///./src/lib/cacheStorage.ts","webpack:///./src/lib/serviceWorker/stream.ts","webpack:///./src/helpers/schedulers/debounce.ts","webpack:///./src/helpers/cancellablePromise.ts","webpack:///./src/config/databases/state.ts","webpack:///./src/lib/idb.ts","webpack:///./src/helpers/object.ts","webpack:///./src/lib/serviceWorker/push.ts","webpack:///./src/lib/serviceWorker/index.service.ts","webpack:///./src/lib/serviceWorker/timeout.ts"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","Modes","test","location","search","indexOf","debug","http","ssl","multipleConnections","asServiceWorker","transport","DEBUG","window","self","USER_AGENT","navigator","userAgent","IS_SAFARI","toLowerCase","vendor","platform","maxTouchPoints","MSStream","match","IS_FIREFOX","IS_SERVICE_WORKER","ServiceWorkerGlobalScope","IS_WEB_WORKER","WorkerGlobalScope","getWindowClients","clients","matchAll","includeUncontrolled","type","notifyServiceWorker","all","args","then","listeners","length","slice","forEach","listener","postMessage","notifyWorker","noop","LogTypes","LOG_LEVELS","None","Error","Warn","Log","Debug","_logTimer","Date","now","dT","toFixed","getCallerFunctionNameFromLine","IS_WEBKIT","line","split","splitted","trim","lastIndexOf","STYLES_SUPPORTED","LINE_INDEX","getCallerFunctionName","lines","stack","LOGGER_STYLES","black","red","green","yellow","blue","magenta","cyan","white","methods","logger","prefix","ignoreDebugReset","style","originalPrefix","originalStyle","log","console","method","logType","setPrefix","newPrefix","setLevel","level","reduce","acc","v","bindPrefix","isCorrectResponse","response","ok","status","timeoutRace","promise","Promise","race","ms","resolve","setTimeout","reject","readBlobAs","blob","reader","FileReader","addEventListener","e","target","result","readBlobAsUint8Array","readBlobAsArrayBuffer","buffer","Uint8Array","blobConstruct","blobParts","mimeType","safeMimeType","blobSafeMimeType","Blob","bb","BlobBuilder","blobPart","append","getBlob","blobSupported","this","fileWriter","bytes","arr","write","saveFileCallback","part","push","truncate","finalize","saveToStorage","dbName","useStorage","STORAGES","openDatabase","openDbPromise","caches","open","entryName","timeoutOperation","cache","delete","put","fileName","Response","headers","size","save","callback","rejected","timeout","undefined","res","err","clearTimeout","fakeWriter","getFakeFileWriter","saveFile","catch","enabled","map","storage","deleteAll","cacheStorage","setInterval","keys","requests","filtered","Map","timestamp","request","url","has","set","promises","id","ignoreSearch","ignoreVary","clientId","deferredPromises","find","client","taskId","streams","info","loadedOffsets","Set","destroy","getId","limitPart","STREAM_CHUNK_UPPER_LIMIT","STREAM_CHUNK_MIDDLE_LIMIT","destroyDebounced","fn","shouldRunFirst","shouldRunLast","waitingTimeout","waitingPromise","hadNewCall","_resolve","_reject","debounce","alignedOffset","limit","fromPreload","task","payload","dcId","JSON","stringify","windowClient","deferred","uploadFile","add","deferredHelper","isFulfilled","isRejected","notify","notifyAll","lastNotify","addNotifyListener","finally","cancel","assign","deferredPromise","bytesPromise","saveChunkToCache","preloadChunks","getChunkKey","getFile","error","requestFilePartFromCache","requestFilePartFromWorker","offset","requestFilePart","end","preloadChunk","alignOffset","range","possibleResponse","statusText","responseForSafariFirstRange","Math","ceil","alignLimit","min","ab","byteLength","base","version","stores","db","storeName","storageIsAvailable","fromObject","safeAssign","preserve","onclose","close","createNew","indexedDB","message","finished","onerror","onsuccess","event","calledNew","onabort","transaction","onversionchange","onupgradeneeded","warn","oldVersion","newVersion","store","objectStoreNames","contains","os","createObjectStore","indexes","index","createIndex","indexName","keyPath","objectParameters","Array","isArray","concat","getObjectStore","objectStore","clear","idx","perf","performance","oncomplete","results","getAll","defaultBaseUrl","protocol","hostname","pathname","join","defaults","push_mute_until","push_last_alive","push_lang","push_settings","obj","data","json","hasActiveWindows","checksPromise","muteUntil","lastAliveTime","clientList","nowTime","userInvisibleIsSupported","badge","reason","closePromise","settings","lang","icon","peerId","title","body","description","custom","channel_id","chat_id","from_id","tag","nopreview","push_message_nopreview","actions","action","push_action_mute1d","registration","showNotification","notification","notifications","onCloseNotification","fireNotification","closeAllNotifications","waitUntil","pendingNotification","focus","openWindow","baseUrl","getNotifications","len","taskListeners","notifications_clear","ping","ports","source","localNotifications","onPing","toggleStorage","onFetch","origin","respondWith","file","fetch","clone","replace","random","requestCache","scope","params","exec","header","chunks","ranges","parseRange","parse","decodeURIComponent","stream","delay","requestRange","onStreamFetch","onChangeState","onfetch","skipWaiting","claim","onunhandledrejection","onoffline","ononline"],"mappings":"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","file":"sw.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport type { TransportType } from \"../lib/mtproto/dcConfigurator\";\r\n\r\nconst Modes = {\r\n test: location.search.indexOf('test=1') > 0/* || true */,\r\n debug: location.search.indexOf('debug=1') > 0,\r\n http: false,\r\n ssl: true, // location.search.indexOf('ssl=1') > 0 || location.protocol === 'https:' && location.search.indexOf('ssl=0') === -1,\r\n multipleConnections: true,\r\n asServiceWorker: false,\r\n transport: 'websocket' as TransportType\r\n};\r\n\r\n \r\nModes.http = location.search.indexOf('http=1') > 0;\r\n \r\n\r\n \r\n \r\n \r\n\r\nif(Modes.http) {\r\n Modes.transport = 'https';\r\n}\r\n\r\n \r\n \r\n \r\n\r\nexport default Modes;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport Modes from \"./modes\";\r\n\r\nexport const DEBUG = process.env.NODE_ENV !== 'production' || Modes.debug;\r\nconst ctx: any = typeof(window) !== 'undefined' ? window : self;\r\nexport const MOUNT_CLASS_TO: any = DEBUG || true/* && false */ ? ctx : {};\r\nexport default DEBUG;\r\n\r\n//let m = DEBUG;\r\n/* if(!DEBUG) {\r\n ctx.sandpitTurtle = () => {\r\n //if(!m) {\r\n for(let i in MOUNT_CLASS_TO) {\r\n ctx[i] = MOUNT_CLASS_TO[i];\r\n }\r\n //m = true;\r\n //}\r\n \r\n //DEBUG = !DEBUG;\r\n };\r\n} */\r\n\r\n/* export const superDebug = (object: any, key: string) => {\r\n var d = object[key];\r\n var beforeStr = '', afterStr = '';\r\n for(var r of d) {\r\n beforeStr += r.before.hex + '\\n';\r\n afterStr += r.after.hex + '\\n';\r\n }\r\n\r\n beforeStr = beforeStr.trim();\r\n afterStr = afterStr.trim();\r\n //var beforeStr = d.map(r => r.before.hex).join('\\n');\r\n //var afterStr = d.map(r => r.after.hex).join('\\n');\r\n\r\n var dada = (name: string, str: string) => {\r\n var a = document.createElement('a');\r\n a.target = '_blank';\r\n a.download = name + '.txt';\r\n a.href = URL.createObjectURL(new Blob([str], {\r\n type: 'text/plain'\r\n }));\r\n document.body.append(a);\r\n a.click();\r\n };\r\n\r\n dada(key + '_' + 'before', beforeStr);\r\n dada(key + '_' + 'after', afterStr);\r\n}\r\n\r\nMOUNT_CLASS_TO.superDebug = superDebug; */\r\n","const ctx = typeof(window) !== 'undefined' ? window : self;\n\nexport default ctx;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport ctx from './ctx';\r\n\r\nexport const USER_AGENT = navigator ? navigator.userAgent : null;\r\nexport const IS_APPLE = navigator.userAgent.search(/OS X|iPhone|iPad|iOS/i) !== -1;\r\nexport const IS_ANDROID = navigator.userAgent.toLowerCase().indexOf('android') !== -1;\r\nexport const IS_CHROMIUM = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);\r\n\r\n// https://stackoverflow.com/a/58065241\r\nexport const IS_APPLE_MOBILE = (/iPad|iPhone|iPod/.test(navigator.platform) ||\r\n (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&\r\n !(ctx as any).MSStream;\r\n\r\nexport const IS_SAFARI = !!('safari' in ctx) || !!(USER_AGENT && (/\\b(iPad|iPhone|iPod)\\b/.test(USER_AGENT) || (!!USER_AGENT.match('Safari') && !USER_AGENT.match('Chrome'))))/* || true */;\r\nexport const IS_FIREFOX = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;\r\n\r\nexport const IS_MOBILE_SAFARI = IS_SAFARI && IS_APPLE_MOBILE;\r\n\r\nexport const IS_MOBILE = /* screen.width && screen.width < 480 || */navigator.maxTouchPoints > 0 && navigator.userAgent.search(/iOS|iPhone OS|Android|BlackBerry|BB10|Series ?[64]0|J2ME|MIDP|opera mini|opera mobi|mobi.+Gecko|Windows Phone/i) != -1;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n// в SW может быть сразу две переменных TRUE\r\nexport const IS_SERVICE_WORKER = typeof ServiceWorkerGlobalScope !== 'undefined' && self instanceof ServiceWorkerGlobalScope;\r\nexport const IS_WEB_WORKER = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && !IS_SERVICE_WORKER;\r\nexport const IS_WORKER = IS_WEB_WORKER || IS_SERVICE_WORKER;\r\n\r\nexport const getWindowClients = () => {\r\n return (self as any as ServiceWorkerGlobalScope)\r\n .clients\r\n .matchAll({ includeUncontrolled: false, type: 'window' });\r\n};\r\n\r\nconst notifyServiceWorker = (all: boolean, ...args: any[]) => {\r\n (self as any as ServiceWorkerGlobalScope)\r\n .clients\r\n .matchAll({ includeUncontrolled: false, type: 'window' })\r\n .then((listeners) => {\r\n if(!listeners.length) {\r\n //console.trace('no listeners?', self, listeners);\r\n return;\r\n }\r\n\r\n listeners.slice(all ? 0 : -1).forEach(listener => {\r\n // @ts-ignore\r\n listener.postMessage(...args);\r\n });\r\n });\r\n};\r\n\r\nconst notifyWorker = (...args: any[]) => {\r\n // @ts-ignore\r\n (self as any as DedicatedWorkerGlobalScope).postMessage(...args);\r\n};\r\n\r\nconst noop = () => {};\r\n\r\nexport const notifySomeone = IS_SERVICE_WORKER ? notifyServiceWorker.bind(null, false) : (IS_WEB_WORKER ? notifyWorker : noop);\r\nexport const notifyAll = IS_SERVICE_WORKER ? notifyServiceWorker.bind(null, true) : (IS_WEB_WORKER ? notifyWorker : noop);\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport DEBUG from \"../config/debug\";\nimport { IS_FIREFOX, IS_SAFARI } from \"../environment/userAgent\";\nimport { IS_SERVICE_WORKER, IS_WEB_WORKER } from \"../helpers/context\";\n\nexport enum LogTypes {\n None = 0,\n Error = 1,\n Warn = 2,\n Log = 4,\n Debug = 8\n};\n\nexport const LOG_LEVELS = [LogTypes.None, LogTypes.Error, LogTypes.Warn, LogTypes.Log, LogTypes.Debug];\n\nconst _logTimer = Date.now();\nfunction dT() {\n return '[' + ((Date.now() - _logTimer) / 1000).toFixed(3) + ']';\n}\n\nlet getCallerFunctionNameFromLine: (line: string) => string;\n\nconst IS_WEBKIT = IS_SAFARI || IS_FIREFOX;\n\nif(IS_WEBKIT) {\n getCallerFunctionNameFromLine = (line) => {\n const splitted = line.split('@');\n return splitted[0];\n };\n} else {\n getCallerFunctionNameFromLine = (line: string) => {\n const splitted = line.trim().split(' ');\n if(splitted.length === 3) {\n return splitted[1].slice(splitted[1].lastIndexOf('.') + 1);\n }\n };\n}\n\nconst STYLES_SUPPORTED = !IS_WEBKIT;\nconst LINE_INDEX = IS_WEBKIT ? 2 : 3;\n\nfunction getCallerFunctionName() {\n const stack = new Error().stack;\n const lines = stack.split('\\n');\n const line = lines[LINE_INDEX] || lines[lines.length - 1];\n // const match = line.match(/\\.([^\\.]+?)\\s/);\n // line = match ? match[1] : line.trim();\n const caller = getCallerFunctionNameFromLine(line) || '<anonymous>';\n return '[' + caller + ']';\n}\n\nexport const LOGGER_STYLES = {\n reset: \"\\x1b[0m\",\n bright: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n underscore: \"\\x1b[4m\",\n blink: \"\\x1b[5m\",\n reverse: \"\\x1b[7m\",\n hidden: \"\\x1b[8m\",\n // Foreground (text) colors\n fg: {\n black: \"\\x1b[30m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\"\n },\n // Background colors\n bg: {\n black: \"\\x1b[40m\",\n red: \"\\x1b[41m\",\n green: \"\\x1b[42m\",\n yellow: \"\\x1b[43m\",\n blue: \"\\x1b[44m\",\n magenta: \"\\x1b[45m\",\n cyan: \"\\x1b[46m\",\n white: \"\\x1b[47m\"\n }\n};\n\nexport type Logger = {\n (...args: any[]): void;\n warn(...args: any[]): void;\n info(...args: any[]): void;\n error(...args: any[]): void;\n trace(...args: any[]): void;\n debug(...args: any[]): void;\n assert(...args: any[]): void;\n // log(...args: any[]): void;\n setPrefix(newPrefix: string): void;\n setLevel(level: 0 | 1 | 2 | 3 | 4): void;\n bindPrefix(prefix: string): Logger;\n};\n\nconst methods: ['debug' | 'info' | 'warn' | 'error' | 'assert' | 'trace'/* | 'log' */, LogTypes][] = [\n [\"debug\", LogTypes.Debug], \n [\"info\", LogTypes.Log], \n [\"warn\", LogTypes.Warn], \n [\"error\", LogTypes.Error], \n [\"assert\", LogTypes.Error],\n [\"trace\", LogTypes.Log],\n // [\"log\", LogTypes.Log]\n];\n\nexport function logger(prefix: string, type: LogTypes = LogTypes.Log | LogTypes.Warn | LogTypes.Error, ignoreDebugReset = false, style = ''): Logger {\n let originalPrefix: string;\n if(!DEBUG && !ignoreDebugReset/* || true */) {\n type = LogTypes.Error;\n }\n\n if(!STYLES_SUPPORTED) {\n style = '';\n } else if(!style) {\n if(IS_SERVICE_WORKER) style = LOGGER_STYLES.fg.yellow;\n else if(IS_WEB_WORKER) style = LOGGER_STYLES.fg.cyan;\n }\n\n let originalStyle = style;\n if(style) style = `%s ${style}%s`;\n else style = '%s';\n\n //level = LogLevels.log | LogLevels.warn | LogLevels.error | LogLevels.debug\n\n const log: Logger = function(...args: any[]) {\n return type & LogTypes.Log && console.log(style, dT(), prefix, getCallerFunctionName(), ...args);\n } as any;\n\n methods.forEach(([method, logType]) => {\n log[method] = function(...args: any[]) {\n return type & logType && console[method](style, dT(), prefix, getCallerFunctionName(), ...args);\n };\n });\n\n log.setPrefix = function(newPrefix: string) {\n originalPrefix = newPrefix;\n prefix = '[' + newPrefix + ']';\n };\n\n log.setPrefix(prefix);\n\n log.setLevel = function(level: 0 | 1 | 2 | 3 | 4) {\n type = LOG_LEVELS.slice(0, level + 1).reduce((acc, v) => acc | v, 0) as any;\n };\n\n log.bindPrefix = function(prefix: string) {\n return logger(`${originalPrefix}] [${prefix}`, type, ignoreDebugReset, originalStyle);\n };\n\n return log;\n};\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { pause } from \"../../helpers/schedulers/pause\";\r\n\r\nconst ctx = self as any as ServiceWorkerGlobalScope;\r\nexport const CACHE_ASSETS_NAME = 'cachedAssets';\r\n\r\nfunction isCorrectResponse(response: Response) {\r\n return response.ok && response.status === 200;\r\n}\r\n\r\nfunction timeoutRace<T extends Promise<any>>(promise: T) {\r\n return Promise.race([\r\n promise,\r\n pause(10000).then(() => Promise.reject())\r\n ]);\r\n}\r\n\r\nexport async function requestCache(event: FetchEvent) {\r\n try {\r\n // const cache = await ctx.caches.open(CACHE_ASSETS_NAME);\r\n const cache = await timeoutRace(ctx.caches.open(CACHE_ASSETS_NAME));\r\n const file = await timeoutRace(cache.match(event.request, {ignoreVary: true}));\r\n \r\n if(file && isCorrectResponse(file)) {\r\n return file;\r\n }\r\n \r\n const headers: HeadersInit = {'Vary': '*'};\r\n let response = await fetch(event.request, {headers});\r\n if(isCorrectResponse(response)) {\r\n cache.put(event.request, response.clone());\r\n } else if(response.status === 304) { // possible fix for 304 in Safari\r\n const url = event.request.url.replace(/\\?.+$/, '') + '?' + (Math.random() * 100000 | 0);\r\n response = await fetch(url, {headers});\r\n if(isCorrectResponse(response)) {\r\n cache.put(event.request, response.clone());\r\n }\r\n }\r\n \r\n return response;\r\n } catch(err) {\r\n return fetch(event.request);\r\n }\r\n}\r\n","export const pause = (ms: number) => new Promise<void>((resolve) => {\r\n setTimeout(resolve, ms);\r\n});\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nexport function readBlobAs(blob: Blob, method: 'readAsText'): Promise<string>;\r\nexport function readBlobAs(blob: Blob, method: 'readAsDataURL'): Promise<string>;\r\nexport function readBlobAs(blob: Blob, method: 'readAsArrayBuffer'): Promise<ArrayBuffer>;\r\nexport function readBlobAs(blob: Blob, method: 'readAsArrayBuffer' | 'readAsText' | 'readAsDataURL'): Promise<any> {\r\n return new Promise<any>((resolve) => {\r\n const reader = new FileReader();\r\n reader.addEventListener('loadend', (e) => resolve(e.target.result));\r\n reader[method](blob);\r\n });\r\n}\r\n\r\nexport function readBlobAsText(blob: Blob) {\r\n return readBlobAs(blob, 'readAsText');\r\n}\r\n\r\nexport function readBlobAsDataURL(blob: Blob) {\r\n return readBlobAs(blob, 'readAsDataURL');\r\n}\r\n\r\nexport function readBlobAsArrayBuffer(blob: Blob) {\r\n return readBlobAs(blob, 'readAsArrayBuffer');\r\n}\r\n\r\nexport function readBlobAsUint8Array(blob: Blob) {\r\n return readBlobAsArrayBuffer(blob).then(buffer => new Uint8Array(buffer));\r\n}\r\n\r\nexport function blobConstruct(blobParts: any, mimeType: string = ''): Blob {\r\n let blob;\r\n const safeMimeType = blobSafeMimeType(mimeType);\r\n try {\r\n blob = new Blob(blobParts, {type: safeMimeType});\r\n } catch(e) {\r\n // @ts-ignore\r\n let bb = new BlobBuilder;\r\n blobParts.forEach((blobPart: any) => {\r\n bb.append(blobPart);\r\n });\r\n blob = bb.getBlob(safeMimeType);\r\n }\r\n return blob;\r\n}\r\n\r\n// https://www.iana.org/assignments/media-types/media-types.xhtml\r\nexport function blobSafeMimeType(mimeType: string) {\r\n if([\r\n 'image/jpeg',\r\n 'image/png',\r\n 'image/gif',\r\n 'image/webp',\r\n 'image/bmp',\r\n 'video/mp4',\r\n 'video/webm',\r\n 'video/quicktime',\r\n 'audio/ogg',\r\n 'audio/mpeg',\r\n 'audio/mp4',\r\n 'application/json',\r\n 'application/pdf'\r\n ].indexOf(mimeType) === -1) {\r\n return 'application/octet-stream';\r\n }\r\n\r\n return mimeType;\r\n}\r\n","export default function noop() {}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { blobConstruct, readBlobAsUint8Array } from \"../helpers/blob\";\r\n\r\nexport class FileManager {\r\n public blobSupported = true;\r\n \r\n constructor() {\r\n try {\r\n blobConstruct([], '');\r\n } catch(e) {\r\n this.blobSupported = false;\r\n }\r\n }\r\n \r\n public isAvailable() {\r\n return this.blobSupported;\r\n }\r\n \r\n public write(fileWriter: ReturnType<FileManager['getFakeFileWriter']>, bytes: Uint8Array | Blob | string): Promise<void> {\r\n if(bytes instanceof Blob) { // is file bytes\r\n return readBlobAsUint8Array(bytes).then(arr => {\r\n return fileWriter.write(arr);\r\n });\r\n } else {\r\n return fileWriter.write(bytes);\r\n }\r\n }\r\n\r\n public getFakeFileWriter(mimeType: string, saveFileCallback?: (blob: Blob) => Promise<Blob>) {\r\n const blobParts: Array<Uint8Array | string> = [];\r\n const fakeFileWriter = {\r\n write: async(part: Uint8Array | string) => {\r\n if(!this.blobSupported) {\r\n throw false;\r\n }\r\n \r\n blobParts.push(part);\r\n },\r\n truncate: () => {\r\n blobParts.length = 0;\r\n },\r\n finalize: (saveToStorage = true) => {\r\n const blob = blobConstruct(blobParts, mimeType);\r\n\r\n if(saveToStorage && saveFileCallback) {\r\n saveFileCallback(blob);\r\n }\r\n \r\n return blob;\r\n }\r\n };\r\n \r\n return fakeFileWriter;\r\n }\r\n}\r\n\r\nexport default new FileManager();\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport Modes from '../config/modes';\r\nimport { blobConstruct } from '../helpers/blob';\r\nimport FileManager from './filemanager';\r\n//import { MOUNT_CLASS_TO } from './mtproto/mtproto_config';\r\n//import { logger } from './polyfill';\r\n\r\nexport type CacheStorageDbName = 'cachedFiles' | 'cachedStreamChunks' | 'cachedAssets';\r\n\r\nexport default class CacheStorageController {\r\n private static STORAGES: CacheStorageController[] = [];\r\n private openDbPromise: Promise<Cache>;\r\n\r\n private useStorage = true;\r\n\r\n //private log: ReturnType<typeof logger> = logger('CS');\r\n\r\n constructor(private dbName: CacheStorageDbName) {\r\n if(Modes.test) {\r\n this.dbName += '_test';\r\n }\r\n\r\n if(CacheStorageController.STORAGES.length) {\r\n this.useStorage = CacheStorageController.STORAGES[0].useStorage;\r\n }\r\n \r\n this.openDatabase();\r\n CacheStorageController.STORAGES.push(this);\r\n }\r\n\r\n private openDatabase(): Promise<Cache> {\r\n return this.openDbPromise ?? (this.openDbPromise = caches.open(this.dbName));\r\n }\r\n\r\n public delete(entryName: string) {\r\n return this.timeoutOperation((cache) => cache.delete('/' + entryName));\r\n }\r\n\r\n public deleteAll() {\r\n return caches.delete(this.dbName);\r\n }\r\n\r\n public get(entryName: string) {\r\n return this.timeoutOperation((cache) => cache.match('/' + entryName));\r\n }\r\n\r\n public save(entryName: string, response: Response) {\r\n // return new Promise((resolve) => {}); // DEBUG\r\n return this.timeoutOperation((cache) => cache.put('/' + entryName, response));\r\n }\r\n\r\n public getFile(fileName: string, method: 'blob' | 'json' | 'text' = 'blob'): Promise<any> {\r\n /* if(method === 'blob') {\r\n return Promise.reject();\r\n } */\r\n\r\n // const str = `get fileName: ${fileName}`;\r\n // console.time(str);\r\n return this.get(fileName).then((response) => {\r\n if(!response) {\r\n //console.warn('getFile:', response, fileName);\r\n throw 'NO_ENTRY_FOUND';\r\n }\r\n\r\n const promise = response[method]();\r\n // promise.then(() => {\r\n // console.timeEnd(str);\r\n // });\r\n return promise;\r\n });\r\n }\r\n\r\n public saveFile(fileName: string, blob: Blob | Uint8Array) {\r\n //return Promise.resolve(blobConstruct([blob]));\r\n if(!(blob instanceof Blob)) {\r\n blob = blobConstruct(blob) as Blob;\r\n }\r\n\r\n const response = new Response(blob, {\r\n headers: {\r\n 'Content-Length': '' + blob.size\r\n }\r\n });\r\n \r\n return this.save(fileName, response).then(() => blob as Blob);\r\n }\r\n\r\n public timeoutOperation<T>(callback: (cache: Cache) => Promise<T>) {\r\n if(!this.useStorage) {\r\n return Promise.reject('STORAGE_OFFLINE');\r\n }\r\n\r\n return new Promise<T>(async(resolve, reject) => {\r\n let rejected = false;\r\n const timeout = setTimeout(() => {\r\n reject();\r\n //console.warn('CACHESTORAGE TIMEOUT');\r\n rejected = true;\r\n }, 15e3);\r\n\r\n try {\r\n const cache = await this.openDatabase();\r\n if(!cache) {\r\n this.useStorage = false;\r\n this.openDbPromise = undefined;\r\n throw 'no cache?';\r\n }\r\n\r\n const res = await callback(cache);\r\n\r\n if(rejected) return;\r\n resolve(res);\r\n } catch(err) {\r\n reject(err);\r\n }\r\n\r\n clearTimeout(timeout);\r\n });\r\n }\r\n\r\n public getFileWriter(fileName: string, mimeType: string) {\r\n const fakeWriter = FileManager.getFakeFileWriter(mimeType, (blob) => {\r\n return this.saveFile(fileName, blob).catch(() => blob);\r\n });\r\n\r\n return Promise.resolve(fakeWriter);\r\n }\r\n\r\n public static toggleStorage(enabled: boolean) {\r\n return Promise.all(this.STORAGES.map(storage => {\r\n storage.useStorage = enabled;\r\n \r\n if(!enabled) {\r\n return storage.deleteAll();\r\n }\r\n }));\r\n }\r\n}\r\n\r\n//const cacheStorage = new CacheStorageController(); \r\n//MOUNT_CLASS_TO.cacheStorage = cacheStorage;\r\n//export default cacheStorage;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { readBlobAsUint8Array } from \"../../helpers/blob\";\r\nimport { CancellablePromise, deferredPromise } from \"../../helpers/cancellablePromise\";\r\nimport { getWindowClients } from \"../../helpers/context\";\r\nimport debounce from \"../../helpers/schedulers/debounce\";\r\nimport { InputFileLocation, UploadFile } from \"../../layer\";\r\nimport CacheStorageController from \"../cacheStorage\";\r\nimport { DownloadOptions } from \"../mtproto/apiFileManager\";\r\nimport { RequestFilePartTask, deferredPromises, log } from \"./index.service\";\r\nimport timeout from \"./timeout\";\r\n\r\nconst cacheStorage = new CacheStorageController('cachedStreamChunks');\r\nconst CHUNK_TTL = 86400;\r\nconst CHUNK_CACHED_TIME_HEADER = 'Time-Cached';\r\n\r\nconst clearOldChunks = () => {\r\n return cacheStorage.timeoutOperation((cache) => {\r\n return cache.keys().then(requests => {\r\n const filtered: Map<StreamId, Request> = new Map();\r\n const timestamp = Date.now() / 1000 | 0;\r\n for(const request of requests) {\r\n const match = request.url.match(/\\/(\\d+?)\\?/);\r\n if(match && !filtered.has(match[1])) {\r\n filtered.set(match[1], request);\r\n }\r\n }\r\n\r\n const promises: Promise<any>[] = [];\r\n for(const [id, request] of filtered) {\r\n const promise = cache.match(request).then((response) => {\r\n if((+response.headers.get(CHUNK_CACHED_TIME_HEADER) + CHUNK_TTL) <= timestamp) {\r\n log('will delete stream chunk:', id);\r\n return cache.delete(request, {ignoreSearch: true, ignoreVary: true});\r\n }\r\n });\r\n\r\n promises.push(promise);\r\n }\r\n\r\n return Promise.all(promises);\r\n });\r\n });\r\n};\r\n\r\nsetInterval(clearOldChunks, 1800e3);\r\nsetInterval(() => {\r\n getWindowClients().then((clients) => {\r\n for(const [clientId, promises] of deferredPromises) {\r\n if(!clients.find(client => client.id === clientId)) {\r\n for(const taskId in promises) {\r\n const promise = promises[taskId];\r\n promise.reject();\r\n }\r\n\r\n deferredPromises.delete(clientId);\r\n }\r\n }\r\n });\r\n}, 120e3);\r\n\r\ntype StreamRange = [number, number];\r\ntype StreamId = DocId;\r\nconst streams: Map<StreamId, Stream> = new Map();\r\nclass Stream {\r\n private destroyDebounced: () => void;\r\n private id: StreamId;\r\n private limitPart: number;\r\n private loadedOffsets: Set<number> = new Set();\r\n\r\n constructor(private info: DownloadOptions) {\r\n this.id = Stream.getId(info);\r\n streams.set(this.id, this);\r\n\r\n // ! если грузить очень большое видео чанками по 512Кб в мобильном Safari, то стрим не запустится\r\n this.limitPart = info.size > (75 * 1024 * 1024) ? STREAM_CHUNK_UPPER_LIMIT : STREAM_CHUNK_MIDDLE_LIMIT;\r\n this.destroyDebounced = debounce(this.destroy, 150000, false, true);\r\n }\r\n\r\n private destroy = () => {\r\n streams.delete(this.id);\r\n };\r\n\r\n private async requestFilePartFromWorker(alignedOffset: number, limit: number, fromPreload = false) {\r\n const task: Omit<RequestFilePartTask, 'id'> = {\r\n type: 'requestFilePart',\r\n payload: [this.info.dcId, this.info.location, alignedOffset, limit]\r\n };\r\n\r\n const taskId = JSON.stringify(task);\r\n (task as RequestFilePartTask).id = taskId;\r\n\r\n const windowClient = await getWindowClients().then((clients) => {\r\n if(!clients.length) {\r\n return;\r\n }\r\n\r\n return clients.find(client => deferredPromises.has(client.id)) || clients[0];\r\n });\r\n\r\n if(!windowClient) {\r\n throw new Error('no window');\r\n }\r\n\r\n let promises = deferredPromises.get(windowClient.id);\r\n if(!promises) {\r\n deferredPromises.set(windowClient.id, promises = {});\r\n }\r\n \r\n let deferred = promises[taskId] as CancellablePromise<UploadFile.uploadFile>;\r\n if(deferred) {\r\n return deferred.then(uploadFile => uploadFile.bytes);\r\n }\r\n \r\n windowClient.postMessage(task);\r\n this.loadedOffsets.add(alignedOffset);\r\n \r\n deferred = promises[taskId] = deferredPromise<UploadFile.uploadFile>();\r\n const bytesPromise = deferred.then(uploadFile => uploadFile.bytes);\r\n\r\n this.saveChunkToCache(bytesPromise, alignedOffset, limit);\r\n !fromPreload && this.preloadChunks(alignedOffset, alignedOffset + (this.limitPart * 15));\r\n\r\n return bytesPromise;\r\n }\r\n\r\n private requestFilePartFromCache(alignedOffset: number, limit: number, fromPreload?: boolean) {\r\n const key = this.getChunkKey(alignedOffset, limit);\r\n return cacheStorage.getFile(key).then((blob: Blob) => {\r\n return fromPreload ? new Uint8Array() : readBlobAsUint8Array(blob);\r\n }, (error) => {\r\n if(error === 'NO_ENTRY_FOUND') {\r\n return;\r\n }\r\n });\r\n }\r\n\r\n private requestFilePart(alignedOffset: number, limit: number, fromPreload?: boolean) {\r\n return this.requestFilePartFromCache(alignedOffset, limit, fromPreload).then(bytes => {\r\n return bytes || this.requestFilePartFromWorker(alignedOffset, limit, fromPreload);\r\n });\r\n }\r\n\r\n private saveChunkToCache(deferred: Promise<Uint8Array>, alignedOffset: number, limit: number) {\r\n return deferred.then(bytes => {\r\n const key = this.getChunkKey(alignedOffset, limit);\r\n const response = new Response(bytes, {\r\n headers: {\r\n 'Content-Length': '' + bytes.length,\r\n 'Content-Type': 'application/octet-stream',\r\n [CHUNK_CACHED_TIME_HEADER]: '' + (Date.now() / 1000 | 0)\r\n }\r\n });\r\n\r\n return cacheStorage.save(key, response);\r\n });\r\n }\r\n\r\n private preloadChunk(offset: number) {\r\n if(this.loadedOffsets.has(offset)) {\r\n return;\r\n }\r\n\r\n this.loadedOffsets.add(offset);\r\n this.requestFilePart(offset, this.limitPart, true);\r\n }\r\n\r\n private preloadChunks(offset: number, end: number) {\r\n if(end > this.info.size) {\r\n end = this.info.size;\r\n }\r\n\r\n if(!offset) { // load last chunk for bounds\r\n this.preloadChunk(alignOffset(offset, this.limitPart));\r\n } else { // don't preload next chunks before the start\r\n for(; offset < end; offset += this.limitPart) {\r\n this.preloadChunk(offset);\r\n }\r\n }\r\n }\r\n\r\n public requestRange(range: StreamRange) {\r\n this.destroyDebounced();\r\n\r\n const possibleResponse = responseForSafariFirstRange(range, this.info.mimeType, this.info.size);\r\n if(possibleResponse) {\r\n return possibleResponse;\r\n }\r\n\r\n let [offset, end] = range;\r\n\r\n /* if(info.size > limitPart && isSafari && offset === limitPart) {\r\n //end = info.size - 1;\r\n //offset = info.size - 1 - limitPart;\r\n offset = info.size - (info.size % limitPart);\r\n } */\r\n\r\n const limit = end && end < this.limitPart ? alignLimit(end - offset + 1) : this.limitPart;\r\n const alignedOffset = alignOffset(offset, limit);\r\n\r\n if(!end) {\r\n end = Math.min(offset + limit, this.info.size - 1);\r\n }\r\n\r\n return this.requestFilePart(alignedOffset, limit).then(ab => {\r\n //log.debug('[stream] requestFilePart result:', result);\r\n\r\n // if(isSafari) {\r\n if(offset !== alignedOffset || end !== (alignedOffset + limit)) {\r\n ab = ab.slice(offset - alignedOffset, end - alignedOffset + 1);\r\n }\r\n \r\n const headers: Record<string, string> = {\r\n 'Accept-Ranges': 'bytes',\r\n 'Content-Range': `bytes ${offset}-${offset + ab.byteLength - 1}/${this.info.size || '*'}`,\r\n 'Content-Length': `${ab.byteLength}`\r\n };\r\n\r\n if(this.info.mimeType) {\r\n headers['Content-Type'] = this.info.mimeType;\r\n }\r\n\r\n // simulate slow connection\r\n //setTimeout(() => {\r\n return new Response(ab, {\r\n status: 206,\r\n statusText: 'Partial Content',\r\n headers,\r\n });\r\n //}, 2.5e3);\r\n });\r\n }\r\n\r\n private getChunkKey(alignedOffset: number, limit: number) {\r\n return this.id + '?offset=' + alignedOffset + '&limit=' + limit;\r\n }\r\n\r\n public static get(info: DownloadOptions) {\r\n return streams.get(this.getId(info)) ?? new Stream(info);\r\n }\r\n\r\n private static getId(info: DownloadOptions) {\r\n return (info.location as InputFileLocation.inputDocumentFileLocation).id;\r\n }\r\n}\r\n\r\nexport default function onStreamFetch(event: FetchEvent, params: string) {\r\n const range = parseRange(event.request.headers.get('Range'));\r\n const info: DownloadOptions = JSON.parse(decodeURIComponent(params));\r\n const stream = Stream.get(info);\r\n\r\n //log.debug('[stream]', url, offset, end);\r\n\r\n event.respondWith(Promise.race([\r\n timeout(45 * 1000),\r\n stream.requestRange(range)\r\n ]));\r\n}\r\n\r\nfunction responseForSafariFirstRange(range: StreamRange, mimeType: string, size: number): Response {\r\n if(range[0] === 0 && range[1] === 1) {\r\n return new Response(new Uint8Array(2).buffer, {\r\n status: 206,\r\n statusText: 'Partial Content',\r\n headers: {\r\n 'Accept-Ranges': 'bytes',\r\n 'Content-Range': `bytes 0-1/${size || '*'}`,\r\n 'Content-Length': '2',\r\n 'Content-Type': mimeType || 'video/mp4',\r\n },\r\n });\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/* const STREAM_CHUNK_UPPER_LIMIT = 256 * 1024;\r\nconst SMALLEST_CHUNK_LIMIT = 256 * 4; */\r\n/* const STREAM_CHUNK_UPPER_LIMIT = 1024 * 1024;\r\nconst SMALLEST_CHUNK_LIMIT = 1024 * 4; */\r\nconst STREAM_CHUNK_MIDDLE_LIMIT = 512 * 1024;\r\nconst STREAM_CHUNK_UPPER_LIMIT = 1024 * 1024;\r\nconst SMALLEST_CHUNK_LIMIT = 512 * 4;\r\n\r\nfunction parseRange(header: string): StreamRange {\r\n if(!header) return [0, 0];\r\n const [, chunks] = header.split('=');\r\n const ranges = chunks.split(', ');\r\n const [offset, end] = ranges[0].split('-');\r\n\r\n return [+offset, +end || 0];\r\n}\r\n\r\nfunction alignOffset(offset: number, base = SMALLEST_CHUNK_LIMIT) {\r\n return offset - (offset % base);\r\n}\r\n\r\nfunction alignLimit(limit: number) {\r\n return 2 ** Math.ceil(Math.log(limit) / Math.log(2));\r\n}\r\n","// * Jolly Cobra's schedulers\r\n\r\nimport { AnyFunction, Awaited } from \"../../types\";\r\n\r\nexport default function debounce<F extends AnyFunction>(\r\n fn: F,\r\n ms: number,\r\n shouldRunFirst = true,\r\n shouldRunLast = true,\r\n) {\r\n let waitingTimeout: number;\r\n let waitingPromise: Promise<Awaited<ReturnType<F>>>, resolve: (result: any) => void, reject: () => void;\r\n let hadNewCall = false;\r\n\r\n return (...args: Parameters<F>): typeof waitingPromise => {\r\n if(!waitingPromise) waitingPromise = new Promise((_resolve, _reject) => (resolve = _resolve, reject = _reject));\r\n\r\n if(waitingTimeout) {\r\n clearTimeout(waitingTimeout);\r\n hadNewCall = true;\r\n reject();\r\n waitingPromise = new Promise((_resolve, _reject) => (resolve = _resolve, reject = _reject));\r\n } else if(shouldRunFirst) {\r\n // @ts-ignore\r\n resolve(fn(...args));\r\n hadNewCall = false;\r\n }\r\n\r\n waitingTimeout = setTimeout(() => {\r\n // will run if should run last or first but with new call\r\n if(shouldRunLast && (!shouldRunFirst || hadNewCall)) {\r\n // @ts-ignore\r\n resolve(fn(...args));\r\n }\r\n\r\n waitingTimeout = waitingPromise = resolve = reject = undefined;\r\n hadNewCall = false;\r\n }, ms) as any;\r\n\r\n waitingPromise.catch(() => {});\r\n return waitingPromise;\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport noop from \"./noop\";\r\n\r\nexport interface CancellablePromise<T> extends Promise<T> {\r\n resolve?: (value: T) => void,\r\n reject?: (...args: any[]) => void,\r\n cancel?: () => void,\r\n\r\n notify?: (...args: any[]) => void,\r\n notifyAll?: (...args: any[]) => void,\r\n lastNotify?: any,\r\n listeners?: Array<(...args: any[]) => void>,\r\n addNotifyListener?: (callback: (...args: any[]) => void) => void,\r\n\r\n isFulfilled?: boolean,\r\n isRejected?: boolean\r\n}\r\n\r\nexport function deferredPromise<T>() {\r\n let deferredHelper: any = {\r\n isFulfilled: false, \r\n isRejected: false,\r\n\r\n notify: () => {}, \r\n notifyAll: (...args: any[]) => {\r\n deferredHelper.lastNotify = args;\r\n deferredHelper.listeners.forEach((callback: any) => callback(...args));\r\n }, \r\n\r\n listeners: [],\r\n addNotifyListener: (callback: (...args: any[]) => void) => {\r\n if(deferredHelper.lastNotify) {\r\n callback(...deferredHelper.lastNotify);\r\n }\r\n\r\n deferredHelper.listeners.push(callback);\r\n }\r\n };\r\n\r\n let deferred: CancellablePromise<T> = new Promise<T>((resolve, reject) => {\r\n deferredHelper.resolve = (value: T) => {\r\n if(deferred.isFulfilled || deferred.isRejected) return;\r\n\r\n deferred.isFulfilled = true;\r\n resolve(value);\r\n };\r\n \r\n deferredHelper.reject = (...args: any[]) => {\r\n if(deferred.isRejected || deferred.isFulfilled) return;\r\n \r\n deferred.isRejected = true;\r\n reject(...args);\r\n };\r\n });\r\n\r\n // @ts-ignore\r\n /* deferred.then = (resolve: (value: T) => any, reject: (...args: any[]) => any) => {\r\n const n = deferredPromise<ReturnType<typeof resolve>>();\r\n \r\n }; */\r\n\r\n deferred.catch(noop).finally(() => {\r\n deferred.notify = deferred.notifyAll = deferred.lastNotify = null;\r\n deferred.listeners.length = 0;\r\n\r\n if(deferred.cancel) {\r\n deferred.cancel = () => {};\r\n }\r\n });\r\n\r\n Object.assign(deferred, deferredHelper);\r\n\r\n return deferred;\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { Database } from '.';\r\n\r\nconst DATABASE_STATE: Database<'session' | 'stickerSets' | 'users' | 'chats' | 'messages' | 'dialogs'> = {\r\n name: 'tweb',\r\n version: 7,\r\n stores: [{\r\n name: 'session'\r\n }, {\r\n name: 'stickerSets'\r\n }, {\r\n name: 'users'\r\n }, {\r\n name: 'chats'\r\n }, {\r\n name: 'dialogs'\r\n }, {\r\n name: 'messages'\r\n }]\r\n};\r\n\r\nexport default DATABASE_STATE;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { Database } from '../config/databases';\r\nimport Modes from '../config/modes';\r\nimport { blobConstruct } from '../helpers/blob';\r\nimport { safeAssign } from '../helpers/object';\r\nimport { logger } from './logger';\r\n\r\n/**\r\n * https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/createIndex\r\n */\r\nexport type IDBIndex = {\r\n indexName: string,\r\n keyPath: string,\r\n objectParameters: IDBIndexParameters\r\n};\r\n\r\nexport type IDBStore = {\r\n name: string, \r\n indexes?: IDBIndex[]\r\n};\r\n\r\nexport type IDBOptions = {\r\n name?: string,\r\n storeName: string,\r\n stores?: IDBStore[],\r\n version?: number\r\n};\r\n\r\nconst DEBUG = false;\r\n\r\nexport default class IDBStorage<T extends Database<any>> {\r\n private static STORAGES: IDBStorage<Database<any>>[] = [];\r\n private openDbPromise: Promise<IDBDatabase>;\r\n private db: IDBDatabase;\r\n private storageIsAvailable = true;\r\n\r\n private log: ReturnType<typeof logger>;\r\n \r\n private name: string;\r\n private version: number;\r\n private stores: IDBStore[];\r\n private storeName: T['stores'][0]['name'];\r\n\r\n constructor(db: T, storeName: typeof db['stores'][0]['name']) {\r\n safeAssign(this, db);\r\n\r\n if(Modes.test) {\r\n this.name += '_test';\r\n }\r\n\r\n this.storeName = storeName;\r\n\r\n this.log = logger('IDB-' + this.storeName);\r\n\r\n this.openDatabase(true);\r\n\r\n IDBStorage.STORAGES.push(this);\r\n }\r\n\r\n public static closeDatabases(preserve?: IDBStorage<Database<any>>) {\r\n this.STORAGES.forEach(storage => {\r\n if(preserve && preserve === storage) {\r\n return;\r\n }\r\n\r\n const db = storage.db;\r\n if(db) {\r\n db.onclose = () => {};\r\n db.close();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * ! WARNING ! function requires at least one opened connection\r\n */\r\n /* public static clearObjectStores() {\r\n const storage = this.STORAGES[0];\r\n this.closeDatabases(storage);\r\n\r\n const names = Array.from(storage.db.objectStoreNames);\r\n const promises = names.map(name => storage.clear(name));\r\n return Promise.all(promises);\r\n } */\r\n\r\n /* public static deleteDatabase() {\r\n this.closeDatabases();\r\n\r\n const storages = this.STORAGES;\r\n const dbNames = Array.from(new Set(storages.map(storage => storage.name)));\r\n const promises = dbNames.map(dbName => {\r\n return new Promise<void>((resolve, reject) => {\r\n const deleteRequest = indexedDB.deleteDatabase(dbName);\r\n \r\n deleteRequest.onerror = () => {\r\n reject();\r\n };\r\n \r\n deleteRequest.onsuccess = () => {\r\n resolve();\r\n };\r\n });\r\n });\r\n\r\n return Promise.all(promises);\r\n } */\r\n\r\n public isAvailable() {\r\n return this.storageIsAvailable;\r\n }\r\n\r\n public openDatabase(createNew = false): Promise<IDBDatabase> {\r\n if(this.openDbPromise && !createNew) {\r\n return this.openDbPromise;\r\n }\r\n\r\n const createObjectStore = (db: IDBDatabase, store: IDBStore) => {\r\n const os = db.createObjectStore(store.name);\r\n\r\n if(store.indexes?.length) {\r\n for(const index of store.indexes) {\r\n os.createIndex(index.indexName, index.keyPath, index.objectParameters);\r\n }\r\n }\r\n };\r\n\r\n try {\r\n var request = indexedDB.open(this.name, this.version);\r\n\r\n if(!request) {\r\n return Promise.reject();\r\n }\r\n } catch(error) {\r\n this.log.error('error opening db', (error as Error).message);\r\n this.storageIsAvailable = false;\r\n return Promise.reject(error);\r\n }\r\n\r\n let finished = false;\r\n setTimeout(() => {\r\n if(!finished) {\r\n request.onerror({type: 'IDB_CREATE_TIMEOUT'} as Event);\r\n }\r\n }, 3000);\r\n\r\n return this.openDbPromise = new Promise<IDBDatabase>((resolve, reject) => {\r\n request.onsuccess = (event) => {\r\n finished = true;\r\n const db = request.result;\r\n let calledNew = false;\r\n\r\n this.log('Opened');\r\n \r\n db.onerror = (error) => {\r\n this.storageIsAvailable = false;\r\n this.log.error('Error creating/accessing IndexedDB database', error);\r\n reject(error);\r\n };\r\n\r\n db.onclose = (e) => {\r\n this.log.error('closed:', e);\r\n !calledNew && this.openDatabase();\r\n };\r\n\r\n db.onabort = (e) => {\r\n this.log.error('abort:', e);\r\n const transaction = e.target as IDBTransaction;\r\n \r\n this.openDatabase(calledNew = true);\r\n\r\n if(transaction.onerror) {\r\n transaction.onerror(e);\r\n }\r\n\r\n db.close();\r\n };\r\n\r\n db.onversionchange = (e) => {\r\n this.log.error('onversionchange, lol?');\r\n };\r\n\r\n resolve(this.db = db);\r\n };\r\n \r\n request.onerror = (event) => {\r\n finished = true;\r\n this.storageIsAvailable = false;\r\n this.log.error('Error creating/accessing IndexedDB database', event);\r\n reject(event);\r\n };\r\n \r\n request.onupgradeneeded = (event) => {\r\n finished = true;\r\n this.log.warn('performing idb upgrade from', event.oldVersion, 'to', event.newVersion);\r\n\r\n // @ts-ignore\r\n var db = event.target.result as IDBDatabase;\r\n this.stores.forEach((store) => {\r\n /* if(db.objectStoreNames.contains(store.name)) {\r\n //if(event.oldVersion === 1) {\r\n db.deleteObjectStore(store.name);\r\n //}\r\n } */\r\n \r\n if(!db.objectStoreNames.contains(store.name)) {\r\n createObjectStore(db, store);\r\n }\r\n });\r\n };\r\n });\r\n }\r\n\r\n public delete(entryName: string | string[]): Promise<void> {\r\n //return Promise.resolve();\r\n if(!Array.isArray(entryName)) {\r\n entryName = [].concat(entryName);\r\n }\r\n\r\n return this.getObjectStore('readwrite', (objectStore) => {\r\n return (entryName as string[]).map((entryName) => objectStore.delete(entryName));\r\n }, DEBUG ? 'delete: ' + entryName.join(', ') : '');\r\n }\r\n\r\n public clear(storeName?: IDBStorage<T>['storeName']) {\r\n return this.getObjectStore('readwrite', (objectStore) => objectStore.clear(), DEBUG ? 'clear' : '', storeName);\r\n }\r\n\r\n public save(entryName: string | string[], value: any | any[]) {\r\n // const handleError = (error: Error) => {\r\n // this.log.error('save: transaction error:', entryName, value, db, error, error && error.name);\r\n // if((!error || error.name === 'InvalidStateError')/* && false */) {\r\n // setTimeout(() => {\r\n // this.save(entryName, value);\r\n // }, 2e3);\r\n // } else {\r\n // //console.error('IndexedDB saveFile transaction error:', error, error && error.name);\r\n // }\r\n // };\r\n\r\n if(!Array.isArray(entryName)) {\r\n entryName = [].concat(entryName);\r\n value = [].concat(value);\r\n }\r\n \r\n return this.getObjectStore('readwrite', (objectStore) => {\r\n return (entryName as string[]).map((entryName, idx) => objectStore.put(value[idx], entryName));\r\n }, DEBUG ? 'save: ' + entryName.join(', ') : '');\r\n }\r\n\r\n public saveFile(fileName: string, blob: Blob | Uint8Array) {\r\n //return Promise.resolve(blobConstruct([blob]));\r\n if(!(blob instanceof Blob)) {\r\n blob = blobConstruct([blob]) as Blob;\r\n }\r\n\r\n return this.save(fileName, blob);\r\n }\r\n\r\n /* public saveFileBase64(db: IDBDatabase, fileName: string, blob: Blob | any): Promise<Blob> {\r\n if(this.getBlobSize(blob) > 10 * 1024 * 1024) {\r\n return Promise.reject();\r\n }\r\n\r\n if(!(blob instanceof Blob)) {\r\n var safeMimeType = blobSafeMimeType(blob.type || 'image/jpeg');\r\n var address = 'data:' + safeMimeType + ';base64,' + bytesToBase64(blob);\r\n return this.storagePutB64String(db, fileName, address).then(() => {\r\n return blob;\r\n });\r\n }\r\n\r\n try {\r\n var reader = new FileReader();\r\n } catch (e) {\r\n this.storageIsAvailable = false;\r\n return Promise.reject();\r\n }\r\n\r\n let promise = new Promise<Blob>((resolve, reject) => {\r\n reader.onloadend = () => {\r\n this.storagePutB64String(db, fileName, reader.result as string).then(() => {\r\n resolve(blob);\r\n }, reject);\r\n }\r\n \r\n reader.onerror = reject;\r\n });\r\n \r\n\r\n try {\r\n reader.readAsDataURL(blob);\r\n } catch (e) {\r\n this.storageIsAvailable = false;\r\n return Promise.reject();\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n public storagePutB64String(db: IDBDatabase, fileName: string, b64string: string) {\r\n try {\r\n var objectStore = db.transaction([this.storeName], 'readwrite')\r\n .objectStore(this.storeName);\r\n var request = objectStore.put(b64string, fileName);\r\n } catch(error) {\r\n this.storageIsAvailable = false;\r\n return Promise.reject(error);\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = function(event) {\r\n resolve();\r\n };\r\n \r\n request.onerror = reject;\r\n });\r\n }\r\n\r\n public getBlobSize(blob: any) {\r\n return blob.size || blob.byteLength || blob.length;\r\n } */\r\n\r\n public get<T>(entryName: string[]): Promise<T[]>;\r\n public get<T>(entryName: string): Promise<T>;\r\n public get<T>(entryName: string | string[]): Promise<T> | Promise<T[]> {\r\n //return Promise.reject();\r\n\r\n if(!Array.isArray(entryName)) {\r\n entryName = [].concat(entryName);\r\n }\r\n\r\n return this.getObjectStore<T>('readonly', (objectStore) => {\r\n return (entryName as string[]).map((entryName) => objectStore.get(entryName));\r\n }, DEBUG ? 'get: ' + entryName.join(', ') : '');\r\n }\r\n\r\n private getObjectStore<T>(mode: IDBTransactionMode, objectStore: (objectStore: IDBObjectStore) => IDBRequest | IDBRequest[], log?: string, storeName = this.storeName) {\r\n let perf: number;\r\n\r\n if(log) {\r\n perf = performance.now();\r\n this.log(log + ': start');\r\n }\r\n\r\n return this.openDatabase().then((db) => {\r\n return new Promise<T>((resolve, reject) => {\r\n /* if(mode === 'readwrite') {\r\n return;\r\n } */\r\n\r\n const transaction = db.transaction([storeName], mode);\r\n\r\n transaction.onerror = (e) => {\r\n clearTimeout(timeout);\r\n reject(transaction.error);\r\n };\r\n \r\n transaction.oncomplete = (e) => {\r\n clearTimeout(timeout);\r\n\r\n if(log) {\r\n this.log(log + ': end', performance.now() - perf);\r\n }\r\n\r\n const results = r.map(r => r.result);\r\n resolve(isArray ? results : results[0]);\r\n };\r\n \r\n const timeout = setTimeout(() => {\r\n this.log.error('transaction not finished', transaction);\r\n }, 10000);\r\n \r\n /* transaction.addEventListener('abort', (e) => {\r\n //handleError();\r\n this.log.error('IndexedDB: transaction abort!', transaction.error);\r\n }); */\r\n \r\n const requests = objectStore(transaction.objectStore(storeName));\r\n\r\n const isArray = Array.isArray(requests);\r\n const r: IDBRequest[] = isArray ? requests : [].concat(requests) as any;\r\n\r\n // const length = r.length;\r\n // /* let left = length;\r\n\r\n // const onRequestFinished = (error?: Error) => {\r\n // if(!--left) {\r\n // resolve(result);\r\n // clearTimeout(timeout);\r\n // }\r\n // }; */\r\n\r\n // for(let i = 0; i < length; ++i) {\r\n // const request = r[i];\r\n // request.onsuccess = () => {\r\n // onRequestFinished();\r\n // };\r\n\r\n // request.onerror = (e) => {\r\n // onRequestFinished(transaction.error);\r\n // };\r\n // }\r\n });\r\n });\r\n }\r\n\r\n public getAll<T>(): Promise<T[]> {\r\n return this.getObjectStore<T[]>('readonly', (objectStore) => objectStore.getAll(), DEBUG ? 'getAll' : '');\r\n }\r\n\r\n /* public getAllKeys(): Promise<Array<string>> {\r\n console.time('getAllEntries');\r\n return this.openDatabase().then((db) => {\r\n var objectStore = db.transaction([this.storeName], 'readonly')\r\n .objectStore(this.storeName);\r\n var request = objectStore.getAllKeys();\r\n\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = function(event) {\r\n // @ts-ignore\r\n var result = event.target.result;\r\n resolve(result);\r\n console.timeEnd('getAllEntries');\r\n }\r\n \r\n request.onerror = reject;\r\n });\r\n });\r\n } */\r\n\r\n /* public isFileExists(fileName: string): Promise<boolean> {\r\n console.time('isFileExists');\r\n return this.openDatabase().then((db) => {\r\n var objectStore = db.transaction([this.storeName], 'readonly')\r\n .objectStore(this.storeName);\r\n var request = objectStore.openCursor(fileName);\r\n\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = function(event) {\r\n // @ts-ignore\r\n var cursor = event.target.result;\r\n resolve(!!cursor);\r\n console.timeEnd('isFileExists');\r\n }\r\n \r\n request.onerror = reject;\r\n });\r\n });\r\n } */\r\n\r\n /* public getFileWriter(fileName: string, mimeType: string) {\r\n var fakeWriter = FileManager.getFakeFileWriter(mimeType, (blob) => {\r\n return this.saveFile(fileName, blob);\r\n });\r\n\r\n return Promise.resolve(fakeWriter);\r\n } */\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nexport function copy<T>(obj: T): T {\r\n //in case of premitives\r\n if(obj === null || typeof(obj) !== \"object\") {\r\n return obj;\r\n }\r\n \r\n //date objects should be \r\n if(obj instanceof Date) {\r\n return new Date(obj.getTime()) as any;\r\n }\r\n \r\n //handle Array\r\n if(Array.isArray(obj)) {\r\n // @ts-ignore\r\n const clonedArr: T = obj.map(el => copy(el)) as any as T;\r\n return clonedArr;\r\n }\r\n \r\n //lastly, handle objects\r\n // @ts-ignore\r\n let clonedObj = new obj.constructor();\r\n for(var prop in obj) {\r\n if(obj.hasOwnProperty(prop)) {\r\n clonedObj[prop] = copy(obj[prop]);\r\n }\r\n }\r\n return clonedObj;\r\n}\r\n\r\nexport function deepEqual(x: any, y: any): boolean {\r\n const ok = Object.keys, tx = typeof x, ty = typeof y;\r\n return x && y && tx === 'object' && tx === ty ? (\r\n ok(x).length === ok(y).length &&\r\n ok(x).every(key => deepEqual(x[key], y[key]))\r\n ) : (x === y);\r\n}\r\n\r\nexport function defineNotNumerableProperties<T extends any>(obj: T, names: (keyof T)[]) {\r\n //const perf = performance.now();\r\n const props = {writable: true, configurable: true};\r\n const out: {[name in keyof T]?: typeof props} = {};\r\n names.forEach(name => {\r\n if(!obj.hasOwnProperty(name)) {\r\n out[name] = props;\r\n }\r\n });\r\n Object.defineProperties(obj, out);\r\n //console.log('defineNotNumerableProperties time:', performance.now() - perf);\r\n}\r\n\r\nexport function getObjectKeysAndSort(object: {[key: string]: any}, sort: 'asc' | 'desc' = 'asc') {\r\n if(!object) return [];\r\n const ids = object instanceof Map ? [...object.keys()] : Object.keys(object).map(i => +i);\r\n if(sort === 'asc') return ids.sort((a, b) => a - b);\r\n else return ids.sort((a, b) => b - a);\r\n}\r\n\r\nexport function safeReplaceObject(wasObject: any, newObject: any) {\r\n if(!wasObject) {\r\n return newObject;\r\n }\r\n\r\n for(var key in wasObject) {\r\n if(!newObject.hasOwnProperty(key)) {\r\n delete wasObject[key];\r\n }\r\n }\r\n\r\n for(var key in newObject) {\r\n //if (newObject.hasOwnProperty(key)) { // useless\r\n wasObject[key] = newObject[key];\r\n //}\r\n }\r\n \r\n return wasObject;\r\n}\r\n\r\n/**\r\n * Will be used for FILE_REFERENCE_EXPIRED\r\n * @param key \r\n * @param wasObject \r\n * @param newObject \r\n */\r\nexport function safeReplaceArrayInObject<K>(key: K, wasObject: any, newObject: any) {\r\n if('byteLength' in newObject[key]) { // Uint8Array\r\n newObject[key] = [...newObject[key]];\r\n }\r\n\r\n if(wasObject && wasObject[key] !== newObject[key]) {\r\n wasObject[key].length = newObject[key].length;\r\n (newObject[key] as any[]).forEach((v, i) => {\r\n wasObject[key][i] = v;\r\n });\r\n\r\n /* wasObject[key].set(newObject[key]); */\r\n newObject[key] = wasObject[key];\r\n }\r\n}\r\n\r\nexport function isObject<T extends Record<any, any>>(object: any): object is T {\r\n return typeof(object) === 'object' && object !== null;\r\n}\r\n\r\nexport function getDeepProperty(object: any, key: string) {\r\n const splitted = key.split('.');\r\n let o: any = object;\r\n splitted.forEach(key => {\r\n if(!key) {\r\n return;\r\n }\r\n \r\n // @ts-ignore\r\n o = o[key];\r\n });\r\n \r\n return o;\r\n}\r\n\r\nexport function setDeepProperty(object: any, key: string, value: any) {\r\n const splitted = key.split('.');\r\n getDeepProperty(object, splitted.slice(0, -1).join('.'))[splitted.pop()] = value;\r\n}\r\n\r\nexport function validateInitObject(initObject: any, currentObject: any, onReplace?: (key: string) => void, previousKey?: string) {\r\n for(const key in initObject) {\r\n if(typeof(currentObject[key]) !== typeof(initObject[key])) {\r\n currentObject[key] = copy(initObject[key]);\r\n onReplace && onReplace(previousKey || key);\r\n } else if(isObject(initObject[key])) {\r\n validateInitObject(initObject[key], currentObject[key], onReplace, previousKey || key);\r\n }\r\n }\r\n}\r\n\r\nexport function safeAssign<T>(object: T, fromObject: any) {\r\n if(fromObject) {\r\n for(let i in fromObject) {\r\n if(fromObject[i] !== undefined) {\r\n // @ts-ignore\r\n object[i] = fromObject[i];\r\n }\r\n }\r\n }\r\n\r\n return object;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { Database } from \"../../config/databases\";\r\nimport DATABASE_STATE from \"../../config/databases/state\";\r\nimport { IS_FIREFOX } from \"../../environment/userAgent\";\r\nimport IDBStorage from \"../idb\";\r\nimport { log, ServiceWorkerPingTask, ServiceWorkerPushClickTask } from \"./index.service\";\r\n\r\nconst ctx = self as any as ServiceWorkerGlobalScope;\r\nconst defaultBaseUrl = location.protocol + '//' + location.hostname + location.pathname.split('/').slice(0, -1).join('/') + '/';\r\n\r\nexport type PushNotificationObject = {\r\n loc_key: string,\r\n loc_args: string[],\r\n //user_id: number, // should be number\r\n custom: {\r\n channel_id?: string, // should be number\r\n chat_id?: string, // should be number\r\n from_id?: string, // should be number\r\n msg_id: string,\r\n peerId?: string // should be number\r\n },\r\n sound?: string,\r\n random_id: number,\r\n badge?: string, // should be number\r\n description: string,\r\n mute: string, // should be number\r\n title: string,\r\n\r\n action?: 'mute1d' | 'push_settings', // will be set before postMessage to main thread\r\n};\r\n\r\nclass SomethingGetter<T extends Database<any>, Storage extends Record<string, any>> {\r\n private cache: Partial<Storage> = {};\r\n private storage: IDBStorage<T>;\r\n\r\n constructor(\r\n db: T, \r\n storeName: typeof db['stores'][number]['name'], \r\n private defaults: {\r\n [Property in keyof Storage]: ((value: Storage[Property]) => Storage[Property]) | Storage[Property]\r\n }\r\n ) {\r\n this.storage = new IDBStorage<T>(db, storeName);\r\n }\r\n\r\n public async get<T extends keyof Storage>(key: T) {\r\n if(this.cache[key] !== undefined) {\r\n return this.cache[key];\r\n }\r\n\r\n let value: Storage[T];\r\n try {\r\n value = await this.storage.get(key as string);\r\n } catch(err) {\r\n\r\n }\r\n\r\n if(this.cache[key] !== undefined) {\r\n return this.cache[key];\r\n }\r\n\r\n if(value === undefined) {\r\n const callback = this.defaults[key];\r\n value = typeof(callback) === 'function' ? callback() : callback;\r\n }\r\n\r\n return this.cache[key] = value;\r\n }\r\n\r\n public async set<T extends keyof Storage>(key: T, value: Storage[T]) {\r\n this.cache[key] = value;\r\n\r\n try {\r\n this.storage.save(key as string, value);\r\n } catch(err) {\r\n\r\n }\r\n }\r\n}\r\n\r\ntype PushStorage = {\r\n push_mute_until: number,\r\n push_last_alive: number,\r\n push_lang: Partial<ServiceWorkerPingTask['payload']['lang']>\r\n push_settings: Partial<ServiceWorkerPingTask['payload']['settings']>\r\n};\r\n\r\nconst getter = new SomethingGetter<typeof DATABASE_STATE, PushStorage>(DATABASE_STATE, 'session', {\r\n push_mute_until: 0,\r\n push_last_alive: 0,\r\n push_lang: {},\r\n push_settings: {}\r\n});\r\n\r\nctx.addEventListener('push', (event) => {\r\n const obj: PushNotificationObject = event.data.json();\r\n log('push', obj);\r\n\r\n let hasActiveWindows = false;\r\n const checksPromise = Promise.all([\r\n getter.get('push_mute_until'), \r\n getter.get('push_last_alive'), \r\n ctx.clients.matchAll({type: 'window'})\r\n ]).then((result) => {\r\n const [muteUntil, lastAliveTime, clientList] = result;\r\n \r\n log('matched clients', clientList);\r\n hasActiveWindows = clientList.length > 0;\r\n if(hasActiveWindows) {\r\n throw 'Supress notification because some instance is alive';\r\n }\r\n \r\n const nowTime = Date.now();\r\n if(userInvisibleIsSupported() &&\r\n muteUntil &&\r\n nowTime < muteUntil) {\r\n throw `Supress notification because mute for ${Math.ceil((muteUntil - nowTime) / 60000)} min`;\r\n }\r\n\r\n if(!obj.badge) {\r\n throw 'No badge?';\r\n }\r\n });\r\n\r\n checksPromise.catch(reason => {\r\n log(reason);\r\n });\r\n\r\n const notificationPromise = checksPromise.then(() => {\r\n return Promise.all([getter.get('push_settings'), getter.get('push_lang')])\r\n }).then((result) => {\r\n return fireNotification(obj, result[0], result[1]);\r\n });\r\n\r\n const closePromise = notificationPromise.catch(() => {\r\n log('Closing all notifications on push', hasActiveWindows);\r\n if(userInvisibleIsSupported() || hasActiveWindows) {\r\n return closeAllNotifications();\r\n }\r\n\r\n return ctx.registration.showNotification('Telegram', {\r\n tag: 'unknown_peer'\r\n }).then(() => {\r\n if(hasActiveWindows) {\r\n return closeAllNotifications();\r\n }\r\n\r\n setTimeout(() => closeAllNotifications(), hasActiveWindows ? 0 : 100);\r\n }).catch((error) => {\r\n log.error('Show notification error', error);\r\n });\r\n });\r\n\r\n event.waitUntil(closePromise);\r\n});\r\n\r\nctx.addEventListener('notificationclick', (event) => {\r\n const notification = event.notification;\r\n log('On notification click: ', notification.tag);\r\n notification.close();\r\n\r\n const action = event.action as PushNotificationObject['action'];\r\n if(action === 'mute1d' && userInvisibleIsSupported()) {\r\n log('[SW] mute for 1d');\r\n getter.set('push_mute_until', Date.now() + 86400e3);\r\n return;\r\n }\r\n\r\n const data: PushNotificationObject = notification.data;\r\n if(!data) {\r\n return;\r\n }\r\n\r\n const promise = ctx.clients.matchAll({\r\n type: 'window'\r\n }).then((clientList) => {\r\n data.action = action;\r\n pendingNotification = {type: 'push_click', payload: data};\r\n for(let i = 0; i < clientList.length; i++) {\r\n const client = clientList[i];\r\n if('focus' in client) {\r\n client.focus();\r\n client.postMessage(pendingNotification);\r\n pendingNotification = undefined;\r\n return;\r\n }\r\n }\r\n\r\n if(ctx.clients.openWindow) {\r\n return getter.get('push_settings').then((settings) => {\r\n return ctx.clients.openWindow(settings.baseUrl || defaultBaseUrl);\r\n });\r\n }\r\n }).catch((error) => {\r\n log.error('Clients.matchAll error', error);\r\n })\r\n\r\n event.waitUntil(promise);\r\n});\r\n\r\nctx.addEventListener('notificationclose', onCloseNotification);\r\n\r\nlet notifications: Set<Notification> = new Set();\r\nlet pendingNotification: ServiceWorkerPushClickTask;\r\nfunction pushToNotifications(notification: Notification) {\r\n if(!notifications.has(notification)) {\r\n notifications.add(notification);\r\n // @ts-ignore\r\n notification.onclose = onCloseNotification;\r\n }\r\n}\r\n\r\nfunction onCloseNotification(event: NotificationEvent) {\r\n removeFromNotifications(event.notification)\r\n}\r\n\r\nfunction removeFromNotifications(notification: Notification) {\r\n notifications.delete(notification);\r\n}\r\n\r\nexport function closeAllNotifications() {\r\n for(const notification of notifications) {\r\n try {\r\n notification.close();\r\n } catch(e) {}\r\n }\r\n\r\n let promise: Promise<void>;\r\n if('getNotifications' in ctx.registration) {\r\n promise = ctx.registration.getNotifications({}).then((notifications) => {\r\n for(let i = 0, len = notifications.length; i < len; ++i) {\r\n try {\r\n notifications[i].close();\r\n } catch(e) {}\r\n }\r\n }).catch((error) => {\r\n log.error('Offline register SW error', error);\r\n });\r\n } else {\r\n promise = Promise.resolve();\r\n }\r\n\r\n notifications.clear();\r\n\r\n return promise;\r\n}\r\n\r\nfunction userInvisibleIsSupported() {\r\n return IS_FIREFOX;\r\n}\r\n\r\nfunction fireNotification(obj: PushNotificationObject, settings: PushStorage['push_settings'], lang: PushStorage['push_lang']) {\r\n const icon = 'assets/img/logo_filled_rounded.png';\r\n let title = obj.title || 'Telegram';\r\n let body = obj.description || '';\r\n let peerId: string;\r\n\r\n if(obj.custom) {\r\n if(obj.custom.channel_id) {\r\n peerId = '' + -obj.custom.channel_id;\r\n } else if(obj.custom.chat_id) {\r\n peerId = '' + -obj.custom.chat_id;\r\n } else {\r\n peerId = obj.custom.from_id || '';\r\n }\r\n }\r\n\r\n obj.custom.peerId = '' + peerId;\r\n let tag = 'peer' + peerId;\r\n\r\n if(settings && settings.nopreview) {\r\n title = 'Telegram';\r\n body = lang.push_message_nopreview || 'You have a new message';\r\n tag = 'unknown_peer';\r\n }\r\n\r\n log('show notify', title, body, icon, obj);\r\n\r\n const actions: (Omit<NotificationAction, 'action'> & {action: PushNotificationObject['action']})[] = [{\r\n action: 'mute1d',\r\n title: lang.push_action_mute1d || 'Mute for 24H'\r\n }/* , {\r\n action: 'push_settings',\r\n title: lang.push_action_settings || 'Settings'\r\n } */];\r\n\r\n const notificationPromise = ctx.registration.showNotification(title, {\r\n body,\r\n icon,\r\n tag,\r\n data: obj,\r\n actions\r\n });\r\n\r\n return notificationPromise.then((event) => {\r\n // @ts-ignore\r\n if(event && event.notification) {\r\n // @ts-ignore\r\n pushToNotifications(event.notification);\r\n }\r\n }).catch((error) => {\r\n log.error('Show notification promise', error);\r\n });\r\n}\r\n\r\nexport function onPing(task: ServiceWorkerPingTask, event: ExtendableMessageEvent) {\r\n const client = event.ports && event.ports[0] || event.source;\r\n const payload = task.payload;\r\n\r\n if(payload.localNotifications) {\r\n getter.set('push_last_alive', Date.now());\r\n }\r\n\r\n if(pendingNotification &&\r\n client &&\r\n 'postMessage' in client) {\r\n client.postMessage(pendingNotification, []);\r\n pendingNotification = undefined;\r\n }\r\n\r\n if(payload.lang) {\r\n getter.set('push_lang', payload.lang);\r\n }\r\n\r\n if(payload.settings) {\r\n getter.set('push_settings', payload.settings);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n \r\n \r\n \r\n//import CacheStorageController from '../cacheStorage';\r\nimport type { Modify, WorkerTaskTemplate, WorkerTaskVoidTemplate } from '../../types';\r\nimport type { InputFileLocation, InputWebFileLocation, UploadFile } from '../../layer';\r\nimport type { WebPushApiManager } from '../mtproto/webPushApiManager';\r\nimport type { PushNotificationObject } from './push';\r\nimport type { ToggleStorageTask } from '../mtproto/mtprotoworker';\r\nimport type { MyUploadFile } from '../mtproto/apiFileManager';\r\nimport { logger, LogTypes } from '../logger';\r\nimport { CancellablePromise } from '../../helpers/cancellablePromise';\r\nimport { CACHE_ASSETS_NAME, requestCache } from './cache';\r\nimport onStreamFetch from './stream';\r\nimport { closeAllNotifications, onPing } from './push';\r\nimport CacheStorageController from '../cacheStorage';\r\n\r\nexport const log = logger('SW', LogTypes.Error | LogTypes.Debug | LogTypes.Log | LogTypes.Warn);\r\nconst ctx = self as any as ServiceWorkerGlobalScope;\r\nexport const deferredPromises: Map<WindowClient['id'], {[taskId: string]: CancellablePromise<any>}> = new Map();\r\n\r\nexport interface RequestFilePartTask extends Modify<WorkerTaskTemplate, {id: string}> {\r\n type: 'requestFilePart',\r\n payload: [number, InputFileLocation | InputWebFileLocation, number, number]\r\n};\r\n\r\nexport interface RequestFilePartTaskResponse extends Modify<WorkerTaskTemplate, {id: string}> {\r\n type: 'requestFilePart',\r\n payload?: MyUploadFile,\r\n originalPayload?: RequestFilePartTask['payload']\r\n};\r\n\r\nexport interface ServiceWorkerPingTask extends WorkerTaskVoidTemplate {\r\n type: 'ping',\r\n payload: {\r\n localNotifications: boolean,\r\n lang: {\r\n push_action_mute1d: string\r\n push_action_settings: string\r\n push_message_nopreview: string\r\n },\r\n settings: WebPushApiManager['settings']\r\n }\r\n};\r\n\r\nexport interface ServiceWorkerNotificationsClearTask extends WorkerTaskVoidTemplate {\r\n type: 'notifications_clear'\r\n};\r\n\r\nexport interface ServiceWorkerPushClickTask extends WorkerTaskVoidTemplate {\r\n type: 'push_click',\r\n payload: PushNotificationObject\r\n};\r\n\r\nexport type ServiceWorkerTask = RequestFilePartTaskResponse | ServiceWorkerPingTask | ServiceWorkerNotificationsClearTask | ToggleStorageTask;\r\n\r\n \r\nconst taskListeners: {\r\n [type in ServiceWorkerTask['type']]: (task: any, event: ExtendableMessageEvent) => void\r\n} = {\r\n notifications_clear: () => {\r\n closeAllNotifications();\r\n },\r\n ping: (task: ServiceWorkerPingTask, event) => {\r\n onPing(task, event);\r\n },\r\n requestFilePart: (task: RequestFilePartTaskResponse, e: ExtendableMessageEvent) => {\r\n const windowClient = e.source as WindowClient;\r\n const promises = deferredPromises.get(windowClient.id);\r\n if(!promises) {\r\n return;\r\n }\r\n\r\n const promise = promises[task.id];\r\n if(promise) {\r\n if(task.error) {\r\n promise.reject(task.error);\r\n } else {\r\n promise.resolve(task.payload);\r\n }\r\n \r\n delete promises[task.id];\r\n }\r\n },\r\n toggleStorage: (task: ToggleStorageTask) => {\r\n CacheStorageController.toggleStorage(task.payload);\r\n }\r\n};\r\nctx.addEventListener('message', (e) => {\r\n const task = e.data as ServiceWorkerTask;\r\n const callback = taskListeners[task.type];\r\n if(callback) {\r\n callback(task, e);\r\n }\r\n});\r\n \r\n\r\n//const cacheStorage = new CacheStorageController('cachedAssets');\r\n/* let taskId = 0;\r\n\r\nexport function getTaskId() {\r\n return taskId;\r\n}\r\n\r\nexport function incrementTaskId() {\r\n return taskId++;\r\n} */\r\n\r\nconst onFetch = (event: FetchEvent): void => {\r\n if(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?)(?:\\?.*)?$/)) {\r\n return event.respondWith(requestCache(event));\r\n }\r\n\r\n try {\r\n const [, url, scope, params] = /http[:s]+\\/\\/.*?(\\/(.*?)(?:$|\\/(.*)$))/.exec(event.request.url) || [];\r\n\r\n //log.debug('[fetch]:', event);\r\n \r\n switch(scope) {\r\n case 'stream': {\r\n onStreamFetch(event, params);\r\n break;\r\n }\r\n }\r\n } catch(err) {\r\n event.respondWith(new Response('', {\r\n status: 500,\r\n statusText: 'Internal Server Error',\r\n }));\r\n }\r\n};\r\n\r\nconst onChangeState = () => {\r\n ctx.onfetch = onFetch;\r\n};\r\n\r\nctx.addEventListener('install', (event) => {\r\n log('installing');\r\n event.waitUntil(ctx.skipWaiting()); // Activate worker immediately\r\n});\r\n\r\nctx.addEventListener('activate', (event) => {\r\n log('activating', ctx);\r\n event.waitUntil(ctx.caches.delete(CACHE_ASSETS_NAME));\r\n event.waitUntil(ctx.clients.claim());\r\n});\r\n\r\nctx.onerror = (error) => {\r\n log.error('error:', error);\r\n};\r\n\r\nctx.onunhandledrejection = (error) => {\r\n log.error('onunhandledrejection:', error);\r\n};\r\n\r\nctx.onoffline = ctx.ononline = onChangeState;\r\n\r\nonChangeState();\r\n","export default function timeout(delay: number): Promise<Response> {\r\n return new Promise(((resolve) => {\r\n setTimeout(() => {\r\n resolve(new Response('', {\r\n status: 408,\r\n statusText: 'Request timed out.',\r\n }));\r\n }, delay);\r\n }));\r\n}\r\n"],"sourceRoot":""}