mirror of
https://github.com/wukko/cobalt.git
synced 2025-05-29 13:00:12 +02:00
web/storage: add memory storage and init() function
This commit is contained in:
parent
be4e7e2d7d
commit
ce4ded64a2
15
web/src/lib/storage/index.ts
Normal file
15
web/src/lib/storage/index.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import type { AbstractStorage } from "./storage";
|
||||
import { MemoryStorage } from "./memory";
|
||||
import { OPFSStorage } from "./opfs";
|
||||
|
||||
export function init(expectedSize?: number): Promise<AbstractStorage> {
|
||||
if (OPFSStorage.isAvailable()) {
|
||||
return OPFSStorage.init();
|
||||
}
|
||||
|
||||
if (MemoryStorage.isAvailable()) {
|
||||
return MemoryStorage.init(expectedSize || 0);
|
||||
}
|
||||
|
||||
throw "no storage method is available";
|
||||
}
|
91
web/src/lib/storage/memory.ts
Normal file
91
web/src/lib/storage/memory.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { AbstractStorage } from "./storage";
|
||||
|
||||
export class MemoryStorage extends AbstractStorage {
|
||||
#chunkSize: number;
|
||||
#actualSize: number = 0;
|
||||
#chunks: Uint8Array[] = [];
|
||||
|
||||
constructor(chunkSize: number) {
|
||||
super();
|
||||
this.#chunkSize = chunkSize;
|
||||
}
|
||||
|
||||
static async init(expectedSize: number) {
|
||||
const MB = 1024 * 1024;
|
||||
const chunkSize = Math.min(512 * MB, expectedSize);
|
||||
|
||||
const storage = new this(chunkSize);
|
||||
|
||||
// since we expect the output file to be roughly the same size
|
||||
// as inputs, preallocate its size for the output
|
||||
for (
|
||||
let toAllocate = expectedSize;
|
||||
toAllocate > 0;
|
||||
toAllocate -= chunkSize
|
||||
) {
|
||||
storage.#chunks.push(new Uint8Array(chunkSize));
|
||||
}
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
async res() {
|
||||
// if we didn't need as much space as we allocated for some reason,
|
||||
// shrink the buffers so that we don't inflate the file with zeroes
|
||||
const outputView: Uint8Array[] = [];
|
||||
|
||||
for (let i = 0; i < this.#chunks.length; ++i) {
|
||||
outputView.push(
|
||||
this.#chunks[i].subarray(
|
||||
0,
|
||||
Math.min(this.#chunkSize, this.#actualSize),
|
||||
),
|
||||
);
|
||||
|
||||
this.#actualSize -= this.#chunkSize;
|
||||
if (this.#actualSize <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Blob(outputView);
|
||||
}
|
||||
|
||||
#expand(size: number) {
|
||||
while (size > this.#chunkSize * this.#chunks.length) {
|
||||
this.#chunks.push(new Uint8Array(this.#chunkSize));
|
||||
}
|
||||
}
|
||||
|
||||
async write(data: Uint8Array | Int8Array, pos: number) {
|
||||
const writeEnd = pos + data.length;
|
||||
this.#expand(writeEnd);
|
||||
|
||||
const chunkIndex = pos / this.#chunkSize | 0;
|
||||
const offset = pos - (this.#chunkSize * chunkIndex);
|
||||
|
||||
if (offset + data.length > this.#chunkSize) {
|
||||
this.#chunks[chunkIndex].set(
|
||||
data.subarray(0, this.#chunkSize - offset),
|
||||
offset,
|
||||
);
|
||||
this.#chunks[chunkIndex + 1].set(
|
||||
data.subarray(this.#chunkSize - offset),
|
||||
0,
|
||||
);
|
||||
} else {
|
||||
this.#chunks[chunkIndex].set(data, offset);
|
||||
}
|
||||
|
||||
this.#actualSize = Math.max(writeEnd, this.#actualSize);
|
||||
return data.length;
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
this.#chunks = [];
|
||||
}
|
||||
|
||||
static isAvailable() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
export abstract class AbstractStorage {
|
||||
static init(): Promise<AbstractStorage> {
|
||||
static init(_expected_size: number): Promise<AbstractStorage> {
|
||||
throw "init() call on abstract implementation";
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user