UNPKG

kura

Version:

The FileSystem API abstraction library.

169 lines (152 loc) 4.78 kB
import { AbstractAccessor } from "./AbstractAccessor"; import { AbstractFileEntry } from "./AbstractFileEntry"; import { blobToFile, createEmptyFile } from "./FileSystemUtil"; import { FileSystemObject } from "./FileSystemObject"; import { FileWriter } from "./filewriter"; import { NotImplementedError } from "./FileError"; export abstract class AbstractFileWriter<T extends AbstractAccessor> implements FileWriter { public DONE: number; public INIT: number; public WRITING: number; public error: Error; public onabort: (event: ProgressEvent<EventTarget>) => void; public onerror: (event: ProgressEvent<EventTarget>) => void; public onprogress: (event: ProgressEvent<EventTarget>) => void; public onwrite: (event: ProgressEvent<EventTarget>) => void; public onwriteend: (event: ProgressEvent<EventTarget>) => void; public onwritestart: (event: ProgressEvent<EventTarget>) => void; public position = 0; public readyState: number; constructor(protected fileEntry: AbstractFileEntry<T>, public file: File) {} public get length() { return this.fileEntry.size; } public abort(): void { throw new NotImplementedError( this.fileEntry.filesystem.name, this.fileEntry.fullPath ); } public addEventListener( type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions ): void { throw new NotImplementedError( this.fileEntry.filesystem.name, this.fileEntry.fullPath ); } public dispatchEvent(event: Event): boolean { throw new NotImplementedError( this.fileEntry.filesystem.name, this.fileEntry.fullPath ); } public removeEventListener( type: string, callback: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions ): void { throw new NotImplementedError( this.fileEntry.filesystem.name, this.fileEntry.fullPath ); } public seek(offset: number): void { this.position = offset; if (this.length < this.position) { this.position = this.length; } else if (this.position < 0) { this.position = 0; } } public truncate(size: number): void { const current = this.file; let file: File; if (current) { if (size < this.length) { file = blobToFile([current.slice(0, size)], current.name, Date.now()); } else { file = blobToFile( [current, new Uint8Array(size - this.length)], current.name, Date.now() ); } } else { file = createEmptyFile(this.fileEntry.name); } this.doWrite(file, () => { this.file = file; this.position = 0; }); } public write(data: Blob): void { const current = this.file; if (current) { const head = current.slice(0, this.position); const tail = current.slice(this.position + data.size); let padding = this.position - head.size; if (padding < 0) { padding = 0; } const file = blobToFile( [head, new Uint8Array(padding), data, tail], current.name, Date.now() ); this.doWrite(file, () => { this.file = file; this.position += data.size; }); } else { const file = blobToFile([data], this.fileEntry.name, Date.now()); this.doWrite(file, () => { this.file = file; this.position = data.size; }); } } protected doWrite(blob: Blob, onsuccess: () => void) { const obj: FileSystemObject = { name: this.fileEntry.name, fullPath: this.fileEntry.fullPath, lastModified: Date.now(), size: blob.size, }; const accessor = this.fileEntry.params.accessor; accessor .putObject(obj, blob) .then(() => { this.fileEntry.params.lastModified = obj.lastModified; this.fileEntry.params.size = obj.size; onsuccess(); if (this.onwriteend) { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const evt: ProgressEvent<EventTarget> = { loaded: this.position, total: this.length, lengthComputable: true, } as any; this.onwriteend(evt); } }) .catch((err) => { if (this.onerror) { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const evt: ProgressEvent<EventTarget> = { error: err, // eslint-disable-line @typescript-eslint/no-unsafe-assignment loaded: this.position, total: this.length, lengthComputable: true, } as any; this.onerror(evt); } else { console.error("AbstractFileWriter#doWrite", err); } }); } }