wallet-storage
Version:
BRC100 conforming wallet, wallet storage and wallet signer components
137 lines (127 loc) • 7.03 kB
text/typescript
import { sdk, table, verifyTruthy } from '../../index.client'
import { StorageReader } from '../StorageReader'
/**
* Gets the next sync chunk of updated data from un-remoted storage (could be using a remote DB connection).
* @param storage
* @param args
* @returns
*/
export async function getSyncChunk(
storage: StorageReader,
args: sdk.RequestSyncChunkArgs
)
: Promise<sdk.SyncChunk>
{
const r: sdk.SyncChunk = {
fromStorageIdentityKey: '',
toStorageIdentityKey: '',
userIdentityKey: args.identityKey
}
let itemCount = args.maxItems
let roughSize = args.maxRoughSize
let i = 0
let done = false
const user = verifyTruthy(await storage.findUserByIdentityKey(args.identityKey))
if (!args.since || user.updated_at > args.since)
r.user = user
const chunkers: ChunkerArgs[] = [
{
name: 'provenTx', maxDivider: 100, preAdd: () => { r.provenTxs = [] }, addItem: (i: table.ProvenTx) => { r.provenTxs!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.getProvenTxsForUser( args ) }
},
{
name: 'outputBasket', maxDivider: 1, preAdd: () => { r.outputBaskets = [] }, addItem: (i: table.OutputBasket) => { r.outputBaskets!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.findOutputBaskets({ partial: { userId: args.userId }, since: args.since, paged: args.paged }) }
},
{
name: 'outputTag', maxDivider: 1, preAdd: () => { r.outputTags = [] }, addItem: (i: table.OutputTag) => { r.outputTags!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.findOutputTags({ partial: { userId: args.userId }, since: args.since, paged: args.paged }) }
},
{
name: 'txLabel', maxDivider: 1, preAdd: () => { r.txLabels = [] }, addItem: (i: table.TxLabel) => { r.txLabels!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.findTxLabels({ partial: { userId: args.userId }, since: args.since, paged: args.paged }) }
},
{
name: 'transaction', maxDivider: 25, preAdd: () => { r.transactions = [] }, addItem: (i: table.Transaction) => { r.transactions!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.findTransactions({ partial: { userId: args.userId }, since: args.since, paged: args.paged }) }
},
{
name: 'output', maxDivider: 25, preAdd: () => { r.outputs = [] }, addItem: (i: table.Output) => { r.outputs!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.findOutputs({ partial: { userId: args.userId }, since: args.since, paged: args.paged }) }
},
{
name: 'txLabelMap', maxDivider: 1, preAdd: () => { r.txLabelMaps = [] }, addItem: (i: table.TxLabelMap) => { r.txLabelMaps!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.getTxLabelMapsForUser(args) }
},
{
name: 'outputTagMap', maxDivider: 1, preAdd: () => { r.outputTagMaps = [] }, addItem: (i: table.OutputTagMap) => { r.outputTagMaps!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.getOutputTagMapsForUser(args) }
},
{
name: 'certificate', maxDivider: 25, preAdd: () => { r.certificates = [] }, addItem: (i: table.Certificate) => { r.certificates!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.findCertificates({ partial: { userId: args.userId }, since: args.since, paged: args.paged }) }
},
{
name: 'certificateField', maxDivider: 25, preAdd: () => { r.certificateFields = [] }, addItem: (i: table.CertificateField) => { r.certificateFields!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.findCertificateFields({ partial: { userId: args.userId }, since: args.since, paged: args.paged }) }
},
{
name: 'commission', maxDivider: 25, preAdd: () => { r.commissions = [] }, addItem: (i: table.Commission) => { r.commissions!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.findCommissions({ partial: { userId: args.userId }, since: args.since, paged: args.paged }) }
},
{
name: 'provenTxReq', maxDivider: 100, preAdd: () => { r.provenTxReqs = [] }, addItem: (i: table.ProvenTxReq) => { r.provenTxReqs!.push(i) },
findItems: async (storage: StorageReader, args: sdk.FindForUserSincePagedArgs) => { return await storage.getProvenTxReqsForUser(args) }
},
]
const addItems = async (a: ChunkerArgs) => {
if (i >= args.offsets.length) { done = true; return }
let { offset, name: oname } = args.offsets[i++]
if (a.name !== oname) throw new sdk.WERR_INVALID_PARAMETER('offsets', `in dependency order. '${a.name}' expected, found ${oname}.`);
let preAddCalled = false
for (; !done;) {
const limit = Math.min(itemCount, Math.max(10, args.maxItems / a.maxDivider))
if (limit <= 0) break;
const items = await a.findItems(storage, { userId: user.userId, since: args.since, paged: { limit, offset } })
checkEntityValues(items)
if (!preAddCalled) { a.preAdd(); preAddCalled = true }
if (items.length === 0) break;
for (const item of items) {
offset++
a.addItem(item)
itemCount--
roughSize -= JSON.stringify(item).length
if (itemCount <= 0 || roughSize < 0) { done = true; break; }
}
}
}
for (; !done;) {
for (const c of chunkers) {
await addItems(c)
}
}
return r
}
type ChunkerArgs = {
name: string,
maxDivider: number,
preAdd: () => void,
addItem: (i: any) => void,
findItems: (
storage: StorageReader,
args: sdk.FindForUserSincePagedArgs
) => Promise<any[]>,
}
function checkIsDate(v: any) {
if (!(v instanceof Date))
throw new sdk.WERR_INVALID_OPERATION('bad date')
}
function checkEntityValues(es: object[]) {
for (const e of es) {
checkIsDate(e['created_at'])
checkIsDate(e['updated_at'])
for (const key of Object.keys(e))
if (e[key] === null)
throw new sdk.WERR_INVALID_OPERATION()
}
}