Restart mechanics in GunSmith for once()s

This commit is contained in:
Daniel Lugo 2021-09-15 12:24:59 -04:00
parent 549f1ba4c4
commit 051d5aa5df
3 changed files with 63 additions and 15 deletions

View file

@ -2274,6 +2274,7 @@ module.exports = async (
* @prop {string=} publicKey
* @prop {string=} publicKeyForDecryption
* @prop {string=} epubForDecryption
* @prop {boolean=} mustBePopulated
*/
/**
* @param {HandleGunFetchParams} args0
@ -2285,7 +2286,8 @@ module.exports = async (
path,
publicKey,
publicKeyForDecryption,
epubForDecryption
epubForDecryption,
mustBePopulated
}) => {
const keys = path.split('>')
const { gun, user } = require('../services/gunDB/Mediator')
@ -2315,7 +2317,7 @@ module.exports = async (
}
}
if (type === 'once') node.once(listener)
if (type === 'once') node.once(listener, { mustBePopulated })
if (type === 'load') node.load(listener)
})
}
@ -2340,7 +2342,8 @@ module.exports = async (
startFromUserGraph: false,
type: 'once',
publicKeyForDecryption,
epubForDecryption
epubForDecryption,
mustBePopulated: !!req.header('must-be-populated')
})
res.status(200).json({
data
@ -2388,7 +2391,8 @@ module.exports = async (
startFromUserGraph: true,
type: 'once',
publicKeyForDecryption,
epubForDecryption
epubForDecryption,
mustBePopulated: !!req.header('must-be-populated')
})
res.status(200).json({
data

View file

@ -13,7 +13,7 @@ const { fork } = require('child_process')
const logger = require('../../config/log')
const { mergePuts } = require('./misc')
const { mergePuts, isPopulated } = require('./misc')
const gunUUID = () => {
const RG = /** @type {any} */ (RealGun)
@ -366,14 +366,29 @@ function createReplica(path, afterMap = false) {
mapListeners.delete(l)
}
},
on(cb) {
on(cb, { mustBePopulated } = {}) {
listenersForThisRef.push(cb)
let canaryPeep = false
const canary = () => {
canaryPeep = true
}
listenersForThisRef.push(canary)
const checkCanary = () =>
setTimeout(() => {
if (!canaryPeep && mustBePopulated) {
forge()
checkCanary()
}
}, 5000)
if (afterMap) {
// eslint-disable-next-line no-multi-assign
const listeners =
pathToMapListeners[path] || (pathToMapListeners[path] = new Set())
listeners.add(cb)
listeners.add(canary)
/** @type {Smith.SmithMsgMapOn} */
const msg = {
@ -387,6 +402,7 @@ function createReplica(path, afterMap = false) {
pathToListeners[path] || (pathToListeners[path] = new Set())
listeners.add(cb)
listeners.add(canary)
/** @type {Smith.SmithMsgOn} */
const msg = {
@ -398,7 +414,8 @@ function createReplica(path, afterMap = false) {
return this
},
once(cb, opts = { wait: 500 }) {
once(cb, _opts) {
const opts = { ...{ mustBePopulated: false, wait: 500 }, ..._opts }
// We could use this.on() but then we couldn't call .off()
const tmp = createReplica(path, afterMap)
if (afterMap) {
@ -412,15 +429,21 @@ function createReplica(path, afterMap = false) {
})
setTimeout(() => {
tmp.off()
if (cb) {
if (opts.mustBePopulated && !isPopulated(lastVal)) {
forge()
this.once(cb, { ...opts, wait: 5000, mustBePopulated: false })
} else {
cb(lastVal, path.split('>')[path.split('>').length - 1])
}
tmp.off()
}
}, opts.wait)
return this
},
put(data, cb) {
logger.info('put()')
const id = uuid()
const pendingPutsForPath = pendingPuts[path] || (pendingPuts[path] = [])
@ -502,11 +525,11 @@ function createReplica(path, afterMap = false) {
}
}
},
then() {
then(opts) {
return new Promise(res => {
this.once(data => {
res(data)
})
}, opts)
})
}
}

View file

@ -58,6 +58,14 @@ namespace GunT {
export type LoadListener = (data: LoadListenerData, key: string) => void
export interface GunSmithFetchOpts {
/**
* GunSmith exclusive. If set to true, gun will be restarted to force
* replication of this data.
*/
mustBePopulated?: boolean
}
export interface GUNNode {
_: Soul
/**
@ -81,13 +89,26 @@ namespace GunT {
load(this: GUNNode, cb?: LoadListener): GUNNode
map(): GUNNode
off(): void
on(this: GUNNode, cb: Listener): void
once(this: GUNNode, cb?: Listener, opts?: { wait: number }): GUNNode
on(
this: GUNNode,
cb: Listener,
opts?: {
change?: boolean
} & GunSmithFetchOpts
): void
once(
this: GUNNode,
cb?: Listener,
opts?: { wait?: number } & GunSmithFetchOpts
): GUNNode
user(): UserGUNNode
user(pub: string): GUNNode
put(data: ValidDataValue, cb?: Callback): GUNNode
set(data: ValidDataValue, cb?: Callback): GUNNode
then(): Promise<ListenerData>
/**
* @param options Gunsmith only.
*/
then(opts?: GunSmithFetchOpts): Promise<ListenerData>
}
export interface CreateAck {