Skip to content

Commit

Permalink
Clean everything up and get it working
Browse files Browse the repository at this point in the history
  • Loading branch information
gmaclennan committed Jan 20, 2023
1 parent e24a465 commit c519632
Show file tree
Hide file tree
Showing 16 changed files with 1,000 additions and 239 deletions.
16 changes: 16 additions & 0 deletions buf.gen.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: v1
plugins:
- name: ts
out: lib
strategy: all
path: node_modules/ts-proto/protoc-gen-ts_proto
opt:
- esModuleInterop=true
- snakeToCamel=false
- importSuffix=.js
- initializeFieldsAsUndefined=false
- env=node
- exportCommonSymbols=false
- outputJsonMethods=false
- useOptionals=none
- outputPartialMethods=false
105 changes: 105 additions & 0 deletions lib/core-manager/core-index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import crypto from 'hypercore-crypto'
import { TypedEmitter } from 'tiny-typed-emitter'

/** @typedef {import('./index.js').Namespace} Namespace */
/** @typedef {{ core: import('hypercore').default, key: Buffer, namespace: Namespace }} CoreRecord */
/**
* @typedef {Object} CoreIndexEvents
* @property {(coreRecord: CoreRecord) => void} add-core
*/

// WARNING: If changed once in production then we need a migration strategy
const TABLE = 'cores'
const CREATE_SQL = `CREATE TABLE IF NOT EXISTS ${TABLE} (
publicKey BLOB NOT NULL,
namespace TEXT NOT NULL
)`

/**
* @extends {TypedEmitter<CoreIndexEvents>}
*/
export class CoreIndex extends TypedEmitter {
/** @type {Map<string, CoreRecord>} */
#coresByDiscoveryId = new Map()
/** @type {Map<Namespace, CoreRecord>} */
#writersByNamespace = new Map()
#addCoreSqlStmt

/**
* @param {object} options
* @param {import('better-sqlite3').Database} options.db better-sqlite3 database instance
*/
constructor ({ db }) {
super()
// Make sure table exists for persisting known cores
db.prepare(CREATE_SQL).run()
// Pre-prepare SQL statement for better performance
this.#addCoreSqlStmt = db.prepare(
`INSERT OR IGNORE INTO ${TABLE} VALUES (@publicKey, @namespace)`
)
}

/**
* NB. Need to pass key here because `core.key` is not populated until the
* core is ready, but we know it beforehand.
*
* @param {Object} options
* @param {import('hypercore').default} options.core Hypercore instance
* @param {Buffer} options.key Buffer containing public key of this core
* @param {Namespace} options.namespace
* @param {boolean} [options.writer] Is this a writer core?
* @param {boolean} [options.persist] Persist to cb?
*/
add ({ core, key, namespace, writer = false, persist = false }) {
const discoveryKey = crypto.discoveryKey(key)
const discoveryId = discoveryKey.toString('hex')
const record = { core, key, namespace }
if (writer) {
this.#writersByNamespace.set(namespace, record)
}
this.#coresByDiscoveryId.set(discoveryId, record)
if (persist) {
this.#addCoreSqlStmt.run({ publicKey: key, namespace })
}
this.emit('add-core', { core, key, namespace })
}

/**
*
* @param {Namespace} namespace
* @returns {CoreRecord[]}
*/
getByNamespace (namespace) {
const records = []
for (const record of this.#coresByDiscoveryId.values()) {
if (record.namespace === namespace) records.push(record)
}
return records
}

/**
*
* @param {Namespace} namespace
* @returns
*/
getWriter (namespace) {
return this.#writersByNamespace.get(namespace)
}

/**
* @param {string} discoveryId
* @returns {CoreRecord | undefined}
*/
getByDiscoveryId (discoveryId) {
return this.#coresByDiscoveryId.get(discoveryId)
}

/**
* @param {Buffer} coreKey
* @returns {CoreRecord | undefined}
*/
getByCoreKey (coreKey) {
const discoveryId = crypto.discoveryKey(coreKey).toString('hex')
return this.#coresByDiscoveryId.get(discoveryId)
}
}
Loading

0 comments on commit c519632

Please sign in to comment.