-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Clean everything up and get it working
- Loading branch information
1 parent
e24a465
commit c519632
Showing
16 changed files
with
1,000 additions
and
239 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
Oops, something went wrong.