working-state
parent
69c441ba56
commit
d8cae0f559
@ -0,0 +1,25 @@
|
||||
import {error, Middleware} from "@extollo/lib"
|
||||
import {Injectable} from "@extollo/di"
|
||||
import {HTTPStatus} from "@extollo/util"
|
||||
|
||||
/**
|
||||
* ValidateExposureTransaction Middleware
|
||||
* --------------------------------------------
|
||||
* Errors out the request if it is missing any fields required to create
|
||||
* a new exposure notification on the blockchain.
|
||||
*/
|
||||
@Injectable()
|
||||
export class ValidateExposureTransaction extends Middleware {
|
||||
public async apply() {
|
||||
const required: string[] = [
|
||||
'clientID',
|
||||
'timestamp',
|
||||
]
|
||||
|
||||
for ( const field of required ) {
|
||||
if ( !this.request.input(field) ) {
|
||||
return error(`Missing required field: ${field}`, HTTPStatus.BAD_REQUEST, 'json')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import {FirebaseResource, FirebaseResourceItem} from "../FirebaseResource"
|
||||
import {Injectable} from "@extollo/di"
|
||||
import {RTDBRef} from "../units/FirebaseUnit"
|
||||
import {AsyncCollection} from "@extollo/util"
|
||||
|
||||
/**
|
||||
* Interface representing a client-submitted encounter transaction.
|
||||
*/
|
||||
export interface ExposureResourceItem extends FirebaseResourceItem {
|
||||
clientID: string; // the exposed client's ID - used as one half of the hashes
|
||||
timestamp: number; // the unix-time in milliseconds when the interaction occurred
|
||||
}
|
||||
|
||||
/**
|
||||
* A Firebase realtime-database resource for managing exposure transactions.
|
||||
*/
|
||||
@Injectable()
|
||||
export class ExposureResource extends FirebaseResource<ExposureResourceItem> {
|
||||
public static collect(): AsyncCollection<ExposureResourceItem> {
|
||||
return new AsyncCollection<ExposureResourceItem>(new ExposureResource())
|
||||
}
|
||||
|
||||
protected refName: RTDBRef = 'exposure'
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
import { FirebaseUnit } from "../FirebaseUnit"
|
||||
import { Singleton, Inject } from "@extollo/di"
|
||||
import { Unit, Logging } from "@extollo/lib"
|
||||
import { Blockchain } from "../Blockchain"
|
||||
import { ExposureResource, ExposureResourceItem } from "../../rtdb/ExposureResource"
|
||||
|
||||
/**
|
||||
* Exposure Unit
|
||||
* ---------------------------------------
|
||||
* This unit listens for exposure notifications created on the realtime database.
|
||||
* When new ones come through, it validates them, and pushes them onto this
|
||||
* server's blockchain.
|
||||
*/
|
||||
@Singleton()
|
||||
export class Exposure extends Unit {
|
||||
/** True if currently processing transactions. */
|
||||
private processing: boolean = false
|
||||
|
||||
@Inject()
|
||||
protected readonly firebase!: FirebaseUnit
|
||||
|
||||
@Inject()
|
||||
protected readonly blockchain!: Blockchain
|
||||
|
||||
@Inject()
|
||||
protected readonly logging!: Logging
|
||||
|
||||
/** Claim the right to process transactions. Returns true if the right was granted. */
|
||||
claim() {
|
||||
if ( !this.processing ) {
|
||||
this.processing = true
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/** Release the right to claim transactions. */
|
||||
release() {
|
||||
this.processing = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the transactions reference and wait for new transactions to be added.
|
||||
*/
|
||||
public async up() {
|
||||
this.firebase.ref('exposure').on('child_added', async (snapshot) => {
|
||||
this.logging.debug('Received child_added event for exposures reference.')
|
||||
if ( !this.claim() ) return
|
||||
await this.firebase.trylock('block')
|
||||
|
||||
const exposure: ExposureResourceItem = snapshot.val()
|
||||
|
||||
// Push the exposure transactions onto the chain
|
||||
await this.blockchain.submitExposures(exposure)
|
||||
|
||||
if ( snapshot.key )
|
||||
await (<ExposureResource> this.make(ExposureResource)).ref().child(snapshot.key).remove()
|
||||
|
||||
this.release()
|
||||
await this.firebase.unlock('block')
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Release listeners and resources before shutdown.
|
||||
*/
|
||||
public async down() {
|
||||
// Release all subscriptions before shutdown
|
||||
this.firebase.ref("transaction").off()
|
||||
}
|
||||
}
|
Loading…
Reference in new issue