Skip to content

Commit

Permalink
bring in rpc clients
Browse files Browse the repository at this point in the history
  • Loading branch information
LiranCohen committed Apr 1, 2024
1 parent 30eae0f commit 8cf351d
Show file tree
Hide file tree
Showing 26 changed files with 2,162 additions and 269 deletions.
2 changes: 1 addition & 1 deletion packages/agent/build/esbuild-tests.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const browserConfig = require('./esbuild-browser-config.cjs');
esbuild.build({
...browserConfig,
format : 'esm',
entryPoints : ['./tests/*.spec.*'],
entryPoints : ['./tests/**/*.spec.*'],
bundle : true,
minify : false,
outdir : 'tests/compiled',
Expand Down
1 change: 1 addition & 0 deletions packages/agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@web5/dids": "0.4.3",
"abstract-level": "1.0.4",
"ed25519-keygen": "0.4.11",
"isomorphic-ws": "^5.0.0",
"level": "8.0.0",
"ms": "2.1.3",
"readable-web-to-node-stream": "3.0.2",
Expand Down
7 changes: 4 additions & 3 deletions packages/agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@ export type * from './types/identity-vault.js';
export type * from './types/key-manager.js';
export type * from './types/sync.js';
export type * from './types/vc.js';
export type * from './prototyping/clients/web5-rpc-types.js';

export * from './bearer-identity.js';
export * from './crypto-api.js';
export * from './did-api.js';
export * from './dwn-api.js';
export * from './hd-identity-vault.js';
export * from './identity-api.js';
export * from './json-rpc.js';
export * from './prototyping/clients/json-rpc.js';
export * from './local-key-manager.js';
export * from './rpc-client.js';
export * from './prototyping/clients/web5-rpc-client.js';
export * from './store-data.js';
export * from './store-did.js';
export * from './store-identity.js';
export * from './store-key.js';
export * from './sync-api.js';
export * from './sync-engine-level.js';
export * from './test-harness.js';
export * from './utils.js';
export * from './utils.js';
159 changes: 159 additions & 0 deletions packages/agent/src/prototyping/clients/dwn-server-info-cache-level.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import type { AbstractLevel } from 'abstract-level';

import ms from 'ms';
import { Level } from 'level';
import { DwnServerInfoCache, ServerInfo } from './web5-rpc-types.js';

/**
* Configuration parameters for creating a LevelDB-based cache for DWN Server Info results.
*
* Allows customization of the underlying database instance, storage location, and cache
* time-to-live (TTL) settings.
*/
export type DwnServerCacheLevelParams = {
/**
* Optional. An instance of `AbstractLevel` to use as the database. If not provided, a new
* LevelDB instance will be created at the specified `location`.
*/
db?: AbstractLevel<string | Buffer | Uint8Array, string, string>;

/**
* Optional. The file system path or IndexedDB name where the LevelDB store will be created.
* Defaults to 'DATA/DWN_SERVERINFOCACHE' if not specified.
*/
location?: string;

/**
* Optional. The time-to-live for cache entries, expressed as a string (e.g., '1h', '15m').
* Determines how long a cache entry should remain valid before being considered expired. Defaults
* to '15m' if not specified.
*/
ttl?: string;
}

/**
* Encapsulates a ServerInfo result along with its expiration information for caching purposes.
*
* This type is used internally by the `DwnServerInfoCacheLevel` to store DWN ServerInfo results
* with an associated time-to-live (TTL) value. The TTL is represented in milliseconds and
* determines when the cached entry is considered expired and eligible for removal.
*/
type CacheWrapper = {
/**
* The expiration time of the cache entry in milliseconds since the Unix epoch.
*
* This value is used to calculate whether the cached entry is still valid or has expired.
*/
ttlMillis: number;

/**
* The DWN ServerInfo entry being cached.
*/
value: ServerInfo;
}

/**
* A Level-based cache implementation for storing and retrieving DWN ServerInfo results.
*
* This cache uses LevelDB for storage, allowing data persistence across process restarts or
* browser refreshes. It's suitable for both Node.js and browser environments.
*
* @remarks
* The LevelDB cache keeps data in memory for fast access and also writes to the filesystem in
* Node.js or indexedDB in browsers. Time-to-live (TTL) for cache entries is configurable.
*
* @example
* ```
* const cache = new DwnServerInfoCacheLevel({ ttl: '15m' });
* ```
*/
export class DwnServerInfoCacheLevel implements DwnServerInfoCache {
/** The underlying LevelDB store used for caching. */
private cache: AbstractLevel<string | Buffer | Uint8Array, string, string>;

/** The time-to-live for cache entries in milliseconds. */
private ttl: number;

constructor({
db,
location = 'DATA/DWN_SERVERINFOCACHE',
ttl = '15m'
}: DwnServerCacheLevelParams = {}) {
this.cache = db ?? new Level<string, string>(location);
this.ttl = ms(ttl);
}

/**
* Retrieves a DWN ServerInfo entry from the cache.
*
* If the cached item has exceeded its TTL, it's scheduled for deletion and undefined is returned.
*
* @param dwnUrl - The DWN URL endpoint string used as the key for retrieving the cached result.
* @returns The cached ServerInfo entry or undefined if not found or expired.
*/
async get(dwnUrl: string): Promise<ServerInfo| void> {
try {
const str = await this.cache.get(dwnUrl);
const cacheWrapper: CacheWrapper = JSON.parse(str);

if (Date.now() >= cacheWrapper.ttlMillis) {
// defer deletion to be called in the next tick of the js event loop
this.cache.nextTick(() => this.cache.del(dwnUrl));

return;
} else {
return cacheWrapper.value;
}

} catch(error: any) {
// Don't throw when a key wasn't found.
if (error.notFound) {
return;
}

throw error;
}
}

/**
* Stores a DWN ServerInfo entry in the cache with a TTL.
*
* @param dwnUrl - The DWN URL endpoint string used as the key for storing the result.
* @param value - The DWN ServerInfo entry to be cached.
* @returns A promise that resolves when the operation is complete.
*/
set(dwnUrl: string, value: ServerInfo): Promise<void> {
const cacheWrapper: CacheWrapper = { ttlMillis: Date.now() + this.ttl, value };
const str = JSON.stringify(cacheWrapper);

return this.cache.put(dwnUrl, str);
}

/**
* Deletes a DWN ServerInfo entry from the cache.
*
* @param dwnUrl - The DWN URL endpoint string used as the key deletion.
* @returns A promise that resolves when the operation is complete.
*/
delete(dwnUrl: string): Promise<void> {
return this.cache.del(dwnUrl);
}

/**
* Clears all entries from the cache.
*
* @returns A promise that resolves when the operation is complete.
*/
clear(): Promise<void> {
return this.cache.clear();
}

/**
* Closes the underlying LevelDB store.
*
* @returns A promise that resolves when the store is closed.
*/
close(): Promise<void> {
return this.cache.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

import ms from 'ms';
import { TtlCache } from '@web5/common';
import { DwnServerInfoCache, ServerInfo } from './web5-rpc-types.js';

/**
* Configuration parameters for creating an in-memory cache for DWN ServerInfo entries.
*
* Allows customization of the cache time-to-live (TTL) setting.
*/
export type DwnServerInfoCacheMemoryParams = {
/**
* Optional. The time-to-live for cache entries, expressed as a string (e.g., '1h', '15m').
* Determines how long a cache entry should remain valid before being considered expired.
*
* Defaults to '15m' if not specified.
*/
ttl?: string;
}

export class DwnServerInfoCacheMemory implements DwnServerInfoCache {
private cache: TtlCache<string, ServerInfo>;

constructor({ ttl = '15m' }: DwnServerInfoCacheMemoryParams= {}) {
this.cache = new TtlCache({ ttl: ms(ttl) });
}

/**
* Retrieves a DWN ServerInfo entry from the cache.
*
* If the cached item has exceeded its TTL, it's scheduled for deletion and undefined is returned.
*
* @param dwnUrl - The DWN URL endpoint string used as the key for getting the entry.
* @returns The cached DWN ServerInfo entry or undefined if not found or expired.
*/
public async get(dwnUrl: string): Promise<ServerInfo| void> {
return this.cache.get(dwnUrl);
}

/**
* Stores a DWN ServerInfo entry in the cache with a TTL.
*
* @param dwnUrl - The DWN URL endpoint string used as the key for storing the entry.
* @param value - The DWN ServerInfo entry to be cached.
* @returns A promise that resolves when the operation is complete.
*/
public async set(dwnUrl: string, value: ServerInfo): Promise<void> {
this.cache.set(dwnUrl, value);
}

/**
* Deletes a DWN ServerInfo entry from the cache.
*
* @param dwnUrl - The DWN URL endpoint string used as the key for deletion.
* @returns A promise that resolves when the operation is complete.
*/
public async delete(dwnUrl: string): Promise<void> {
this.cache.delete(dwnUrl);
}

/**
* Clears all entries from the cache.
*
* @returns A promise that resolves when the operation is complete.
*/
public async clear(): Promise<void> {
this.cache.clear();
}

/**
* This method is a no-op but exists to be consistent with other DWN ServerInfo Cache
* implementations.
*
* @returns A promise that resolves immediately.
*/
public async close(): Promise<void> {
// No-op since there is no underlying store to close.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

import { DwnServerInfoCache, ServerInfo } from './web5-rpc-types.js';

export class DwnServerInfoCacheNoOp implements DwnServerInfoCache {

public async get(_dwnUrl: string): Promise<ServerInfo| void> {}

public async set(_dwnUrl: string, _value: ServerInfo): Promise<void> {}

public async delete(_dwnUrl: string): Promise<void> {}

public async clear(): Promise<void> {}

public async close(): Promise<void> {}
}
Loading

0 comments on commit 8cf351d

Please sign in to comment.