@atproto/repo
Version:
atproto repo and MST implementation
107 lines (89 loc) • 2.24 kB
text/typescript
import { CID } from 'multiformats/cid'
import * as uint8arrays from 'uint8arrays'
import { dataToCborBlock } from '@atproto/common'
import { LexValue, lexToIpld } from '@atproto/lexicon'
export class BlockMap {
private map: Map<string, Uint8Array> = new Map()
async add(value: LexValue): Promise<CID> {
const block = await dataToCborBlock(lexToIpld(value))
this.set(block.cid, block.bytes)
return block.cid
}
set(cid: CID, bytes: Uint8Array): BlockMap {
this.map.set(cid.toString(), bytes)
return this
}
get(cid: CID): Uint8Array | undefined {
return this.map.get(cid.toString())
}
delete(cid: CID): BlockMap {
this.map.delete(cid.toString())
return this
}
getMany(cids: CID[]): { blocks: BlockMap; missing: CID[] } {
const missing: CID[] = []
const blocks = new BlockMap()
for (const cid of cids) {
const got = this.map.get(cid.toString())
if (got) {
blocks.set(cid, got)
} else {
missing.push(cid)
}
}
return { blocks, missing }
}
has(cid: CID): boolean {
return this.map.has(cid.toString())
}
clear(): void {
this.map.clear()
}
forEach(cb: (bytes: Uint8Array, cid: CID) => void): void {
this.map.forEach((val, key) => cb(val, CID.parse(key)))
}
entries(): Entry[] {
const entries: Entry[] = []
this.forEach((bytes, cid) => {
entries.push({ cid, bytes })
})
return entries
}
cids(): CID[] {
return this.entries().map((e) => e.cid)
}
addMap(toAdd: BlockMap): BlockMap {
toAdd.forEach((bytes, cid) => {
this.set(cid, bytes)
})
return this
}
get size(): number {
return this.map.size
}
get byteSize(): number {
let size = 0
this.forEach((bytes) => {
size += bytes.length
})
return size
}
equals(other: BlockMap): boolean {
if (this.size !== other.size) {
return false
}
for (const entry of this.entries()) {
const otherBytes = other.get(entry.cid)
if (!otherBytes) return false
if (!uint8arrays.equals(entry.bytes, otherBytes)) {
return false
}
}
return true
}
}
type Entry = {
cid: CID
bytes: Uint8Array
}
export default BlockMap