UNPKG

@ssb-graphql/whakapapa

Version:

GraphQL types and resolvers for the ssb-whakapapa plugin

118 lines (100 loc) 3.37 kB
const Cache = require('hashlru') const pull = require('pull-stream') const paraMap = require('pull-paramap') module.exports = function linksCache (sbot) { const cache = { 'link/profile-profile/child': Cache(6000), 'link/profile-profile/partner': Cache(4000) } const API = { /* set */ setParent (type, recordId, links) { if (!cache[type]) cache[type] = Cache(2000) cache[type].set(cacheKey({ parent: recordId }), links) }, setChild (type, recordId, links) { if (!cache[type]) cache[type] = Cache(2000) cache[type].set(cacheKey({ child: recordId }), links) }, /* remove */ removeParent (type, recordId) { if (!cache[type]) return cache[type].remove(cacheKey({ parent: recordId })) }, removeChild (type, recordId) { if (!cache[type]) return cache[type].remove(cacheKey({ child: recordId })) }, has (type, { parent, child }) { const typeCache = cache[type] if (!typeCache) return false if (!parent && !child) throw new Error('must provide parent AND/OR child') const results = [] if (parent) results.push(typeCache.has(cacheKey({ parent }))) if (child) results.push(typeCache.has(cacheKey({ child }))) return results.every(bool => bool === true) }, get (type, { parent, child }) { const typeCache = cache[type] if (!typeCache) return if (!parent && !child) throw new Error('must provide parent AND/OR child') if (!this.has(type, { parent, child })) return return [ ...(parent ? typeCache.get(cacheKey({ parent })) : []), ...(child ? typeCache.get(cacheKey({ child })) : []) ] } } // invalidate type cache if any new message comes in for a particular pair // this is naive! sbot.post(m => { sbot.get({ id: m.key, meta: true, private: true }, (err, m) => { if (err) return if (typeof m.value.content === 'string') return pull( pull.values([m]), invalidateSink() ) }) }) // NOTE - this should work, but for some reason does not :( // pull( // sbot.createLogStream({ live: true, old: false, private: true }), // invalidateSink() // ) function invalidateSink () { return pull( pull.map(m => m.value.content), pull.filter(content => content.type in cache), pull.filter(content => typeof content?.tangles?.link === 'object'), paraMap( (content, cb) => { if (content.tangles.link.root === null) return cb(null, content) sbot.get({ id: content.tangles.link.root, private: true }, (err, rootVal) => { if (err) cb(null, null) // swallow error else cb(null, rootVal.content) }) }, 6 ), pull.filter(Boolean), pull.drain(({ type, parent, child }) => { API.removeParent(type, parent) API.removeChild(type, child) // some of these are directed links, some are not API.removeParent(type, child) API.removeChild(type, parent) }, (err) => { if (err) console.error('Error in linksCache:', err) }) ) } return API } function cacheKey ({ parent, child }) { if (parent && child) throw new Error('can only store EITHER child OR parent links') return parent ? parent + '_' : '_' + child }