Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: improve types for Hypercore peers #735

Merged
merged 1 commit into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/core-manager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { coresTable } from '../schema/project.js'
import * as rle from './bitfield-rle.js'
import { CoreIndex } from './core-index.js'

/** @typedef {import('../types.js').HypercorePeer} HypercorePeer */

const WRITER_CORE_PREHAVES_DEBOUNCE_DELAY = 1000

export const kCoreManagerReplicate = Symbol('replicate core manager')
Expand Down Expand Up @@ -401,7 +403,7 @@ export class CoreManager extends TypedEmitter {

/**
* @param {ProjectExtension} msg
* @param {any} peer
* @param {HypercorePeer} peer
*/
#handleProjectMessage({ wantCoreKeys, ...coreKeys }, peer) {
const message = ProjectExtension.create()
Expand All @@ -426,7 +428,7 @@ export class CoreManager extends TypedEmitter {

/**
* @param {Omit<HaveMsg, 'namespace'> & { namespace: Namespace | 'UNRECOGNIZED' }} msg
* @param {any} peer
* @param {HypercorePeer} peer
*/
#handleHaveMessage(msg, peer) {
const { start, discoveryKey, bitfield, namespace } = msg
Expand All @@ -444,7 +446,7 @@ export class CoreManager extends TypedEmitter {

/**
*
* @param {any} peer
* @param {HypercorePeer} peer
* @param {Iterable<{ core: Hypercore<Hypercore.ValueEncoding, Buffer>, namespace: Namespace }>} cores
*/
async #sendHaves(peer, cores) {
Expand Down Expand Up @@ -640,7 +642,7 @@ function findPeer(core, publicKey, { timeout = 200 } = {}) {

core.on('peer-add', onPeer)

/** @param {any} peer */
/** @param {HypercorePeer} peer */
function onPeer(peer) {
if (peer.remotePublicKey.equals(publicKey)) {
clearTimeout(timeoutId)
Expand Down
16 changes: 9 additions & 7 deletions src/sync/core-sync-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { keyToId } from '../utils.js'
import RemoteBitfield, {
BITS_PER_PAGE,
} from '../core-manager/remote-bitfield.js'
/** @typedef {import('../types.js').HypercoreRemoteBitfield} HypercoreRemoteBitfield */
/** @typedef {import('../types.js').HypercorePeer} HypercorePeer */

/**
* @typedef {RemoteBitfield} Bitfield
Expand Down Expand Up @@ -192,7 +194,7 @@ export class CoreSyncState {
* emit state updates whenever the peer remote bitfield changes
*
* (defined as class field to bind to `this`)
* @param {any} peer
* @param {HypercorePeer} peer
*/
#onPeerAdd = (peer) => {
const peerId = keyToId(peer.remotePublicKey)
Expand All @@ -217,11 +219,11 @@ export class CoreSyncState {
// a result of these two internal calls.
const originalOnBitfield = peer.onbitfield
const originalOnRange = peer.onrange
peer.onbitfield = (/** @type {any[]} */ ...args) => {
peer.onbitfield = (...args) => {
originalOnBitfield.apply(peer, args)
this.#update()
}
peer.onrange = (/** @type {any[]} */ ...args) => {
peer.onrange = (...args) => {
originalOnRange.apply(peer, args)
this.#update()
}
Expand All @@ -231,7 +233,7 @@ export class CoreSyncState {
* Handle a peer being removed - keeps it in state, but sets state.connected = false
*
* (defined as class field to bind to `this`)
* @param {any} peer
* @param {HypercorePeer} peer
*/
#onPeerRemove = (peer) => {
const peerId = keyToId(peer.remotePublicKey)
Expand All @@ -253,7 +255,7 @@ export class CoreSyncState {
export class PeerState {
/** @type {Bitfield} */
#preHaves = new RemoteBitfield()
/** @type {Bitfield | undefined} */
/** @type {HypercoreRemoteBitfield | undefined} */
#haves
/** @type {Bitfield} */
#wants = new RemoteBitfield()
Expand All @@ -274,7 +276,7 @@ export class PeerState {
return this.#preHaves.insert(start, bitfield)
}
/**
* @param {Bitfield} bitfield
* @param {HypercoreRemoteBitfield} bitfield
*/
setHavesBitfield(bitfield) {
this.#haves = bitfield
Expand Down Expand Up @@ -434,7 +436,7 @@ export function bitCount32(n) {
/**
* Get a 32-bit "chunk" (word) of the bitfield.
*
* @param {RemoteBitfield} bitfield
* @param {Bitfield | HypercoreRemoteBitfield} bitfield
* @param {number} index
*/
function getBitfieldWord(bitfield, index) {
Expand Down
25 changes: 25 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
} from 'type-fest'
import { SUPPORTED_BLOB_VARIANTS } from './blob-store/index.js'
import { MapeoCommon, MapeoDoc, MapeoValue, decode } from '@mapeo/schema'
import type BigSparseArray from 'big-sparse-array'
import type Protomux from 'protomux'
import type NoiseStream from '@hyperswarm/secret-stream'
import { Duplex } from 'streamx'
Expand Down Expand Up @@ -105,6 +106,30 @@ export type PublicKey = Buffer
export type SecretKey = Buffer
export type IdentityKeyPair = KeyPair

type HypercoreRemoteBitfieldPage = {
bitfield: Uint32Array
}

/**
* A subset of Hypercore's `RemoteBitfield` class that we use.
*/
export type HypercoreRemoteBitfield = {
_pages: BigSparseArray<HypercoreRemoteBitfieldPage>
get(index: number): boolean
}

/**
* A subset of Hypercore's `Peer` class that we use.
* TODO: Contribute these types upstream.
*/
export type HypercorePeer = {
protomux: Protomux
remotePublicKey: Buffer
remoteBitfield: HypercoreRemoteBitfield
onbitfield: (options: { start: number; bitfield: Buffer }) => void
onrange: (options: { drop: boolean; start: number; length: number }) => void
}

export { NoiseStream }
type ProtocolStream = Omit<NoiseStream, 'userData'> & {
userData: Protomux
Expand Down
Loading