diff --git a/package-lock.json b/package-lock.json index 081a702087..a7d53e23c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "workspaces": [ "packages/byte-utils", "packages/interfaces", + "packages/libp2p-utils", "packages/core", "packages/enr", "packages/dns-discovery", @@ -3210,6 +3211,10 @@ "resolved": "packages/interfaces", "link": true }, + "node_modules/@waku/libp2p-utils": { + "resolved": "packages/libp2p-utils", + "link": true + }, "node_modules/@waku/message-encryption": { "resolved": "packages/message-encryption", "link": true @@ -17457,6 +17462,32 @@ "node": ">=16" } }, + "packages/libp2p-utils": { + "name": "@waku/libp2p-utils", + "version": "0.0.2", + "license": "MIT OR Apache-2.0", + "devDependencies": { + "@rollup/plugin-commonjs": "^22.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.3.0", + "@typescript-eslint/eslint-plugin": "^5.8.1", + "@typescript-eslint/parser": "^5.8.1", + "cspell": "^5.14.0", + "eslint": "^8.6.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-functional": "^4.0.2", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-prettier": "^4.0.0", + "npm-run-all": "^4.1.5", + "prettier": "^2.1.1", + "rollup": "^2.75.0", + "typescript": "^4.6.3" + }, + "engines": { + "node": ">=16" + } + }, "packages/message-encryption": { "name": "@waku/message-encryption", "version": "0.0.4", @@ -20282,6 +20313,27 @@ "typescript": "^4.6.3" } }, + "@waku/libp2p-utils": { + "version": "file:packages/libp2p-utils", + "requires": { + "@rollup/plugin-commonjs": "^22.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.3.0", + "@typescript-eslint/eslint-plugin": "^5.8.1", + "@typescript-eslint/parser": "^5.8.1", + "cspell": "^5.14.0", + "eslint": "^8.6.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-functional": "^4.0.2", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-prettier": "^4.0.0", + "npm-run-all": "^4.1.5", + "prettier": "^2.1.1", + "rollup": "^2.75.0", + "typescript": "^4.6.3" + } + }, "@waku/message-encryption": { "version": "file:packages/message-encryption", "requires": { diff --git a/package.json b/package.json index 927b47c14b..8d7139e4e4 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "workspaces": [ "packages/byte-utils", "packages/interfaces", + "packages/libp2p-utils", "packages/core", "packages/enr", "packages/dns-discovery", diff --git a/packages/core/src/lib/multiaddr_to_peer_info.ts b/packages/core/src/lib/multiaddr_to_peer_info.ts deleted file mode 100644 index 65524c4439..0000000000 --- a/packages/core/src/lib/multiaddr_to_peer_info.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PeerInfo } from "@libp2p/interface-peer-info"; -import { peerIdFromString } from "@libp2p/peer-id"; -import { Multiaddr } from "@multiformats/multiaddr"; - -export function multiaddrsToPeerInfo(mas: Multiaddr[]): PeerInfo[] { - return mas - .map((ma) => { - const peerIdStr = ma.getPeerId(); - const protocols: string[] = []; - return { - id: peerIdStr ? peerIdFromString(peerIdStr) : null, - multiaddrs: [ma.decapsulateCode(421)], - protocols, - }; - }) - .filter((peerInfo): peerInfo is PeerInfo => peerInfo.id !== null); -} diff --git a/packages/core/src/lib/select_connection.ts b/packages/core/src/lib/select_connection.ts deleted file mode 100644 index 05977c7ab5..0000000000 --- a/packages/core/src/lib/select_connection.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Connection } from "@libp2p/interface-connection"; - -export function selectConnection( - connections: Connection[] -): Connection | undefined { - if (!connections.length) return; - if (connections.length === 1) return connections[0]; - - let latestConnection: Connection | undefined; - - connections.forEach((connection) => { - if (connection.stat.status === "OPEN") { - if (!latestConnection) { - latestConnection = connection; - } else if ( - connection.stat.timeline.open > latestConnection.stat.timeline.open - ) { - latestConnection = connection; - } - } - }); - - return latestConnection; -} diff --git a/packages/core/src/lib/waku_filter/index.ts b/packages/core/src/lib/waku_filter/index.ts index 6015dacd4b..ca62470b24 100644 --- a/packages/core/src/lib/waku_filter/index.ts +++ b/packages/core/src/lib/waku_filter/index.ts @@ -13,6 +13,12 @@ import type { Message, ProtocolOptions, } from "@waku/interfaces"; +import { + getPeersForProtocol, + selectConnection, + selectPeerForProtocol, + selectRandomPeer, +} from "@waku/libp2p-utils"; import debug from "debug"; import all from "it-all"; import * as lp from "it-length-prefixed"; @@ -21,12 +27,6 @@ import { pipe } from "it-pipe"; import { WakuMessage as WakuMessageProto } from "../../proto/message.js"; import { DefaultPubSubTopic } from "../constants.js"; import { groupByContentTopic } from "../group_by.js"; -import { selectConnection } from "../select_connection.js"; -import { - getPeersForProtocol, - selectPeerForProtocol, - selectRandomPeer, -} from "../select_peer.js"; import { toProtoMessage } from "../to_proto_message.js"; import { ContentFilter, FilterRPC } from "./filter_rpc.js"; diff --git a/packages/core/src/lib/waku_light_push/index.ts b/packages/core/src/lib/waku_light_push/index.ts index 2a4eb7db29..d94e4d29dd 100644 --- a/packages/core/src/lib/waku_light_push/index.ts +++ b/packages/core/src/lib/waku_light_push/index.ts @@ -9,6 +9,12 @@ import type { ProtocolOptions, SendResult, } from "@waku/interfaces"; +import { + getPeersForProtocol, + selectConnection, + selectPeerForProtocol, + selectRandomPeer, +} from "@waku/libp2p-utils"; import debug from "debug"; import all from "it-all"; import * as lp from "it-length-prefixed"; @@ -17,12 +23,6 @@ import { Uint8ArrayList } from "uint8arraylist"; import { PushResponse } from "../../proto/light_push.js"; import { DefaultPubSubTopic } from "../constants.js"; -import { selectConnection } from "../select_connection.js"; -import { - getPeersForProtocol, - selectPeerForProtocol, - selectRandomPeer, -} from "../select_peer.js"; import { PushRPC } from "./push_rpc.js"; diff --git a/packages/core/src/lib/waku_store/index.ts b/packages/core/src/lib/waku_store/index.ts index bb343de0f0..a1cbccbdb0 100644 --- a/packages/core/src/lib/waku_store/index.ts +++ b/packages/core/src/lib/waku_store/index.ts @@ -11,6 +11,11 @@ import { Index, Store, } from "@waku/interfaces"; +import { + getPeersForProtocol, + selectConnection, + selectPeerForProtocol, +} from "@waku/libp2p-utils"; import debug from "debug"; import all from "it-all"; import * as lp from "it-length-prefixed"; @@ -19,8 +24,6 @@ import { Uint8ArrayList } from "uint8arraylist"; import * as proto from "../../proto/store.js"; import { DefaultPubSubTopic } from "../constants.js"; -import { selectConnection } from "../select_connection.js"; -import { getPeersForProtocol, selectPeerForProtocol } from "../select_peer.js"; import { toProtoMessage } from "../to_proto_message.js"; import { HistoryRPC, PageDirection, Params } from "./history_rpc.js"; diff --git a/packages/libp2p-utils/.eslintrc.cjs b/packages/libp2p-utils/.eslintrc.cjs new file mode 100644 index 0000000000..324f1f526d --- /dev/null +++ b/packages/libp2p-utils/.eslintrc.cjs @@ -0,0 +1,6 @@ +module.exports = { + parserOptions: { + tsconfigRootDir: __dirname, + project: "./tsconfig.dev.json", + }, +}; diff --git a/packages/libp2p-utils/.prettierignore b/packages/libp2p-utils/.prettierignore new file mode 100644 index 0000000000..fecb37a393 --- /dev/null +++ b/packages/libp2p-utils/.prettierignore @@ -0,0 +1,4 @@ +build +bundle +dist +node_modules diff --git a/packages/libp2p-utils/package.json b/packages/libp2p-utils/package.json new file mode 100644 index 0000000000..5067cac29d --- /dev/null +++ b/packages/libp2p-utils/package.json @@ -0,0 +1,93 @@ +{ + "name": "@waku/libp2p-utils", + "version": "0.0.2", + "description": "Utilities to help with libp2p", + "types": "./dist/index.d.ts", + "module": "./dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "type": "module", + "author": "Waku Team", + "homepage": "https://github.com/waku-org/js-waku/tree/master/packages/libp2p-utils#readme", + "repository": { + "type": "git", + "url": "https://github.com/waku-org/js-waku.git" + }, + "bugs": { + "url": "https://github.com/waku-org/js-waku/issues" + }, + "license": "MIT OR Apache-2.0", + "keywords": [ + "waku", + "decentralized", + "secure", + "communication", + "web3", + "ethereum", + "dapps", + "privacy" + ], + "scripts": { + "build": "run-s build:**", + "build:esm": "tsc", + "build:bundle": "rollup --config rollup.config.js", + "fix": "run-s fix:*", + "fix:prettier": "prettier . --write", + "fix:lint": "eslint src --ext .ts --ext .cjs --fix", + "check": "run-s check:*", + "check:lint": "eslint src --ext .ts", + "check:prettier": "prettier . --list-different", + "check:spelling": "cspell \"{README.md,src/**/*.ts}\"", + "check:tsc": "tsc -p tsconfig.dev.json", + "prepublish": "npm run build", + "reset-hard": "git clean -dfx -e .idea && git reset --hard && npm i && npm run build" + }, + "engines": { + "node": ">=16" + }, + "dependencies": { + "@multiformats/multiaddr": "^11.0.6", + "@libp2p/interface-peer-info": "^1.0.1", + "@libp2p/peer-id": "^1.1.10", + "@libp2p/interface-connection": "^3.0.3", + "@libp2p/interface-peer-id": "^1.0.6", + "@libp2p/interface-peer-store": "^1.2.3" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^22.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.3.0", + "@typescript-eslint/eslint-plugin": "^5.8.1", + "@typescript-eslint/parser": "^5.8.1", + "cspell": "^5.14.0", + "eslint": "^8.6.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-functional": "^4.0.2", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-prettier": "^4.0.0", + "npm-run-all": "^4.1.5", + "prettier": "^2.1.1", + "rollup": "^2.75.0", + "typescript": "^4.6.3" + }, + "typedoc": { + "entryPoint": "./src/index.ts" + }, + "files": [ + "dist", + "bundle", + "src/*.ts", + "src/lib/**/*.ts", + "src/proto/**/*.ts", + "!**/*.spec.*", + "!**/*.json", + "CHANGELOG.md", + "LICENSE", + "README.md" + ] +} diff --git a/packages/libp2p-utils/rollup.config.js b/packages/libp2p-utils/rollup.config.js new file mode 100644 index 0000000000..d22d3d231e --- /dev/null +++ b/packages/libp2p-utils/rollup.config.js @@ -0,0 +1,21 @@ +import commonjs from "@rollup/plugin-commonjs"; +import json from "@rollup/plugin-json"; +import { nodeResolve } from "@rollup/plugin-node-resolve"; + +export default { + input: { + index: "dist/index.js", + }, + output: { + dir: "bundle", + format: "esm", + }, + plugins: [ + commonjs(), + json(), + nodeResolve({ + browser: true, + preferBuiltins: false, + }), + ], +}; diff --git a/packages/core/src/lib/select_peer.ts b/packages/libp2p-utils/src/index.ts similarity index 60% rename from packages/core/src/lib/select_peer.ts rename to packages/libp2p-utils/src/index.ts index 9c34fbce44..f760a16953 100644 --- a/packages/core/src/lib/select_peer.ts +++ b/packages/libp2p-utils/src/index.ts @@ -1,8 +1,12 @@ +import type { Connection } from "@libp2p/interface-connection"; import type { PeerId } from "@libp2p/interface-peer-id"; +import type { PeerInfo } from "@libp2p/interface-peer-info"; import type { Peer, PeerStore } from "@libp2p/interface-peer-store"; +import { peerIdFromString } from "@libp2p/peer-id"; +import type { Multiaddr } from "@multiformats/multiaddr"; import debug from "debug"; -const log = debug("waku:select-peer"); +const log = debug("waku:libp2p-utils"); /** * Returns a pseudo-random peer that supports the given protocol. @@ -75,3 +79,40 @@ export async function selectPeerForProtocol( return { peer, protocol }; } + +export function multiaddrsToPeerInfo(mas: Multiaddr[]): PeerInfo[] { + return mas + .map((ma) => { + const peerIdStr = ma.getPeerId(); + const protocols: string[] = []; + return { + id: peerIdStr ? peerIdFromString(peerIdStr) : null, + multiaddrs: [ma.decapsulateCode(421)], + protocols, + }; + }) + .filter((peerInfo): peerInfo is PeerInfo => peerInfo.id !== null); +} + +export function selectConnection( + connections: Connection[] +): Connection | undefined { + if (!connections.length) return; + if (connections.length === 1) return connections[0]; + + let latestConnection: Connection | undefined; + + connections.forEach((connection) => { + if (connection.stat.status === "OPEN") { + if (!latestConnection) { + latestConnection = connection; + } else if ( + connection.stat.timeline.open > latestConnection.stat.timeline.open + ) { + latestConnection = connection; + } + } + }); + + return latestConnection; +} diff --git a/packages/libp2p-utils/tsconfig.dev.json b/packages/libp2p-utils/tsconfig.dev.json new file mode 100644 index 0000000000..4f7c34af3c --- /dev/null +++ b/packages/libp2p-utils/tsconfig.dev.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.dev" +} diff --git a/packages/libp2p-utils/tsconfig.json b/packages/libp2p-utils/tsconfig.json new file mode 100644 index 0000000000..eebbc51585 --- /dev/null +++ b/packages/libp2p-utils/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "dist/", + "rootDir": "src", + "tsBuildInfoFile": "dist/.tsbuildinfo" + }, + "include": ["src"], + "exclude": ["src/**/*.spec.ts", "src/test_utils"] +}