Skip to content

Commit

Permalink
Merge pull request #169 from plasma-group/dev-framework
Browse files Browse the repository at this point in the history
Convert plasma-core to use new framework design
  • Loading branch information
smartcontracts committed Apr 7, 2019
2 parents 755ae73 + ed0a9e2 commit 3116d56
Show file tree
Hide file tree
Showing 190 changed files with 4,619 additions and 4,254 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ lerna-debug.log
npm-debug.log
/**/npm-debug.log
/packages/**/LICENSE.txt
testdb/
6 changes: 6 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@pigi/utils": "^0.0.1-alpha.10",
"@pigi/verifier": "^0.0.1-alpha.7",
"@types/bn.js": "^4.11.4",
"@types/memdown": "^3.0.0",
"async-lock": "^1.1.4",
"axios": "^0.18.0",
"bn.js": "^4.11.8",
Expand All @@ -40,6 +41,8 @@
"ethereumjs-vm": "^2.6.0",
"ethers": "^4.0.27",
"lodash": "^4.17.11",
"memdown": "^4.0.0",
"reflect-metadata": "^0.1.13",
"uuid": "^3.3.2",
"watch-eth": "0.0.1-beta.7",
"web3": "^1.0.0-beta.48",
Expand All @@ -49,13 +52,16 @@
},
"devDependencies": {
"@pigi/prettier-config": "^0.0.2-alpha.2",
"@pigi/watch-eth": "^0.0.1-alpha.1",
"@types/abstract-leveldown": "^5.0.1",
"@types/async-lock": "^1.1.1",
"@types/chai": "^4.1.7",
"@types/chai-as-promised": "^7.1.0",
"@types/debug": "^4.1.2",
"@types/lodash": "^4.14.123",
"@types/mocha": "^5.2.6",
"@types/uuid": "^3.4.4",
"abstract-leveldown": "^6.0.2",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"ganache-cli": "^6.4.1",
Expand Down
28 changes: 0 additions & 28 deletions packages/core/src/app.module.ts

This file was deleted.

81 changes: 81 additions & 0 deletions packages/core/src/app/common/app/app.ts
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()
})
})
)
}
}
2 changes: 2 additions & 0 deletions packages/core/src/app/common/app/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './app'
export * from './process'
119 changes: 119 additions & 0 deletions packages/core/src/app/common/app/process.ts
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()
})
})
}
}
100 changes: 100 additions & 0 deletions packages/core/src/app/common/db/bucket.ts
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
}
}

0 comments on commit 3116d56

Please sign in to comment.