Deleted dead code.
This commit is contained in:
1 parent
eae420a5a4
commit
8dcd8cc425
4 files changed
+51
-70
No files matched your search
+19
-2
@@ -1,14 +1,31 @@
|
|||||||
import { Context, Router } from './deps.ts';
|
import { Context, Router } from './deps.ts';
|
||||||
import { FileService } from './services/mod.ts';
|
import { FileMetaData, FileService } from './services/mod.ts';
|
||||||
import { readerFromStreamReader } from './deps.ts';
|
import { readerFromStreamReader } from './deps.ts';
|
||||||
import { asyncIterableToArray } from './utils.ts';
|
import { asyncIterableToArray } from './utils.ts';
|
||||||
|
|
||||||
type Handler = (ctx: Context) => void;
|
type Handler = (ctx: Context) => void;
|
||||||
|
|
||||||
|
class FileDTO {
|
||||||
|
readonly path: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly size: number;
|
||||||
|
|
||||||
|
constructor(path: string, id: string, size: number){
|
||||||
|
this.path = path;
|
||||||
|
this.id = id;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromFileMetaData(fm: FileMetaData): FileDTO{
|
||||||
|
return new FileDTO();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function listFileHandlerFactory(fileService: FileService): Handler {
|
function listFileHandlerFactory(fileService: FileService): Handler {
|
||||||
return async (ctx: Context) => {
|
return async (ctx: Context) => {
|
||||||
ctx.response.type = 'application/json';
|
ctx.response.type = 'application/json';
|
||||||
ctx.response.body = await asyncIterableToArray(fileService.list());
|
ctx.response.body = (await asyncIterableToArray(fileService.list())).map(FileDTO.fromFileMetaData);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-63
@@ -4,11 +4,16 @@ import { BlobService, FileMetaData, FileService } from './interfaces.ts';
|
|||||||
|
|
||||||
import { readableStreamFromReader, readerFromStreamReader } from 'https://deno.land/std@0.191.0/streams/mod.ts';
|
import { readableStreamFromReader, readerFromStreamReader } from 'https://deno.land/std@0.191.0/streams/mod.ts';
|
||||||
|
|
||||||
|
enum CompressionAlgorithm{
|
||||||
|
UNCOMPRESSED = 'uncompressed',
|
||||||
|
GZIP = 'gzip',
|
||||||
|
}
|
||||||
|
|
||||||
interface SerializedFile {
|
interface SerializedFile {
|
||||||
id: string;
|
id: string;
|
||||||
path: string;
|
path: string;
|
||||||
contentSize: number;
|
contentSize: number;
|
||||||
compression: string;
|
compression: CompressionAlgorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SerializedFilePathIndex {
|
interface SerializedFilePathIndex {
|
||||||
@@ -24,65 +29,42 @@ export class DenoKVBlobService implements BlobService {
|
|||||||
this.blobSize = blobSize;
|
this.blobSize = blobSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async sha1(msgUint8: Uint8Array): Promise<string> {
|
private async sha1(content: Uint8Array): Promise<string> {
|
||||||
const hashBuffer = await crypto.subtle.digest('SHA-1', msgUint8);
|
const hashBuffer = await crypto.subtle.digest('SHA-1', content);
|
||||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||||
return hashArray
|
return hashArray
|
||||||
.map((b) => b.toString(16).padStart(2, '0'))
|
.map((b) => b.toString(16).padStart(2, '0'))
|
||||||
.join(''); // convert bytes to hex string
|
.join(''); // convert bytes to hex string
|
||||||
}
|
}
|
||||||
|
|
||||||
private *splitText(content: Uint8Array): Generator<Uint8Array> {
|
private async unsafePersistChunck(blobIndex: string, chunckIndex: number, content: Uint8Array): Promise<void> {
|
||||||
let blobCount = 0;
|
|
||||||
let txt = content.slice(
|
|
||||||
blobCount * this.blobSize,
|
|
||||||
(blobCount + 1) * this.blobSize,
|
|
||||||
);
|
|
||||||
while (txt.length > 0) {
|
|
||||||
yield txt;
|
|
||||||
blobCount += 1;
|
|
||||||
txt = content.slice(
|
|
||||||
blobCount * this.blobSize,
|
|
||||||
(blobCount + 1) * this.blobSize,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async unsafePersistBlob(mainIndex: string, index: number, content: Uint8Array): Promise<void> {
|
|
||||||
if (content.length > this.blobSize) {
|
if (content.length > this.blobSize) {
|
||||||
throw new Error('Persisted a too large blob');
|
throw new Error('Persisted a too large blob');
|
||||||
}
|
}
|
||||||
|
|
||||||
const blob_id = await this.sha1(content);
|
const blob_id = await this.sha1(content);
|
||||||
await this.kv.set(['blob_index', mainIndex, index], blob_id);
|
await this.kv.set(['blob_index', blobIndex, chunckIndex], blob_id);
|
||||||
await this.kv.set(['blob', blob_id], content);
|
await this.kv.set(['blob', blob_id], content);
|
||||||
}
|
}
|
||||||
|
|
||||||
async persistBlob(index: string, content: Uint8Array): Promise<number> {
|
persistBlob(index: string, content: Uint8Array): Promise<number> {
|
||||||
let blobCount = 0;
|
return this.persistReader(index, new Buffer(content));
|
||||||
let size = 0;
|
|
||||||
for (const txt of this.splitText(content)) {
|
|
||||||
await this.unsafePersistBlob(index, blobCount, txt);
|
|
||||||
size += txt.length;
|
|
||||||
blobCount += 1;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async persistReader(index: string, content: Deno.Reader): Promise<number> {
|
async persistReader(index: string, content: Deno.Reader): Promise<number> {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let size = 0;
|
let size = 0;
|
||||||
for await (const chunk of iterateReader(content, { bufSize: this.blobSize })) {
|
for await (const chunck of iterateReader(content, { bufSize: this.blobSize })) {
|
||||||
await this.unsafePersistBlob(index, i, chunk);
|
await this.unsafePersistChunck(index, i, chunck);
|
||||||
size += chunk.length;
|
size += chunck.length;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async *iterBlob(index: string): AsyncIterable<Uint8Array> {
|
private async *iterBlob(blobIndex: string): AsyncIterable<Uint8Array> {
|
||||||
for await (
|
for await (
|
||||||
const itm of this.kv.list<string>({ prefix: ['blob_index', index] })
|
const itm of this.kv.list<string>({ prefix: ['blob_index', blobIndex] })
|
||||||
) {
|
) {
|
||||||
const foo = await this.kv.get<Uint8Array>(['blob', itm.value]);
|
const foo = await this.kv.get<Uint8Array>(['blob', itm.value]);
|
||||||
if (foo.value === null) {
|
if (foo.value === null) {
|
||||||
@@ -102,20 +84,7 @@ export class DenoKVBlobService implements BlobService {
|
|||||||
return readerFromIterable(this.iterBlob(index));
|
return readerFromIterable(this.iterBlob(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async *iterRawBlobs(index: string): AsyncIterable<Uint8Array> {
|
async getNumberOfChunks(index: string): Promise<number> {
|
||||||
const prefix = ['blob_index', index];
|
|
||||||
for await (const itm of this.kv.list<string>({ prefix })) {
|
|
||||||
const foo = await this.kv.get<Uint8Array>(['blob', itm.value]);
|
|
||||||
if (foo.value === null) {
|
|
||||||
throw new Error(
|
|
||||||
`Inconsistant blob index for key "${foo.value}", this is very bad.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
yield foo.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getNumberOfBlobs(index: string): Promise<number> {
|
|
||||||
let ret = 0;
|
let ret = 0;
|
||||||
for await (
|
for await (
|
||||||
const _itm of this.kv.list<string>({ prefix: ['blob_index', index] })
|
const _itm of this.kv.list<string>({ prefix: ['blob_index', index] })
|
||||||
@@ -124,10 +93,6 @@ export class DenoKVBlobService implements BlobService {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
streamBlob(index: string): Deno.Reader {
|
|
||||||
return readerFromIterable(this.iterRawBlobs(index));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DenoKVFileService implements FileService {
|
export class DenoKVFileService implements FileService {
|
||||||
@@ -143,23 +108,21 @@ export class DenoKVFileService implements FileService {
|
|||||||
path: string,
|
path: string,
|
||||||
content: string | Uint8Array,
|
content: string | Uint8Array,
|
||||||
): Promise<FileMetaData> {
|
): Promise<FileMetaData> {
|
||||||
if (content instanceof Uint8Array) {
|
const reader = content instanceof Uint8Array ? new Buffer(content) : new StringReader(content);
|
||||||
return this.createFromReader(path, new Buffer(content));
|
return this.createFromReader(path, reader);
|
||||||
}
|
|
||||||
return this.createFromReader(path, new StringReader(content));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async createFromReader(path: string, content: Deno.Reader): Promise<FileMetaData> {
|
async createFromReader(path: string, content: Deno.Reader): Promise<FileMetaData> {
|
||||||
const newId = crypto.randomUUID();
|
const newId = crypto.randomUUID();
|
||||||
|
|
||||||
const compressedContent = readableStreamFromReader(content).pipeThrough(new CompressionStream('gzip'))
|
const compressedContent = readableStreamFromReader(content).pipeThrough(new CompressionStream(CompressionAlgorithm.GZIP))
|
||||||
.getReader();
|
.getReader();
|
||||||
const size = await this.blobService.persistReader(newId, readerFromStreamReader(compressedContent));
|
const size = await this.blobService.persistReader(newId, readerFromStreamReader(compressedContent));
|
||||||
const serializedFile: SerializedFile = {
|
const serializedFile: SerializedFile = {
|
||||||
id: newId,
|
id: newId,
|
||||||
path,
|
path,
|
||||||
contentSize: size,
|
contentSize: size,
|
||||||
compression: 'gzip',
|
compression: CompressionAlgorithm.GZIP,
|
||||||
};
|
};
|
||||||
const idx: SerializedFilePathIndex = { fileId: newId };
|
const idx: SerializedFilePathIndex = { fileId: newId };
|
||||||
await this.kv.set(['file', newId], serializedFile);
|
await this.kv.set(['file', newId], serializedFile);
|
||||||
@@ -211,13 +174,15 @@ export class DenoKVFileService implements FileService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private decompressContent(serializedFile: SerializedFile, content: Deno.Reader): Deno.Reader {
|
private decompressContent(serializedFile: SerializedFile, content: Deno.Reader): Deno.Reader {
|
||||||
if (serializedFile.compression == 'gzip') {
|
if(serializedFile.compression === CompressionAlgorithm.UNCOMPRESSED){
|
||||||
const ret = readableStreamFromReader(content).pipeThrough(new DecompressionStream('gzip')).getReader();
|
|
||||||
return readerFromStreamReader(ret);
|
|
||||||
}
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const decompresser = new DecompressionStream(serializedFile.compression);
|
||||||
|
const ret = readableStreamFromReader(content).pipeThrough(decompresser).getReader();
|
||||||
|
return readerFromStreamReader(ret);
|
||||||
|
}
|
||||||
|
|
||||||
async getRawContentByPath(path: string): Promise<Uint8Array | null> {
|
async getRawContentByPath(path: string): Promise<Uint8Array | null> {
|
||||||
const ret = await this.getContentAsReader(path);
|
const ret = await this.getContentAsReader(path);
|
||||||
return ret === null ? null : readAll(ret);
|
return ret === null ? null : readAll(ret);
|
||||||
|
|||||||
@@ -35,6 +35,5 @@ export interface BlobService {
|
|||||||
persistReader(index: string, content: Deno.Reader): Promise<number>;
|
persistReader(index: string, content: Deno.Reader): Promise<number>;
|
||||||
readAllBlob(index: string): Promise<Uint8Array>;
|
readAllBlob(index: string): Promise<Uint8Array>;
|
||||||
getBlob(index: string): Deno.Reader;
|
getBlob(index: string): Deno.Reader;
|
||||||
getNumberOfBlobs(index: string): Promise<number>;
|
getNumberOfChunks(index: string): Promise<number>;
|
||||||
streamBlob(index: string): Deno.Reader;
|
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ Deno.test('DenoKVBlobService happy path', async (t) => {
|
|||||||
const size = await bs.persistBlob('0002', toUint8Array('hello world'));
|
const size = await bs.persistBlob('0002', toUint8Array('hello world'));
|
||||||
const content = await bs.readAllBlob('0002');
|
const content = await bs.readAllBlob('0002');
|
||||||
assertEquals(content, toUint8Array('hello world'));
|
assertEquals(content, toUint8Array('hello world'));
|
||||||
assertEquals(await bs.getNumberOfBlobs('0002'), 1);
|
assertEquals(await bs.getNumberOfChunks('0002'), 1);
|
||||||
assertEquals(size, 'hello world'.length);
|
assertEquals(size, 'hello world'.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ Deno.test('DenoKVBlobService happy path', async (t) => {
|
|||||||
const size = await bs.persistBlob('0001', largeText);
|
const size = await bs.persistBlob('0001', largeText);
|
||||||
const content = await bs.readAllBlob('0001');
|
const content = await bs.readAllBlob('0001');
|
||||||
assertEquals(content, largeText);
|
assertEquals(content, largeText);
|
||||||
assertEquals(await bs.getNumberOfBlobs('0001'), 21);
|
assertEquals(await bs.getNumberOfChunks('0001'), 21);
|
||||||
assertEquals(size, largeText.length);
|
assertEquals(size, largeText.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ Deno.test('DenoKVBlobService happy path', async (t) => {
|
|||||||
const f = await Deno.open(fileName);
|
const f = await Deno.open(fileName);
|
||||||
const size = await bs.persistReader('large-stream', f);
|
const size = await bs.persistReader('large-stream', f);
|
||||||
|
|
||||||
assertEquals(await bs.getNumberOfBlobs('large-stream'), 1030);
|
assertEquals(await bs.getNumberOfChunks('large-stream'), 1030);
|
||||||
assertEquals((await Deno.readFile(fileName)).length, size);
|
assertEquals((await Deno.readFile(fileName)).length, size);
|
||||||
f.close();
|
f.close();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user