@orbitdb/core
Version:
Distributed p2p database on IPFS
114 lines (97 loc) • 2.44 kB
JavaScript
/**
* @namespace module:Log~Heads
* @memberof module:Log
* @description The log's heads.
* @private
*/
import Entry from './entry.js'
import MemoryStorage from '../storage/memory.js'
const DefaultStorage = MemoryStorage
const Heads = async ({ storage, heads, decryptPayloadFn, decryptEntryFn }) => {
storage = storage || await DefaultStorage()
const encoder = new TextEncoder()
const decoder = new TextDecoder()
const put = async (heads) => {
heads = findHeads(heads)
const newHeads = heads.map(e => ({ hash: e.hash, next: e.next }))
const bytes = encoder.encode(JSON.stringify(newHeads))
await storage.put('heads', bytes)
}
const add = async (head) => {
const currentHeads = await all()
if (currentHeads.find(e => Entry.isEqual(e, head))) {
return
}
const newHeads = findHeads([...currentHeads, head])
await put(newHeads)
return newHeads
}
const remove = async (hash) => {
const currentHeads = await all()
const newHeads = currentHeads.filter(e => e.hash !== hash)
await put(newHeads)
}
const iterator = async function * () {
const bytes = await storage.get('heads')
const headHashes = bytes ? JSON.parse(decoder.decode(bytes)) : []
for (const hash of headHashes) {
yield hash
}
}
const all = async () => {
const values = []
for await (const head of iterator()) {
values.push(head)
}
return values
}
const clear = async () => {
await storage.clear()
}
const close = async () => {
await storage.close()
}
// Initialize the heads if given as parameter
if (heads) {
await put(heads)
}
return {
put,
set: put,
add,
remove,
iterator,
all,
clear,
close
}
}
/**
* Find heads from a collection of entries.
*
* Finds entries that are the heads of this collection,
* ie. entries that are not referenced by other entries.
*
* This function is private and not exposed in the Log API
*
* @param {Array<Entry>} entries Entries to search heads from
* @return {Array<Entry>}
* @private
*/
const findHeads = (entries) => {
entries = new Set(entries)
const items = {}
for (const entry of entries) {
for (const next of entry.next) {
items[next] = entry.hash
}
}
const res = []
for (const entry of entries) {
if (!items[entry.hash]) {
res.push(entry)
}
}
return res
}
export default Heads