From 596953886596825af294e2c26d22292906684244 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Thu, 19 Sep 2024 10:10:51 +0200 Subject: [PATCH 1/4] feat: add isPubSub method to detect PubSub implementations Adds a type disambiguator function to signal to tsc that an object implements the PubSub interface. --- packages/interface/src/pubsub/index.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/interface/src/pubsub/index.ts b/packages/interface/src/pubsub/index.ts index a269cc4e8f..3448f971ad 100644 --- a/packages/interface/src/pubsub/index.ts +++ b/packages/interface/src/pubsub/index.ts @@ -268,3 +268,19 @@ export interface PeerStreamEvents { 'stream:outbound': CustomEvent 'close': CustomEvent } + +export function isPubSub (obj?: any): obj is PubSub { + if (obj == null) { + return false + } + + return obj.globalSignaturePolicy != null && + Array.isArray(obj.multicodecs) && + obj.topicValidators != null && + typeof obj.getPeers === 'function' && + typeof obj.getTopics === 'function' && + typeof obj.subscribe === 'function' && + typeof obj.unsubscribe === 'function' && + typeof obj.getSubscribers === 'function' && + typeof obj.publish === 'function' +} From 3c463971a51b1a6a00a5a4a1035d9c472bbffd8f Mon Sep 17 00:00:00 2001 From: achingbrain Date: Thu, 19 Sep 2024 11:14:46 +0200 Subject: [PATCH 2/4] chore: switch to symbol --- packages/interface/src/pubsub/index.ts | 23 ++++++++----------- packages/pubsub-floodsub/src/index.ts | 4 +++- .../pubsub-floodsub/test/floodsub.spec.ts | 6 ++++- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/packages/interface/src/pubsub/index.ts b/packages/interface/src/pubsub/index.ts index 3448f971ad..a53d6c1500 100644 --- a/packages/interface/src/pubsub/index.ts +++ b/packages/interface/src/pubsub/index.ts @@ -269,18 +269,15 @@ export interface PeerStreamEvents { 'close': CustomEvent } +/** + * All Pubsub implementations must use this symbol as the name of a property + * with a boolean `true` value + */ +export const pubSubSymbol = Symbol.for('@libp2p/pubsub') + +/** + * Returns true if the passed argument is a PubSub implementation + */ export function isPubSub (obj?: any): obj is PubSub { - if (obj == null) { - return false - } - - return obj.globalSignaturePolicy != null && - Array.isArray(obj.multicodecs) && - obj.topicValidators != null && - typeof obj.getPeers === 'function' && - typeof obj.getTopics === 'function' && - typeof obj.subscribe === 'function' && - typeof obj.unsubscribe === 'function' && - typeof obj.getSubscribers === 'function' && - typeof obj.publish === 'function' + return Boolean(obj?.[pubSubSymbol]) } diff --git a/packages/pubsub-floodsub/src/index.ts b/packages/pubsub-floodsub/src/index.ts index fd92f0b379..a2517a68c3 100644 --- a/packages/pubsub-floodsub/src/index.ts +++ b/packages/pubsub-floodsub/src/index.ts @@ -32,7 +32,7 @@ * ``` */ -import { serviceDependencies } from '@libp2p/interface' +import { pubSubSymbol, serviceDependencies } from '@libp2p/interface' import { PubSubBaseProtocol, type PubSubComponents } from '@libp2p/pubsub' import { toString } from 'uint8arrays/to-string' import { SimpleTimeCache } from './cache.js' @@ -78,6 +78,8 @@ export class FloodSub extends PubSubBaseProtocol { }) } + readonly [pubSubSymbol] = true + readonly [Symbol.toStringTag] = '@libp2p/floodsub' readonly [serviceDependencies]: string[] = [ diff --git a/packages/pubsub-floodsub/test/floodsub.spec.ts b/packages/pubsub-floodsub/test/floodsub.spec.ts index 0a92559875..e25d3cc5b3 100644 --- a/packages/pubsub-floodsub/test/floodsub.spec.ts +++ b/packages/pubsub-floodsub/test/floodsub.spec.ts @@ -1,7 +1,7 @@ /* eslint-env mocha */ import { generateKeyPair } from '@libp2p/crypto/keys' -import { type Message, type PubSubRPC, StrictNoSign } from '@libp2p/interface' +import { type Message, type PubSubRPC, StrictNoSign, isPubSub } from '@libp2p/interface' import { mockRegistrar } from '@libp2p/interface-compliance-tests/mocks' import { defaultLogger } from '@libp2p/logger' import { PeerSet } from '@libp2p/peer-collections' @@ -47,6 +47,10 @@ describe('floodsub', () => { await floodsub.stop() }) + it('is a PubSub implementation', () => { + expect(isPubSub(floodsub)).to.be.true() + }) + it('checks cache when processing incoming message', async function () { const otherPeer = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) const sig = await sha256.encode(message) From 4940c59a7fabd2ca9a188d92d0704010e3b244d1 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Thu, 19 Sep 2024 11:16:49 +0200 Subject: [PATCH 3/4] chore: switch test to interface --- packages/interface-compliance-tests/src/pubsub/api.ts | 6 +++++- packages/pubsub-floodsub/test/floodsub.spec.ts | 4 ---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/interface-compliance-tests/src/pubsub/api.ts b/packages/interface-compliance-tests/src/pubsub/api.ts index 32cbc9920c..811d40cf23 100644 --- a/packages/interface-compliance-tests/src/pubsub/api.ts +++ b/packages/interface-compliance-tests/src/pubsub/api.ts @@ -1,4 +1,4 @@ -import { isStartable, start, stop } from '@libp2p/interface' +import { isPubSub, isStartable, start, stop } from '@libp2p/interface' import { expect } from 'aegir/chai' import delay from 'delay' import pDefer from 'p-defer' @@ -39,6 +39,10 @@ export default (common: TestSetup): void => { mockNetwork.reset() }) + it('is a PubSub implementation', () => { + expect(isPubSub(pubsub)).to.be.true() + }) + it('can start correctly', async () => { if (!isStartable(pubsub)) { return diff --git a/packages/pubsub-floodsub/test/floodsub.spec.ts b/packages/pubsub-floodsub/test/floodsub.spec.ts index e25d3cc5b3..563debe8c1 100644 --- a/packages/pubsub-floodsub/test/floodsub.spec.ts +++ b/packages/pubsub-floodsub/test/floodsub.spec.ts @@ -47,10 +47,6 @@ describe('floodsub', () => { await floodsub.stop() }) - it('is a PubSub implementation', () => { - expect(isPubSub(floodsub)).to.be.true() - }) - it('checks cache when processing incoming message', async function () { const otherPeer = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) const sig = await sha256.encode(message) From d21f386d76a205650f7ce5cb012e8e21fbee93c3 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Thu, 19 Sep 2024 11:20:00 +0200 Subject: [PATCH 4/4] chore: remove unused import --- packages/pubsub-floodsub/test/floodsub.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pubsub-floodsub/test/floodsub.spec.ts b/packages/pubsub-floodsub/test/floodsub.spec.ts index 563debe8c1..0a92559875 100644 --- a/packages/pubsub-floodsub/test/floodsub.spec.ts +++ b/packages/pubsub-floodsub/test/floodsub.spec.ts @@ -1,7 +1,7 @@ /* eslint-env mocha */ import { generateKeyPair } from '@libp2p/crypto/keys' -import { type Message, type PubSubRPC, StrictNoSign, isPubSub } from '@libp2p/interface' +import { type Message, type PubSubRPC, StrictNoSign } from '@libp2p/interface' import { mockRegistrar } from '@libp2p/interface-compliance-tests/mocks' import { defaultLogger } from '@libp2p/logger' import { PeerSet } from '@libp2p/peer-collections'