Skip to content

Commit

Permalink
feat: add client.list()
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuhvi committed Nov 16, 2023
1 parent 943a6f0 commit 100eb59
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 15 deletions.
61 changes: 61 additions & 0 deletions lib/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,67 @@ class Client {
return () => this._supscriptions.delete(url, callback)
}

/**
* Returns a list of items in a directory.
*
* @param {string} directory
* @param {object} [opts]
* @param {boolean} [opts.skipCache] - Skip the local cache and wait for the remote relay to respond with fresh data
*
* @returns {Promise<Array<string>>}
*/
async list (directory, opts = {}) {
if (!directory.endsWith('/')) directory += '/'
if (!directory.startsWith('/')) directory = '/' + directory

if (opts.skipCache) {
return this._listRelay(directory)
}

return this._listLocal(directory)
}

/**
* Returns a list of items in a directory from local store.
*
* @param {string} directory
*
* @returns {Promise<Array<string>>}
*/
async _listLocal (directory) {
const range = {
gte: PREFIXES.RECORDS + this.id + directory,
//
lte: PREFIXES.RECORDS + this.id + directory.slice(0, directory.length - 1) + '~'
}

const list = await this._store.iterator(range).all()

return list.map(r => r[0].split(PREFIXES.RECORDS + this.id + directory)[1])
}

/**
* Returns a list of items in a directory from the relay.
*
* @param {string} directory
*
* @returns {Promise<Array<string>>}
*/
async _listRelay (directory) {
const path = this.id + directory
const url = this._relay + '/' + path

const response = await fetch(url)

if (!response.ok) {
throw new Error(`Failed to list director ${directory} from relay ${this._relay}, status: ${response.status}`)
}

const text = await response.text()

return text.split('\n').map(p => p.split(path)[1]).filter(Boolean)
}

/**
* Return a url that can be shared by others to acess a file.
*
Expand Down
4 changes: 2 additions & 2 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions test/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,40 @@ test('throw errors on server 4XX response if awaitRelaySync set to true', async
relay.close()
})

test('list', async (t) => {
const relay = new Relay(tmpdir())

const address = await relay.listen()

const content = b4a.from(JSON.stringify({
name: 'Alice Bob Carl'
}))

const client = new Client({ storage: tmpdir(), relay: address })

for (let i = 0; i < 10; i++) {
await client.put(`/dir/subdir/foo${i}.txt`, content, { awaitRelaySync: true })
await client.put(`/dir/wrong/foo${i}.txt`, content, { awaitRelaySync: true })
}

const list = await client.list('/dir/subdir', { skipCache: true })

t.alike(list, [
'foo0.txt',
'foo1.txt',
'foo2.txt',
'foo3.txt',
'foo4.txt',
'foo5.txt',
'foo6.txt',
'foo7.txt',
'foo8.txt',
'foo9.txt'
])

relay.close()
})

function tmpdir () {
return path.join(os.tmpdir(), Math.random().toString(16).slice(2))
}
16 changes: 5 additions & 11 deletions test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ test('missing header', async (t) => {

const response = await fetch(
address + '/' + ZERO_ID + '/test.txt', {
method: 'PUT',
body: 'ffff'
})
method: 'PUT',
body: 'ffff'
})

t.is(response.status, 400)
t.is(response.statusText, `Missing or malformed header: '${HEADERS.RECORD}'`)
Expand Down Expand Up @@ -561,12 +561,6 @@ test('query all in a directory', async (t) => {
await relay._recordsDB.put('/' + GREATER_ID + `/dir/subdir/foo${i}.txt`, bytes)
}

// let result = relay._recordsDB.getRange({ start: "/" + ZERO_ID + "/", end: "/" + ZERO_ID + "0" }).asArray.map(({ key, value }) => {
// return { key, value: Record.deserialize(value) }
// })
//
// console.log(result)

const headers = {
[HEADERS.CONTENT_TYPE]: 'application/octet-stream'
}
Expand Down Expand Up @@ -598,11 +592,11 @@ test('query all in a directory', async (t) => {
relay.close()
})

function tmpdir() {
function tmpdir () {
return path.join(os.tmpdir(), Math.random().toString(16).slice(2))
}

/** @param {number} ms */
function sleep(ms) {
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
28 changes: 28 additions & 0 deletions types/lib/client/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,34 @@ declare class Client {
* @returns {() => void}
*/
subscribe(path: string, onupdate: (value: Uint8Array | null) => any): () => void;
/**
* Returns a list of items in a directory.
*
* @param {string} directory
* @param {object} [opts]
* @param {boolean} [opts.skipCache] - Skip the local cache and wait for the remote relay to respond with fresh data
*
* @returns {Promise<Array<string>>}
*/
list(directory: string, opts?: {
skipCache?: boolean;
}): Promise<Array<string>>;
/**
* Returns a list of items in a directory from local store.
*
* @param {string} directory
*
* @returns {Promise<Array<string>>}
*/
_listLocal(directory: string): Promise<Array<string>>;
/**
* Returns a list of items in a directory from the relay.
*
* @param {string} directory
*
* @returns {Promise<Array<string>>}
*/
_listRelay(directory: string): Promise<Array<string>>;
/**
* Return a url that can be shared by others to acess a file.
*
Expand Down
2 changes: 1 addition & 1 deletion types/lib/client/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions types/lib/server/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/// <reference types="node" />
/// <reference types="node" />
export = Relay;
declare class Relay {
static SERVER_SIDE_RECORDS_METADATA: string;
Expand Down Expand Up @@ -105,6 +106,25 @@ declare class Relay {
* @param {http.ServerResponse} res
*/
_SUBSCRIBE(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>;
/**
* @param {string} id
* @param {string} directory
* @param {object} [options]
* @param {number} [options.limit]
* @param {number} [options.offset]
*
* @returns {lmdb.RangeIterable}
*/
_searchDirectory(id: string, directory: string, options?: {
limit?: number;
offset?: number;
}): lmdb.RangeIterable<any>;
/**
* @param {http.IncomingMessage} _req
* @param {http.ServerResponse} res
* @param {URL} url
*/
_QUERY(_req: http.IncomingMessage, res: http.ServerResponse, url: URL): Promise<void>;
/**
* Health check endpoint to provide server metrics.
*
Expand All @@ -121,4 +141,6 @@ declare class Relay {
import http = require("http");
import Record = require("../record.js");
import Prometheus = require("prom-client");
import lmdb = require("lmdb");
import { URL } from "url";
//# sourceMappingURL=index.d.ts.map
2 changes: 1 addition & 1 deletion types/lib/server/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 100eb59

Please sign in to comment.