-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #169 from plasma-group/dev-framework
Convert plasma-core to use new framework design
- Loading branch information
Showing
190 changed files
with
4,619 additions
and
4,254 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,3 +16,4 @@ lerna-debug.log | |
npm-debug.log | ||
/**/npm-debug.log | ||
/packages/**/LICENSE.txt | ||
testdb/ |
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 was deleted.
Oops, something went wrong.
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,81 @@ | ||
import { DebugLogger } from '../utils' | ||
import { Process } from './process' | ||
|
||
/** | ||
* Basic application framework. Makes it easy to | ||
* start/stop different processes. | ||
*/ | ||
export class BaseApp { | ||
private logger = new DebugLogger('app') | ||
private processes: Record<string, Process<any>> = {} | ||
|
||
/** | ||
* Registers a process to the app. | ||
* @param name Name of the process. | ||
* @param process Process to register. | ||
*/ | ||
public register(name: string, process: Process<any>): void { | ||
if (name in this.processes) { | ||
throw new Error(`process already registered: ${name}`) | ||
} | ||
|
||
this.processes[name] = process | ||
} | ||
|
||
/** | ||
* Queries a specific process by name. | ||
* @param name Name of the process. | ||
* @returns the process registered with that name. | ||
*/ | ||
public query(name: string): Process<any> { | ||
if (!(name in this.processes)) { | ||
throw new Error(`process does not exist: ${name}`) | ||
} | ||
|
||
return this.processes[name] | ||
} | ||
|
||
/** | ||
* Starts all processes. | ||
*/ | ||
public async start(): Promise<void> { | ||
await this.execute(async (name: string, process: Process<any>) => { | ||
this.logger.log(`starting process: ${name}`) | ||
await process.start() | ||
this.logger.log(`started process: ${name}`) | ||
}) | ||
} | ||
|
||
/** | ||
* Stops all processes. | ||
*/ | ||
public async stop(): Promise<void> { | ||
await this.execute(async (name: string, process: Process<any>) => { | ||
this.logger.log(`stopping process: ${name}`) | ||
await process.stop() | ||
this.logger.log(`stopped process: ${name}`) | ||
}) | ||
} | ||
|
||
/** | ||
* Executes some function in parallel for all processes. | ||
* @param fn Function to execute. | ||
*/ | ||
private async execute( | ||
fn: (name: string, process: Process<any>) => Promise<void> | ||
): Promise<void> { | ||
await Promise.all( | ||
Object.keys(this.processes).map((name) => { | ||
return new Promise<void>(async (resolve, reject) => { | ||
try { | ||
await fn(name, this.processes[name]) | ||
} catch (err) { | ||
reject(err) | ||
return | ||
} | ||
resolve() | ||
}) | ||
}) | ||
) | ||
} | ||
} |
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 * from './app' | ||
export * from './process' |
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,119 @@ | ||
import { EventEmitter } from 'events' | ||
import uuid = require('uuid') | ||
|
||
/** | ||
* Represents a basic process with start/stop functionality. | ||
* All processes have a "subject" - some value that the | ||
* process provides after it's been fully initialized. | ||
*/ | ||
export class Process<TSubject> { | ||
public subject: TSubject | ||
public readonly pid = uuid.v4() | ||
private ready = false | ||
private statusEmitter = new EventEmitter() | ||
private onStarted: Promise<void> | ||
private onStopped: Promise<void> | ||
|
||
/** | ||
* Creates the process. | ||
*/ | ||
constructor() { | ||
this.reset() | ||
} | ||
|
||
/** | ||
* @returns `true` if the process is ready, `false` otherwise. | ||
*/ | ||
public isReady(): boolean { | ||
return this.ready | ||
} | ||
|
||
/** | ||
* Starts the process. | ||
*/ | ||
public async start(): Promise<void> { | ||
if (this.ready) { | ||
return | ||
} | ||
|
||
this.reset() | ||
|
||
await this.onStart() | ||
this.ready = true | ||
this.statusEmitter.emit('started') | ||
} | ||
|
||
/** | ||
* Stops the process. | ||
*/ | ||
public async stop(): Promise<void> { | ||
if (!this.ready) { | ||
return | ||
} | ||
|
||
this.reset() | ||
|
||
await this.onStop() | ||
this.ready = false | ||
this.statusEmitter.emit('stopped') | ||
} | ||
|
||
/** | ||
* Waits until the process is started. | ||
*/ | ||
public async waitUntilStarted(): Promise<void> { | ||
if (!this.ready) { | ||
return this.onStarted | ||
} | ||
} | ||
|
||
/** | ||
* Waits until the process is stopped. | ||
*/ | ||
public async waitUntilStopped(): Promise<void> { | ||
if (this.ready) { | ||
return this.onStopped | ||
} | ||
} | ||
|
||
/** | ||
* Runs when the process is started. | ||
*/ | ||
protected async onStart(): Promise<void> { | ||
return | ||
} | ||
|
||
/** | ||
* Runs when the process is stopped. | ||
*/ | ||
protected async onStop(): Promise<void> { | ||
return | ||
} | ||
|
||
/** | ||
* Asserts that the process is ready and | ||
* throws otherwise. | ||
*/ | ||
protected assertReady(): void { | ||
if (!this.isReady()) { | ||
throw new Error('Process is not ready.') | ||
} | ||
} | ||
|
||
/** | ||
* Initializes lifecycle promises. | ||
*/ | ||
private reset(): void { | ||
this.statusEmitter.removeAllListeners() | ||
this.onStarted = new Promise<void>((resolve, _) => { | ||
this.statusEmitter.on('started', () => { | ||
resolve() | ||
}) | ||
}) | ||
this.onStopped = new Promise<void>((resolve, _) => { | ||
this.statusEmitter.on('stopped', () => { | ||
resolve() | ||
}) | ||
}) | ||
} | ||
} |
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,100 @@ | ||
import { | ||
Bucket, | ||
Batch, | ||
DB, | ||
IteratorOptions, | ||
Iterator, | ||
K, | ||
V, | ||
} from '../../../interfaces' | ||
|
||
/** | ||
* Simple bucket implementation that forwards all | ||
* calls up to the database but appends a prefix. | ||
*/ | ||
export class BaseBucket implements Bucket { | ||
constructor(readonly db: DB, readonly prefix: Buffer) {} | ||
|
||
/** | ||
* Queries the value at a given key. | ||
* @param key Key to query. | ||
* @returns the value at that key. | ||
*/ | ||
public async get(key: K): Promise<V> { | ||
return this.db.get(this.addPrefix(key)) | ||
} | ||
|
||
/** | ||
* Sets the value at a given key. | ||
* @param key Key to set. | ||
* @param value Value to set to. | ||
*/ | ||
public async put(key: K, value: V): Promise<void> { | ||
return this.db.put(this.addPrefix(key), value) | ||
} | ||
|
||
/** | ||
* Deletes a given key. | ||
* @param key Key to delete. | ||
*/ | ||
public async del(key: K): Promise<void> { | ||
return this.db.del(this.addPrefix(key)) | ||
} | ||
|
||
/** | ||
* Checks whether a given key is set. | ||
* @param key Key to query. | ||
* @returns `true` if the key is set, `false` otherwise. | ||
*/ | ||
public async has(key: K): Promise<boolean> { | ||
return this.db.has(this.addPrefix(key)) | ||
} | ||
|
||
/** | ||
* Performs a series of operations in batch. | ||
* @param operations Operations to perform. | ||
*/ | ||
public async batch(operations: ReadonlyArray<Batch>): Promise<void> { | ||
return this.db.batch( | ||
operations.map((op) => { | ||
return { | ||
...op, | ||
key: this.addPrefix(op.key), | ||
} | ||
}) | ||
) | ||
} | ||
|
||
/** | ||
* Creates an iterator with some options. | ||
* @param options Parameters for the iterator. | ||
* @returns the iterator instance. | ||
*/ | ||
public iterator(options?: IteratorOptions): Iterator { | ||
return this.db.iterator({ | ||
...options, | ||
prefix: this.addPrefix(options.prefix), | ||
}) | ||
} | ||
|
||
/** | ||
* Creates a prefixed bucket underneath | ||
* this bucket. | ||
* @param prefix Prefix to use for the bucket. | ||
* @returns the bucket instance. | ||
*/ | ||
public bucket(prefix: Buffer): Bucket { | ||
return this.db.bucket(this.addPrefix(prefix)) | ||
} | ||
|
||
/** | ||
* Concatenates some value to this bucket's prefix. | ||
* @param value Value to concatenate. | ||
* @returns the value concatenated to the prefix. | ||
*/ | ||
private addPrefix(value: Buffer): Buffer { | ||
return value !== undefined | ||
? Buffer.concat([this.prefix, value]) | ||
: this.prefix | ||
} | ||
} |
Oops, something went wrong.