-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(source-memory): add memory source (#372)
* feat: add a memory source * fix: support non recursive list * refactor: sort the package references * refactor: cleanup lint
- Loading branch information
Showing
12 changed files
with
241 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
tsconfig.tsbuildinfo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Change Log | ||
|
||
All notable changes to this project will be documented in this file. | ||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# @chunkd/source-memory | ||
|
||
Use memory as a simple file system, | ||
|
||
this is designed for unit tests to prevent file system access, and not recommended for large file workloads. | ||
|
||
## Usage | ||
|
||
```javascript | ||
import { FsMemory } from '@chunkd/source-memory'; | ||
|
||
fsa.register('memory://', new FsMemory()); | ||
|
||
await fsa.write('memory://foo.png', pngBuffer); | ||
|
||
await fsa.read('memory://foo.png'); // png | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"name": "@chunkd/source-memory", | ||
"version": "8.2.0", | ||
"type": "module", | ||
"engines": { | ||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/blacha/chunkd.git", | ||
"directory": "packages/source-memory" | ||
}, | ||
"main": "./build/index.js", | ||
"types": "./build/index.d.ts", | ||
"author": "Blayne Chard", | ||
"license": "MIT", | ||
"scripts": {}, | ||
"dependencies": { | ||
"@chunkd/core": "^8.2.0" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^17.0.35" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { toArray } from '@chunkd/core'; | ||
import o from 'ospec'; | ||
import { FsMemory } from '../memory.fs.js'; | ||
|
||
o.spec('FsMemory', () => { | ||
const memory = new FsMemory(); | ||
|
||
o.afterEach(() => { | ||
memory.files.clear(); | ||
}); | ||
o('should write files', async () => { | ||
o(memory.files.size).equals(0); | ||
await memory.write('memory://foo.png', Buffer.from('a')); | ||
o(memory.files.size).equals(1); | ||
|
||
const b = await memory.read('memory://foo.png'); | ||
o(b.toString()).equals('a'); | ||
}); | ||
|
||
o('should stream files', async () => { | ||
await memory.write('memory://foo.png', Buffer.from('a')); | ||
|
||
await memory.write('memory://bar.png', memory.stream('memory://foo.png')); | ||
o(memory.files.size).equals(2); | ||
|
||
const bar = await memory.read('memory://bar.png'); | ||
o(bar.toString()).equals('a'); | ||
}); | ||
|
||
o('should list files', async () => { | ||
await memory.write('memory://a/b/c.png', Buffer.from('a')); | ||
await memory.write('memory://a/d.png', Buffer.from('a')); | ||
|
||
o(await toArray(memory.list('memory://a/b'))).deepEquals(['memory://a/b/c.png']); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { SourceMemory } from '@chunkd/core'; | ||
export { FsMemory } from './memory.fs.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { CompositeError, FileInfo, FileSystem, ListOptions, SourceMemory } from '@chunkd/core'; | ||
import { Readable } from 'stream'; | ||
|
||
export function toReadable(r: string | Buffer | Readable): Readable { | ||
if (typeof r === 'string') r = Buffer.from(r); | ||
return Readable.from(r); | ||
} | ||
|
||
export async function toBuffer(stream: Readable): Promise<Buffer> { | ||
return new Promise<Buffer>((resolve, reject) => { | ||
const buf: Buffer[] = []; | ||
|
||
stream.on('data', (chunk) => buf.push(chunk)); | ||
stream.on('end', () => resolve(Buffer.concat(buf))); | ||
stream.on('error', (err) => reject(`error converting stream - ${err}`)); | ||
}); | ||
} | ||
|
||
export class FsMemory implements FileSystem<SourceMemory> { | ||
protocol = 'memory'; | ||
|
||
files: Map<string, Buffer> = new Map(); | ||
|
||
async read(filePath: string): Promise<Buffer> { | ||
const data = this.files.get(filePath); | ||
if (data == null) throw new CompositeError('Not found', 404, new Error()); | ||
return data; | ||
} | ||
|
||
stream(filePath: string): Readable { | ||
const buf = this.files.get(filePath); | ||
if (buf == null) throw new CompositeError('Not found', 404, new Error()); | ||
return toReadable(buf); | ||
} | ||
|
||
async write(filePath: string, buffer: string | Buffer | Readable): Promise<void> { | ||
if (typeof buffer === 'string') { | ||
this.files.set(filePath, Buffer.from(buffer)); | ||
return; | ||
} | ||
if (Buffer.isBuffer(buffer)) { | ||
this.files.set(filePath, buffer); | ||
return; | ||
} | ||
const buf = await toBuffer(buffer); | ||
this.files.set(filePath, buf); | ||
} | ||
|
||
async *list(filePath: string, opt?: ListOptions): AsyncGenerator<string> { | ||
const folders = new Set(); | ||
for (const file of this.files.keys()) { | ||
if (file.startsWith(filePath)) { | ||
if (opt?.recursive === false) { | ||
const subPath = file.slice(filePath.length); | ||
const parts = subPath.split('/'); | ||
if (parts.length === 1) yield file; | ||
else { | ||
const folderName = parts[0]; | ||
if (folders.has(folderName)) continue; | ||
folders.add(folderName); | ||
yield filePath + folderName + '/'; | ||
} | ||
} else { | ||
yield file; | ||
} | ||
} | ||
} | ||
} | ||
|
||
async *details(filePath: string, opt?: ListOptions): AsyncGenerator<FileInfo> { | ||
for await (const file of this.list(filePath, opt)) { | ||
const data = await this.head(file); | ||
if (data == null) { | ||
yield { path: file, isDirectory: true }; | ||
} else { | ||
yield data; | ||
} | ||
} | ||
} | ||
|
||
async exists(filePath: string): Promise<boolean> { | ||
const dat = await this.head(filePath); | ||
return dat != null; | ||
} | ||
|
||
async head(filePath: string): Promise<FileInfo | null> { | ||
const buf = this.files.get(filePath); | ||
if (buf == null) return null; | ||
return { path: filePath, size: buf.length }; | ||
} | ||
|
||
source(filePath: string): SourceMemory { | ||
const bytes = this.files.get(filePath); | ||
if (bytes == null) throw new CompositeError('File not found', 404, new Error()); | ||
const source = new SourceMemory(filePath, bytes); | ||
return source; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"extends": "../../tsconfig.base.json", | ||
"compilerOptions": { | ||
"rootDir": "./src", | ||
"outDir": "./build", | ||
"lib": ["es2018", "DOM"] | ||
}, | ||
"include": ["src/**/*", "src/.ts"], | ||
"references": [{ "path": "../core" }] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters