|
|
|
@ -17,9 +17,9 @@ const ctx = self as any as ServiceWorkerGlobalScope;
@@ -17,9 +17,9 @@ const ctx = self as any as ServiceWorkerGlobalScope;
|
|
|
|
|
|
|
|
|
|
//console.error('INCLUDE !!!', new Error().stack);
|
|
|
|
|
|
|
|
|
|
function isObject(object: any) { |
|
|
|
|
/* function isObject(object: any) { |
|
|
|
|
return typeof(object) === 'object' && object !== null; |
|
|
|
|
} |
|
|
|
|
} */ |
|
|
|
|
|
|
|
|
|
/* function fillTransfer(transfer: any, obj: any) { |
|
|
|
|
if(!obj) return; |
|
|
|
@ -79,70 +79,72 @@ networkerFactory.setUpdatesProcessor((obj, bool) => {
@@ -79,70 +79,72 @@ networkerFactory.setUpdatesProcessor((obj, bool) => {
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const onMessage = async(e: ExtendableMessageEvent) => { |
|
|
|
|
const taskID = e.data.taskID; |
|
|
|
|
|
|
|
|
|
log.debug('got message:', taskID, e, e.data); |
|
|
|
|
|
|
|
|
|
if(e.data.useLs) { |
|
|
|
|
AppStorage.finishTask(e.data.taskID, e.data.args); |
|
|
|
|
return; |
|
|
|
|
} else if(e.data.type == 'convertWebp') { |
|
|
|
|
const {fileName, bytes} = e.data.payload; |
|
|
|
|
const deferred = apiFileManager.webpConvertPromises[fileName]; |
|
|
|
|
if(deferred) { |
|
|
|
|
deferred.resolve(bytes); |
|
|
|
|
delete apiFileManager.webpConvertPromises[fileName]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
try { |
|
|
|
|
const taskID = e.data.taskID; |
|
|
|
|
|
|
|
|
|
switch(e.data.task) { |
|
|
|
|
case 'computeSRP': |
|
|
|
|
case 'gzipUncompress': |
|
|
|
|
// @ts-ignore
|
|
|
|
|
return cryptoWorker[e.data.task].apply(cryptoWorker, e.data.args).then(result => { |
|
|
|
|
respond(e.source, {taskID: taskID, result: result}); |
|
|
|
|
}); |
|
|
|
|
log.debug('got message:', taskID, e, e.data); |
|
|
|
|
|
|
|
|
|
case 'cancelDownload': |
|
|
|
|
case 'downloadFile': { |
|
|
|
|
/* // @ts-ignore |
|
|
|
|
return apiFileManager.downloadFile(...e.data.args); */ |
|
|
|
|
if(e.data.useLs) { |
|
|
|
|
AppStorage.finishTask(e.data.taskID, e.data.args); |
|
|
|
|
return; |
|
|
|
|
} else if(e.data.type == 'convertWebp') { |
|
|
|
|
const {fileName, bytes} = e.data.payload; |
|
|
|
|
const deferred = apiFileManager.webpConvertPromises[fileName]; |
|
|
|
|
if(deferred) { |
|
|
|
|
deferred.resolve(bytes); |
|
|
|
|
delete apiFileManager.webpConvertPromises[fileName]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
switch(e.data.task) { |
|
|
|
|
case 'computeSRP': |
|
|
|
|
case 'gzipUncompress': |
|
|
|
|
// @ts-ignore
|
|
|
|
|
let result = apiFileManager[e.data.task].apply(apiFileManager, e.data.args); |
|
|
|
|
return cryptoWorker[e.data.task].apply(cryptoWorker, e.data.args).then(result => { |
|
|
|
|
respond(e.source, {taskID: taskID, result: result}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if(result instanceof Promise) { |
|
|
|
|
result = await result; |
|
|
|
|
} |
|
|
|
|
case 'cancelDownload': |
|
|
|
|
case 'downloadFile': { |
|
|
|
|
/* // @ts-ignore |
|
|
|
|
return apiFileManager.downloadFile(...e.data.args); */ |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
// @ts-ignore
|
|
|
|
|
let result = apiFileManager[e.data.task].apply(apiFileManager, e.data.args); |
|
|
|
|
|
|
|
|
|
respond(e.source, {taskID: taskID, result: result}); |
|
|
|
|
} catch(err) { |
|
|
|
|
respond(e.source, {taskID: taskID, error: err}); |
|
|
|
|
if(result instanceof Promise) { |
|
|
|
|
result = await result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
respond(e.source, {taskID: taskID, result: result}); |
|
|
|
|
} catch(err) { |
|
|
|
|
respond(e.source, {taskID: taskID, error: err}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: { |
|
|
|
|
try { |
|
|
|
|
// @ts-ignore
|
|
|
|
|
let result = apiManager[e.data.task].apply(apiManager, e.data.args); |
|
|
|
|
default: { |
|
|
|
|
try { |
|
|
|
|
// @ts-ignore
|
|
|
|
|
let result = apiManager[e.data.task].apply(apiManager, e.data.args); |
|
|
|
|
|
|
|
|
|
if(result instanceof Promise) { |
|
|
|
|
result = await result; |
|
|
|
|
if(result instanceof Promise) { |
|
|
|
|
result = await result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
respond(e.source, {taskID: taskID, result: result}); |
|
|
|
|
} catch(err) { |
|
|
|
|
respond(e.source, {taskID: taskID, error: err}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
respond(e.source, {taskID: taskID, result: result}); |
|
|
|
|
} catch(err) { |
|
|
|
|
respond(e.source, {taskID: taskID, error: err}); |
|
|
|
|
//throw new Error('Unknown task: ' + e.data.task);
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//throw new Error('Unknown task: ' + e.data.task);
|
|
|
|
|
} |
|
|
|
|
} catch(err) { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
ctx.onmessage = onMessage; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Service Worker Installation |
|
|
|
|
*/ |
|
|
|
@ -201,257 +203,274 @@ ctx.onerror = (error) => {
@@ -201,257 +203,274 @@ ctx.onerror = (error) => {
|
|
|
|
|
log.error('error:', error); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
ctx.onunhandledrejection = (error) => { |
|
|
|
|
log.error('onunhandledrejection:', error); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const onChangeState = () => { |
|
|
|
|
ctx.onmessage = onMessage; |
|
|
|
|
ctx.onfetch = onFetch; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
onChangeState(); |
|
|
|
|
|
|
|
|
|
ctx.onoffline = ctx.ononline = onChangeState; |
|
|
|
|
|
|
|
|
|
const onFetch = (event: FetchEvent): void => { |
|
|
|
|
const [, url, scope, params] = /http[:s]+\/\/.*?(\/(.*?)(?:$|\/(.*)$))/.exec(event.request.url) || []; |
|
|
|
|
try { |
|
|
|
|
const [, url, scope, params] = /http[:s]+\/\/.*?(\/(.*?)(?:$|\/(.*)$))/.exec(event.request.url) || []; |
|
|
|
|
|
|
|
|
|
log.debug('[fetch]:', event); |
|
|
|
|
log.debug('[fetch]:', event); |
|
|
|
|
|
|
|
|
|
switch(scope) { |
|
|
|
|
case 'download': |
|
|
|
|
case 'thumb': |
|
|
|
|
case 'document': |
|
|
|
|
case 'photo': { |
|
|
|
|
const info: DownloadOptions = JSON.parse(decodeURIComponent(params)); |
|
|
|
|
switch(scope) { |
|
|
|
|
case 'download': |
|
|
|
|
case 'thumb': |
|
|
|
|
case 'document': |
|
|
|
|
case 'photo': { |
|
|
|
|
const info: DownloadOptions = JSON.parse(decodeURIComponent(params)); |
|
|
|
|
|
|
|
|
|
const rangeHeader = event.request.headers.get('Range'); |
|
|
|
|
if(rangeHeader && info.mimeType && info.size) { // maybe safari
|
|
|
|
|
const range = parseRange(event.request.headers.get('Range')); |
|
|
|
|
const possibleResponse = responseForSafariFirstRange(range, info.mimeType, info.size); |
|
|
|
|
if(possibleResponse) { |
|
|
|
|
return event.respondWith(possibleResponse); |
|
|
|
|
const rangeHeader = event.request.headers.get('Range'); |
|
|
|
|
if(rangeHeader && info.mimeType && info.size) { // maybe safari
|
|
|
|
|
const range = parseRange(event.request.headers.get('Range')); |
|
|
|
|
const possibleResponse = responseForSafariFirstRange(range, info.mimeType, info.size); |
|
|
|
|
if(possibleResponse) { |
|
|
|
|
return event.respondWith(possibleResponse); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const fileName = getFileNameByLocation(info.location, {fileName: info.fileName}); |
|
|
|
|
const fileName = getFileNameByLocation(info.location, {fileName: info.fileName}); |
|
|
|
|
|
|
|
|
|
/* event.request.signal.addEventListener('abort', (e) => { |
|
|
|
|
console.log('[SW] user aborted request:', fileName); |
|
|
|
|
cancellablePromise.cancel(); |
|
|
|
|
}); |
|
|
|
|
/* event.request.signal.addEventListener('abort', (e) => { |
|
|
|
|
console.log('[SW] user aborted request:', fileName); |
|
|
|
|
cancellablePromise.cancel(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
event.request.signal.onabort = (e) => { |
|
|
|
|
console.log('[SW] user aborted request:', fileName); |
|
|
|
|
cancellablePromise.cancel(); |
|
|
|
|
}; |
|
|
|
|
event.request.signal.onabort = (e) => { |
|
|
|
|
console.log('[SW] user aborted request:', fileName); |
|
|
|
|
cancellablePromise.cancel(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if(fileName == '5452060085729624717') { |
|
|
|
|
setInterval(() => { |
|
|
|
|
console.log('[SW] request status:', fileName, event.request.signal.aborted); |
|
|
|
|
}, 1000); |
|
|
|
|
} */ |
|
|
|
|
if(fileName == '5452060085729624717') { |
|
|
|
|
setInterval(() => { |
|
|
|
|
console.log('[SW] request status:', fileName, event.request.signal.aborted); |
|
|
|
|
}, 1000); |
|
|
|
|
} */ |
|
|
|
|
|
|
|
|
|
const cancellablePromise = apiFileManager.downloadFile(info); |
|
|
|
|
cancellablePromise.notify = (progress: {done: number, total: number, offset: number}) => { |
|
|
|
|
notify({progress: {fileName, ...progress}}); |
|
|
|
|
}; |
|
|
|
|
const cancellablePromise = apiFileManager.downloadFile(info); |
|
|
|
|
cancellablePromise.notify = (progress: {done: number, total: number, offset: number}) => { |
|
|
|
|
notify({progress: {fileName, ...progress}}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
log.debug('[fetch] file:', /* info, */fileName); |
|
|
|
|
log.debug('[fetch] file:', /* info, */fileName); |
|
|
|
|
|
|
|
|
|
const promise = cancellablePromise.then(b => { |
|
|
|
|
const responseInit: ResponseInit = {}; |
|
|
|
|
const promise = cancellablePromise.then(b => { |
|
|
|
|
const responseInit: ResponseInit = {}; |
|
|
|
|
|
|
|
|
|
if(rangeHeader) { |
|
|
|
|
responseInit.headers = { |
|
|
|
|
'Accept-Ranges': 'bytes', |
|
|
|
|
'Content-Range': `bytes 0-${info.size - 1}/${info.size || '*'}`, |
|
|
|
|
'Content-Length': `${info.size}`, |
|
|
|
|
if(rangeHeader) { |
|
|
|
|
responseInit.headers = { |
|
|
|
|
'Accept-Ranges': 'bytes', |
|
|
|
|
'Content-Range': `bytes 0-${info.size - 1}/${info.size || '*'}`, |
|
|
|
|
'Content-Length': `${info.size}`, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return new Response(b, responseInit); |
|
|
|
|
}); |
|
|
|
|
return new Response(b, responseInit); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
event.respondWith(Promise.race([ |
|
|
|
|
timeout(45 * 1000), |
|
|
|
|
promise |
|
|
|
|
])); |
|
|
|
|
event.respondWith(Promise.race([ |
|
|
|
|
timeout(45 * 1000), |
|
|
|
|
promise |
|
|
|
|
])); |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case 'stream': { |
|
|
|
|
const range = parseRange(event.request.headers.get('Range')); |
|
|
|
|
const [offset, end] = range; |
|
|
|
|
case 'stream': { |
|
|
|
|
const range = parseRange(event.request.headers.get('Range')); |
|
|
|
|
const [offset, end] = range; |
|
|
|
|
|
|
|
|
|
const info: DownloadOptions = JSON.parse(decodeURIComponent(params)); |
|
|
|
|
//const fileName = getFileNameByLocation(info.location);
|
|
|
|
|
const info: DownloadOptions = JSON.parse(decodeURIComponent(params)); |
|
|
|
|
//const fileName = getFileNameByLocation(info.location);
|
|
|
|
|
|
|
|
|
|
log.debug('[stream]', url, offset, end); |
|
|
|
|
log.debug('[stream]', url, offset, end); |
|
|
|
|
|
|
|
|
|
event.respondWith(Promise.race([ |
|
|
|
|
timeout(45 * 1000), |
|
|
|
|
new Promise<Response>((resolve, reject) => { |
|
|
|
|
// safari workaround
|
|
|
|
|
const possibleResponse = responseForSafariFirstRange(range, info.mimeType, info.size); |
|
|
|
|
if(possibleResponse) { |
|
|
|
|
return resolve(possibleResponse); |
|
|
|
|
} |
|
|
|
|
event.respondWith(Promise.race([ |
|
|
|
|
timeout(45 * 1000), |
|
|
|
|
new Promise<Response>((resolve, reject) => { |
|
|
|
|
// safari workaround
|
|
|
|
|
const possibleResponse = responseForSafariFirstRange(range, info.mimeType, info.size); |
|
|
|
|
if(possibleResponse) { |
|
|
|
|
return resolve(possibleResponse); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const limit = end && end < STREAM_CHUNK_UPPER_LIMIT ? alignLimit(end - offset + 1) : STREAM_CHUNK_UPPER_LIMIT; |
|
|
|
|
const alignedOffset = alignOffset(offset, limit); |
|
|
|
|
const limit = end && end < STREAM_CHUNK_UPPER_LIMIT ? alignLimit(end - offset + 1) : STREAM_CHUNK_UPPER_LIMIT; |
|
|
|
|
const alignedOffset = alignOffset(offset, limit); |
|
|
|
|
|
|
|
|
|
//log.debug('[stream] requestFilePart:', info.dcID, info.location, alignedOffset, limit);
|
|
|
|
|
//log.debug('[stream] requestFilePart:', info.dcID, info.location, alignedOffset, limit);
|
|
|
|
|
|
|
|
|
|
apiFileManager.requestFilePart(info.dcID, info.location, alignedOffset, limit).then(result => { |
|
|
|
|
let ab = result.bytes; |
|
|
|
|
apiFileManager.requestFilePart(info.dcID, info.location, alignedOffset, limit).then(result => { |
|
|
|
|
let ab = result.bytes; |
|
|
|
|
|
|
|
|
|
//log.debug('[stream] requestFilePart result:', result);
|
|
|
|
|
//log.debug('[stream] requestFilePart result:', result);
|
|
|
|
|
|
|
|
|
|
const headers: Record<string, string> = { |
|
|
|
|
'Accept-Ranges': 'bytes', |
|
|
|
|
'Content-Range': `bytes ${alignedOffset}-${alignedOffset + ab.byteLength - 1}/${info.size || '*'}`, |
|
|
|
|
'Content-Length': `${ab.byteLength}`, |
|
|
|
|
}; |
|
|
|
|
const headers: Record<string, string> = { |
|
|
|
|
'Accept-Ranges': 'bytes', |
|
|
|
|
'Content-Range': `bytes ${alignedOffset}-${alignedOffset + ab.byteLength - 1}/${info.size || '*'}`, |
|
|
|
|
'Content-Length': `${ab.byteLength}`, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if(info.mimeType) headers['Content-Type'] = info.mimeType; |
|
|
|
|
if(info.mimeType) headers['Content-Type'] = info.mimeType; |
|
|
|
|
|
|
|
|
|
if(isSafari) { |
|
|
|
|
ab = ab.slice(offset - alignedOffset, end - alignedOffset + 1); |
|
|
|
|
headers['Content-Range'] = `bytes ${offset}-${offset + ab.byteLength - 1}/${info.size || '*'}`; |
|
|
|
|
headers['Content-Length'] = `${ab.byteLength}`; |
|
|
|
|
} |
|
|
|
|
if(isSafari) { |
|
|
|
|
ab = ab.slice(offset - alignedOffset, end - alignedOffset + 1); |
|
|
|
|
headers['Content-Range'] = `bytes ${offset}-${offset + ab.byteLength - 1}/${info.size || '*'}`; |
|
|
|
|
headers['Content-Length'] = `${ab.byteLength}`; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
resolve(new Response(ab, { |
|
|
|
|
status: 206, |
|
|
|
|
statusText: 'Partial Content', |
|
|
|
|
headers, |
|
|
|
|
})); |
|
|
|
|
}); |
|
|
|
|
}) |
|
|
|
|
])); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
resolve(new Response(ab, { |
|
|
|
|
status: 206, |
|
|
|
|
statusText: 'Partial Content', |
|
|
|
|
headers, |
|
|
|
|
})); |
|
|
|
|
}); |
|
|
|
|
}) |
|
|
|
|
])); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* case 'download': { |
|
|
|
|
const info: DownloadOptions = JSON.parse(decodeURIComponent(params)); |
|
|
|
|
/* case 'download': { |
|
|
|
|
const info: DownloadOptions = JSON.parse(decodeURIComponent(params)); |
|
|
|
|
|
|
|
|
|
const promise = new Promise<Response>((resolve) => { |
|
|
|
|
const headers: Record<string, string> = { |
|
|
|
|
'Content-Disposition': `attachment; filename="${info.fileName}"`, |
|
|
|
|
}; |
|
|
|
|
const promise = new Promise<Response>((resolve) => { |
|
|
|
|
const headers: Record<string, string> = { |
|
|
|
|
'Content-Disposition': `attachment; filename="${info.fileName}"`, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if(info.size) headers['Content-Length'] = info.size.toString(); |
|
|
|
|
if(info.mimeType) headers['Content-Type'] = info.mimeType; |
|
|
|
|
if(info.size) headers['Content-Length'] = info.size.toString(); |
|
|
|
|
if(info.mimeType) headers['Content-Type'] = info.mimeType; |
|
|
|
|
|
|
|
|
|
log('[download] file:', info); |
|
|
|
|
log('[download] file:', info); |
|
|
|
|
|
|
|
|
|
const stream = new ReadableStream({ |
|
|
|
|
start(controller: ReadableStreamDefaultController) { |
|
|
|
|
const limitPart = DOWNLOAD_CHUNK_LIMIT; |
|
|
|
|
const stream = new ReadableStream({ |
|
|
|
|
start(controller: ReadableStreamDefaultController) { |
|
|
|
|
const limitPart = DOWNLOAD_CHUNK_LIMIT; |
|
|
|
|
|
|
|
|
|
apiFileManager.downloadFile({ |
|
|
|
|
...info, |
|
|
|
|
limitPart, |
|
|
|
|
processPart: (bytes, offset) => { |
|
|
|
|
log('[download] file processPart:', bytes, offset); |
|
|
|
|
apiFileManager.downloadFile({ |
|
|
|
|
...info, |
|
|
|
|
limitPart, |
|
|
|
|
processPart: (bytes, offset) => { |
|
|
|
|
log('[download] file processPart:', bytes, offset); |
|
|
|
|
|
|
|
|
|
controller.enqueue(new Uint8Array(bytes)); |
|
|
|
|
controller.enqueue(new Uint8Array(bytes)); |
|
|
|
|
|
|
|
|
|
const isFinal = offset + limitPart >= info.size; |
|
|
|
|
if(isFinal) { |
|
|
|
|
controller.close(); |
|
|
|
|
} |
|
|
|
|
const isFinal = offset + limitPart >= info.size; |
|
|
|
|
if(isFinal) { |
|
|
|
|
controller.close(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return Promise.resolve(); |
|
|
|
|
} |
|
|
|
|
}).catch(err => { |
|
|
|
|
log.error('[download] error:', err); |
|
|
|
|
controller.error(err); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
return Promise.resolve(); |
|
|
|
|
} |
|
|
|
|
}).catch(err => { |
|
|
|
|
log.error('[download] error:', err); |
|
|
|
|
controller.error(err); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
cancel() { |
|
|
|
|
log.error('[download] file canceled:', info); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
cancel() { |
|
|
|
|
log.error('[download] file canceled:', info); |
|
|
|
|
} |
|
|
|
|
resolve(new Response(stream, {headers})); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
resolve(new Response(stream, {headers})); |
|
|
|
|
}); |
|
|
|
|
event.respondWith(promise); |
|
|
|
|
|
|
|
|
|
event.respondWith(promise); |
|
|
|
|
break; |
|
|
|
|
} */ |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} */ |
|
|
|
|
case 'upload': { |
|
|
|
|
if(event.request.method == 'POST') { |
|
|
|
|
event.respondWith(event.request.blob().then(blob => { |
|
|
|
|
return apiFileManager.uploadFile(blob).then(v => new Response(JSON.stringify(v), {headers: {'Content-Type': 'application/json'}})); |
|
|
|
|
})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case 'upload': { |
|
|
|
|
if(event.request.method == 'POST') { |
|
|
|
|
event.respondWith(event.request.blob().then(blob => { |
|
|
|
|
return apiFileManager.uploadFile(blob).then(v => new Response(JSON.stringify(v), {headers: {'Content-Type': 'application/json'}})); |
|
|
|
|
})); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* default: { |
|
|
|
|
/* default: { |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case 'documents': |
|
|
|
|
case 'photos': |
|
|
|
|
case 'profiles': |
|
|
|
|
// direct download
|
|
|
|
|
if (event.request.method === 'POST') { |
|
|
|
|
event.respondWith(// download(url, 'unknown file.txt', getFilePartRequest));
|
|
|
|
|
event.request.text() |
|
|
|
|
.then((text) => { |
|
|
|
|
const [, filename] = text.split('='); |
|
|
|
|
return download(url, filename ? filename.toString() : 'unknown file', getFilePartRequest); |
|
|
|
|
}), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// inline
|
|
|
|
|
} else { |
|
|
|
|
event.respondWith( |
|
|
|
|
ctx.cache.match(url).then((cached) => { |
|
|
|
|
if (cached) return cached; |
|
|
|
|
|
|
|
|
|
return Promise.race([ |
|
|
|
|
timeout(45 * 1000), // safari fix
|
|
|
|
|
new Promise<Response>((resolve) => { |
|
|
|
|
fetchRequest(url, resolve, getFilePartRequest, ctx.cache, fileProgress); |
|
|
|
|
}), |
|
|
|
|
]); |
|
|
|
|
}), |
|
|
|
|
); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case 'documents': |
|
|
|
|
case 'photos': |
|
|
|
|
case 'profiles': |
|
|
|
|
// direct download
|
|
|
|
|
if (event.request.method === 'POST') { |
|
|
|
|
event.respondWith(// download(url, 'unknown file.txt', getFilePartRequest));
|
|
|
|
|
event.request.text() |
|
|
|
|
.then((text) => { |
|
|
|
|
const [, filename] = text.split('='); |
|
|
|
|
return download(url, filename ? filename.toString() : 'unknown file', getFilePartRequest); |
|
|
|
|
}), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// inline
|
|
|
|
|
} else { |
|
|
|
|
event.respondWith( |
|
|
|
|
ctx.cache.match(url).then((cached) => { |
|
|
|
|
if (cached) return cached; |
|
|
|
|
|
|
|
|
|
return Promise.race([ |
|
|
|
|
timeout(45 * 1000), // safari fix
|
|
|
|
|
new Promise<Response>((resolve) => { |
|
|
|
|
fetchRequest(url, resolve, getFilePartRequest, ctx.cache, fileProgress); |
|
|
|
|
}), |
|
|
|
|
]); |
|
|
|
|
}), |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'stream': { |
|
|
|
|
const [offset, end] = parseRange(event.request.headers.get('Range') || ''); |
|
|
|
|
case 'stream': { |
|
|
|
|
const [offset, end] = parseRange(event.request.headers.get('Range') || ''); |
|
|
|
|
|
|
|
|
|
log('stream', url, offset, end); |
|
|
|
|
log('stream', url, offset, end); |
|
|
|
|
|
|
|
|
|
event.respondWith(new Promise((resolve) => { |
|
|
|
|
fetchStreamRequest(url, offset, end, resolve, getFilePartRequest); |
|
|
|
|
})); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
event.respondWith(new Promise((resolve) => { |
|
|
|
|
fetchStreamRequest(url, offset, end, resolve, getFilePartRequest); |
|
|
|
|
})); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case 'stripped': |
|
|
|
|
case 'cached': { |
|
|
|
|
const bytes = getThumb(url) || null; |
|
|
|
|
event.respondWith(new Response(bytes, { headers: { 'Content-Type': 'image/jpg' } })); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case 'stripped': |
|
|
|
|
case 'cached': { |
|
|
|
|
const bytes = getThumb(url) || null; |
|
|
|
|
event.respondWith(new Response(bytes, { headers: { 'Content-Type': 'image/jpg' } })); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
if (url && url.endsWith('.tgs')) event.respondWith(fetchTGS(url)); |
|
|
|
|
else event.respondWith(fetch(event.request.url)); */ |
|
|
|
|
default: |
|
|
|
|
if (url && url.endsWith('.tgs')) event.respondWith(fetchTGS(url)); |
|
|
|
|
else event.respondWith(fetch(event.request.url)); */ |
|
|
|
|
} |
|
|
|
|
} catch(err) { |
|
|
|
|
event.respondWith(new Response('', { |
|
|
|
|
status: 500, |
|
|
|
|
statusText: 'Internal Server Error', |
|
|
|
|
})); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Fetch requests |
|
|
|
|
*/ |
|
|
|
|
//ctx.addEventListener('fetch', );
|
|
|
|
|
ctx.onfetch = onFetch; |
|
|
|
|
|
|
|
|
|
const DOWNLOAD_CHUNK_LIMIT = 512 * 1024; |
|
|
|
|
//const STREAM_CHUNK_UPPER_LIMIT = 256 * 1024;
|
|
|
|
|
//const SMALLEST_CHUNK_LIMIT = 256 * 4;
|
|
|
|
|
const STREAM_CHUNK_UPPER_LIMIT = 1024 * 1024; |
|
|
|
|
const SMALLEST_CHUNK_LIMIT = 1024 * 4; |
|
|
|
|
|
|
|
|
|
/* const STREAM_CHUNK_UPPER_LIMIT = 256 * 1024; |
|
|
|
|
const SMALLEST_CHUNK_LIMIT = 256 * 4; */ |
|
|
|
|
/* const STREAM_CHUNK_UPPER_LIMIT = 1024 * 1024; |
|
|
|
|
const SMALLEST_CHUNK_LIMIT = 1024 * 4; */ |
|
|
|
|
const STREAM_CHUNK_UPPER_LIMIT = 512 * 1024; |
|
|
|
|
const SMALLEST_CHUNK_LIMIT = 512 * 4; |
|
|
|
|
|
|
|
|
|
function parseRange(header: string): [number, number] { |
|
|
|
|
if(!header) return [0, 0]; |
|
|
|
|