Compare commits
56 Commits
v0.0.1
...
v0.0.2-dev
Author | SHA1 | Date |
---|---|---|
semantic-release-bot | c2674c9df2 | |
Derrick Hammer | 04438ee02c | |
Derrick Hammer | 15df3a86d3 | |
Derrick Hammer | 659428c812 | |
Derrick Hammer | 774aab1a21 | |
Derrick Hammer | 499d2cfbf7 | |
Derrick Hammer | acca3680ac | |
Derrick Hammer | 2fd5b11582 | |
Derrick Hammer | 824881ed88 | |
Derrick Hammer | f69ff102cc | |
Derrick Hammer | 184eed8be8 | |
Derrick Hammer | 50271fad44 | |
Derrick Hammer | 1dedb7b240 | |
Derrick Hammer | 17bb912927 | |
Derrick Hammer | b6f1df264d | |
Derrick Hammer | 76d9b69935 | |
Derrick Hammer | ffc62dc5be | |
Derrick Hammer | 911c34076e | |
Derrick Hammer | df42526b21 | |
Derrick Hammer | a18deea021 | |
Derrick Hammer | 04bcc3f7eb | |
Derrick Hammer | cba2a126ae | |
Derrick Hammer | 6f5e0765d6 | |
Derrick Hammer | 6cc15997f8 | |
Derrick Hammer | 4dd54a4f8b | |
Derrick Hammer | 3ba792cd35 | |
Derrick Hammer | 3955ff2c29 | |
Derrick Hammer | bc10722539 | |
Derrick Hammer | fd2d66d2c4 | |
Derrick Hammer | cad93cbb21 | |
Derrick Hammer | b9b8040b50 | |
Derrick Hammer | fe6dac6e4a | |
Derrick Hammer | 9edc8269fa | |
Derrick Hammer | 053e988ea8 | |
Derrick Hammer | f0e6c5aa02 | |
Derrick Hammer | 74498c5691 | |
Derrick Hammer | 2ec2663ced | |
Derrick Hammer | 4855c993fd | |
Derrick Hammer | 8345026736 | |
Derrick Hammer | cd7f89b617 | |
Derrick Hammer | 9ebee0eefd | |
Derrick Hammer | c674e18229 | |
Derrick Hammer | c894082b9d | |
Derrick Hammer | bcf4b0d998 | |
Derrick Hammer | 7834ed5e6d | |
Derrick Hammer | e30f1797fb | |
Derrick Hammer | d7a17ca163 | |
Derrick Hammer | 5d0f30c49d | |
Derrick Hammer | 524372c49b | |
Derrick Hammer | afdeca0bca | |
Derrick Hammer | 564306bed2 | |
Derrick Hammer | b70c77eeda | |
Derrick Hammer | 6aca65b3e1 | |
Derrick Hammer | d778255b2a | |
Derrick Hammer | 3ca8fd9711 | |
Derrick Hammer | 909e8be59e |
|
@ -0,0 +1,13 @@
|
|||
name: Build/Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- develop-*
|
||||
|
||||
jobs:
|
||||
main:
|
||||
uses: lumeweb/github-node-deploy-workflow/.github/workflows/main.yml@master
|
||||
secrets: inherit
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"preset": [
|
||||
"@lumeweb/presetter-kernel-module-preset"
|
||||
],
|
||||
"config": {
|
||||
"official": true,
|
||||
"browser": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
## [0.0.2-develop.1](https://git.lumeweb.com/LumeWeb/kernel-ipfs/compare/v0.0.1...v0.0.2-develop.1) (2023-07-06)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "@lumeweb/kernel-ipfs",
|
||||
"version": "0.0.2-develop.1",
|
||||
"type": "module",
|
||||
"readme": "ERROR: No README data found!",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "gitea@git.lumeweb.com:LumeWeb/kernel-ipfs.git"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "presetter bootstrap",
|
||||
"build": "shx echo 'export default undefined;' > nop.js; run build",
|
||||
"semantic-release": "semantic-release",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chainsafe/libp2p-yamux": "^4.0.2",
|
||||
"@helia/interface": "^1.2.1",
|
||||
"@helia/ipns": "^1.1.3",
|
||||
"@helia/unixfs": "^1.4.0",
|
||||
"@libp2p/bootstrap": "^8.0.0",
|
||||
"@libp2p/delegated-content-routing": "^4.0.6",
|
||||
"@libp2p/delegated-peer-routing": "^4.0.9",
|
||||
"@libp2p/peer-id": "^2.0.4",
|
||||
"@lumeweb/kernel-swarm-client": "^0.0.2-develop.6",
|
||||
"@lumeweb/libhyperproxy": "^0.0.2-develop.1",
|
||||
"@lumeweb/libkernel": "0.1.0-develop.14",
|
||||
"@lumeweb/presetter-kernel-module-preset": "^0.1.0-develop.30",
|
||||
"blockstore-idb": "^1.1.1",
|
||||
"datastore-idb": "^2.1.2",
|
||||
"helia": "^1.3.5",
|
||||
"ipfs-core": "^0.18.1",
|
||||
"ipfs-http-client": "^60.0.1",
|
||||
"libp2p": "^0.42.2",
|
||||
"multiformats": "^12.0.1",
|
||||
"p-defer": "^4.0.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"runes2": "^1.1.2",
|
||||
"timers-browserify": "^2.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-alias": "^5.0.0",
|
||||
"os-browserify": "^0.3.0",
|
||||
"patch-package": "^7.0.0",
|
||||
"rollup-plugin-ignore-import": "^1.3.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
diff --git a/node_modules/@libp2p/tcp/dist/src/index.js b/node_modules/@libp2p/tcp/dist/src/index.js
|
||||
index fe47701..d239a6a 100644
|
||||
--- a/node_modules/@libp2p/tcp/dist/src/index.js
|
||||
+++ b/node_modules/@libp2p/tcp/dist/src/index.js
|
||||
@@ -8,7 +8,7 @@ import { TCPListener } from './listener.js';
|
||||
import { toMultiaddrConnection } from './socket-to-conn.js';
|
||||
import { multiaddrToNetConfig } from './utils.js';
|
||||
const log = logger('libp2p:tcp');
|
||||
-class TCP {
|
||||
+export class TCP {
|
||||
opts;
|
||||
metrics;
|
||||
components;
|
||||
diff --git a/node_modules/@libp2p/tcp/package.json b/node_modules/@libp2p/tcp/package.json
|
||||
index e4524a9..74fa657 100644
|
||||
--- a/node_modules/@libp2p/tcp/package.json
|
||||
+++ b/node_modules/@libp2p/tcp/package.json
|
||||
@@ -32,12 +32,20 @@
|
||||
"!dist/test",
|
||||
"!**/*.tsbuildinfo"
|
||||
],
|
||||
- "exports": {
|
||||
- ".": {
|
||||
- "types": "./dist/src/index.d.ts",
|
||||
- "import": "./dist/src/index.js"
|
||||
- }
|
||||
- },
|
||||
+ "exports": {
|
||||
+ ".": {
|
||||
+ "types": "./dist/src/index.d.ts",
|
||||
+ "import": "./dist/src/index.js"
|
||||
+ },
|
||||
+ "./socket-to-conn": {
|
||||
+ "types": "./dist/src/socket-to-conn.d.ts",
|
||||
+ "import": "./dist/src/socket-to-conn.js"
|
||||
+ },
|
||||
+ "./utils": {
|
||||
+ "types": "./dist/src/utils.d.ts",
|
||||
+ "import": "./dist/src/utils.js"
|
||||
+ }
|
||||
+ },
|
||||
"eslintConfig": {
|
||||
"extends": "ipfs",
|
||||
"parserOptions": {
|
|
@ -0,0 +1,76 @@
|
|||
// @ts-nocheck
|
||||
import * as import0 from "@rollup/plugin-json";
|
||||
import * as import1 from "@rollup/plugin-node-resolve";
|
||||
import * as import2 from "@rollup/plugin-commonjs";
|
||||
import * as import3 from "@rollup/plugin-graphql";
|
||||
import * as import4 from "@rollup/plugin-image";
|
||||
import * as import5 from "@rollup/plugin-yaml";
|
||||
import * as import6 from "rollup-plugin-postcss";
|
||||
import * as import7 from "rollup-plugin-visualizer";
|
||||
import * as import8 from "@rollup/plugin-wasm";
|
||||
import * as import9 from "@rollup/plugin-alias";
|
||||
import * as import10 from "rollup-plugin-ignore-import";
|
||||
export default {
|
||||
input: "build/index.js",
|
||||
output: [
|
||||
{
|
||||
file: "lib/index.js",
|
||||
format: "cjs",
|
||||
sourcemap: true,
|
||||
inlineDynamicImports: true,
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
import0.default(...([] as const)),
|
||||
import10.default({
|
||||
include: [
|
||||
"**/multiSocket/tcpSocket.js",
|
||||
"**/node-fetch/**",
|
||||
"**/@libp2p/tcp/dist/src/listener.js",
|
||||
],
|
||||
exclude: [],
|
||||
}),
|
||||
import10.default({
|
||||
include: ["**/@achingbrain/nat-port-mapper/**"],
|
||||
exclude: [],
|
||||
body: "export default {}; export const upnpNat = {};",
|
||||
}),
|
||||
import10.default({
|
||||
include: ["**/@libp2p/tcp/dist/src/listener.js"],
|
||||
exclude: [],
|
||||
body: "export default {}; export const TCPListener = {};",
|
||||
}),
|
||||
import9.default({
|
||||
entries: {
|
||||
"node-fetch": "./nop.js",
|
||||
"stream": "./nop.js",
|
||||
"path": "path-browserify",
|
||||
"timers": "timers-browserify",
|
||||
"os": "os-browserify",
|
||||
"net": "./nop.js",
|
||||
},
|
||||
}),
|
||||
import1.default(
|
||||
...([
|
||||
{
|
||||
browser: true,
|
||||
preferBuiltins: false,
|
||||
dedupe: [
|
||||
"@lumeweb/libkernel",
|
||||
"@lumeweb/libweb",
|
||||
"@lumeweb/libportal",
|
||||
],
|
||||
},
|
||||
] as const),
|
||||
),
|
||||
import2.default(
|
||||
...([{ extensions: [".js", ".jsx", ".ts", ".tsx"] }] as const),
|
||||
),
|
||||
import3.default(...([] as const)),
|
||||
import4.default(...([] as const)),
|
||||
import5.default(...([] as const)),
|
||||
import6.default(...([{ inject: { insertAt: "top" } }] as const)),
|
||||
import7.visualizer(...([] as const)),
|
||||
import8.default(...([{ targetEnv: "auto-inline" }] as const)),
|
||||
],
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
export const PROTOCOL = "lumeweb.proxy.ipfs";
|
||||
|
||||
export const DELEGATE_LIST = [
|
||||
"/dns4/node0.delegate.ipfs.io/tcp/443/https",
|
||||
"/dns4/node1.delegate.ipfs.io/tcp/443/https",
|
||||
"/dns4/node2.delegate.ipfs.io/tcp/443/https",
|
||||
"/dns4/node3.delegate.ipfs.io/tcp/443/https",
|
||||
];
|
|
@ -0,0 +1,404 @@
|
|||
import { createLibp2p, Libp2p } from "libp2p";
|
||||
import { createHelia } from "helia";
|
||||
import { yamux } from "@chainsafe/libp2p-yamux";
|
||||
// @ts-ignore
|
||||
import Hyperswarm from "hyperswarm";
|
||||
import { MultiSocketProxy } from "@lumeweb/libhyperproxy";
|
||||
import { mplex } from "@libp2p/mplex";
|
||||
import { hypercoreTransport } from "./libp2p/transport.js";
|
||||
import { UnixFS, unixfs } from "@helia/unixfs";
|
||||
|
||||
import { delegatedPeerRouting } from "@libp2p/delegated-peer-routing";
|
||||
import { noise } from "@chainsafe/libp2p-noise";
|
||||
import { create as createIpfsHttpClient } from "ipfs-http-client";
|
||||
import { delegatedContentRouting } from "@libp2p/delegated-content-routing";
|
||||
|
||||
import type { Options } from "ipfs-core";
|
||||
import { multiaddr } from "@multiformats/multiaddr";
|
||||
import { DELEGATE_LIST, PROTOCOL } from "./constants.js";
|
||||
import {
|
||||
ActiveQuery,
|
||||
addHandler,
|
||||
handleMessage,
|
||||
} from "@lumeweb/libkernel/module";
|
||||
import { createClient } from "@lumeweb/kernel-swarm-client";
|
||||
import { ipns, IPNS, ipnsSelector, ipnsValidator } from "@helia/ipns";
|
||||
import { dht, pubsub } from "@helia/ipns/routing";
|
||||
import { kadDHT } from "@libp2p/kad-dht";
|
||||
// @ts-ignore
|
||||
import { gossipsub } from "@chainsafe/libp2p-gossipsub";
|
||||
import { CID } from "multiformats/cid";
|
||||
import { bases } from "multiformats/basics";
|
||||
import { substr } from "runes2";
|
||||
import { MultibaseDecoder } from "multiformats";
|
||||
import { peerIdFromCID } from "@libp2p/peer-id";
|
||||
import { bootstrap } from "@libp2p/bootstrap";
|
||||
import { IDBBlockstore } from "blockstore-idb";
|
||||
import { IDBDatastore } from "datastore-idb";
|
||||
import defer from "p-defer";
|
||||
import { Helia } from "@helia/interface";
|
||||
// @ts-ignore
|
||||
import type { Components } from "libp2p/src/components.js";
|
||||
|
||||
const basesByPrefix: { [prefix: string]: MultibaseDecoder<any> } = Object.keys(
|
||||
bases,
|
||||
).reduce((acc, curr) => {
|
||||
// @ts-ignore
|
||||
acc[bases[curr].prefix] = bases[curr];
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
onmessage = handleMessage;
|
||||
|
||||
const moduleDefer = defer();
|
||||
let activeIpfsPeersDefer = defer();
|
||||
let networkPeersAvailable = defer();
|
||||
|
||||
let swarm;
|
||||
let proxy: MultiSocketProxy;
|
||||
let fs: UnixFS;
|
||||
let IPNS: IPNS;
|
||||
let ipfs: Helia;
|
||||
|
||||
// @ts-ignore
|
||||
BigInt.prototype.toJSON = function () {
|
||||
return this.toString();
|
||||
};
|
||||
|
||||
addHandler("presentKey", handlePresentKey);
|
||||
addHandler("ready", handleReady);
|
||||
addHandler("stat", handleStat);
|
||||
addHandler("ls", handleLs, { receiveUpdates: true });
|
||||
addHandler("cat", handleCat, { receiveUpdates: true });
|
||||
addHandler("ipnsResolve", handleIpnsResolve);
|
||||
addHandler("getActivePeers", handleGetActivePeers);
|
||||
|
||||
async function handlePresentKey() {
|
||||
swarm = createClient();
|
||||
|
||||
const client = createIpfsHttpClient(getDelegateConfig());
|
||||
|
||||
proxy = new MultiSocketProxy({
|
||||
swarm,
|
||||
listen: true,
|
||||
protocol: PROTOCOL,
|
||||
autostart: true,
|
||||
emulateWebsocket: true,
|
||||
server: false,
|
||||
});
|
||||
|
||||
const libp2p = await createLibp2p({
|
||||
peerDiscovery: [
|
||||
bootstrap({
|
||||
list: [
|
||||
// Default Bootstrap
|
||||
"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
||||
"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
|
||||
"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
|
||||
"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
|
||||
"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
|
||||
// Cloudflare
|
||||
"/dnsaddr/node-1.ingress.cloudflare-ipfs.com/p2p/QmcFf2FH3CEgTNHeMRGhN7HNHU1EXAxoEk6EFuSyXCsvRE",
|
||||
"/dnsaddr/node-2.ingress.cloudflare-ipfs.com/p2p/QmcFmLd5ySfk2WZuJ1mfSWLDjdmHZq7rSAua4GoeSQfs1z",
|
||||
"/dnsaddr/node-3.ingress.cloudflare-ipfs.com/p2p/QmcfFmzSDVbwexQ9Au2pt5YEXHK5xajwgaU6PpkbLWerMa",
|
||||
"/dnsaddr/node-4.ingress.cloudflare-ipfs.com/p2p/QmcfJeB3Js1FG7T8YaZATEiaHqNKVdQfybYYkbT1knUswx",
|
||||
"/dnsaddr/node-5.ingress.cloudflare-ipfs.com/p2p/QmcfVvzK4tMdFmpJjEKDUoqRgP4W9FnmJoziYX5GXJJ8eZ",
|
||||
"/dnsaddr/node-6.ingress.cloudflare-ipfs.com/p2p/QmcfZD3VKrUxyP9BbyUnZDpbqDnT7cQ4WjPP8TRLXaoE7G",
|
||||
"/dnsaddr/node-7.ingress.cloudflare-ipfs.com/p2p/QmcfZP2LuW4jxviTeG8fi28qjnZScACb8PEgHAc17ZEri3",
|
||||
"/dnsaddr/node-8.ingress.cloudflare-ipfs.com/p2p/QmcfgsJsMtx6qJb74akCw1M24X1zFwgGo11h1cuhwQjtJP",
|
||||
"/dnsaddr/node-9.ingress.cloudflare-ipfs.com/p2p/Qmcfr2FC7pFzJbTSDfYaSy1J8Uuy8ccGLeLyqJCKJvTHMi",
|
||||
"/dnsaddr/node-10.ingress.cloudflare-ipfs.com/p2p/QmcfR3V5YAtHBzxVACWCzXTt26SyEkxdwhGJ6875A8BuWx",
|
||||
"/dnsaddr/node-11.ingress.cloudflare-ipfs.com/p2p/Qmcfuo1TM9uUiJp6dTbm915Rf1aTqm3a3dnmCdDQLHgvL5",
|
||||
"/dnsaddr/node-12.ingress.cloudflare-ipfs.com/p2p/QmcfV2sg9zaq7UUHVCGuSvT2M2rnLBAPsiE79vVyK3Cuev",
|
||||
// Estuary
|
||||
"/ip4/139.178.68.217/tcp/6744/p2p/12D3KooWCVXs8P7iq6ao4XhfAmKWrEeuKFWCJgqe9jGDMTqHYBjw",
|
||||
"/ip4/147.75.49.71/tcp/6745/p2p/12D3KooWGBWx9gyUFTVQcKMTenQMSyE2ad9m7c9fpjS4NMjoDien",
|
||||
"/ip4/147.75.86.255/tcp/6745/p2p/12D3KooWFrnuj5o3tx4fGD2ZVJRyDqTdzGnU3XYXmBbWbc8Hs8Nd",
|
||||
"/ip4/3.134.223.177/tcp/6745/p2p/12D3KooWN8vAoGd6eurUSidcpLYguQiGZwt4eVgDvbgaS7kiGTup",
|
||||
"/ip4/35.74.45.12/udp/6746/quic/p2p/12D3KooWLV128pddyvoG6NBvoZw7sSrgpMTPtjnpu3mSmENqhtL7",
|
||||
|
||||
// Pinata
|
||||
"/dnsaddr/fra1-1.hostnodes.pinata.cloud/p2p/QmWaik1eJcGHq1ybTWe7sezRfqKNcDRNkeBaLnGwQJz1Cj",
|
||||
"/dnsaddr/fra1-2.hostnodes.pinata.cloud/p2p/QmNfpLrQQZr5Ns9FAJKpyzgnDL2GgC6xBug1yUZozKFgu4",
|
||||
"/dnsaddr/fra1-3.hostnodes.pinata.cloud/p2p/QmPo1ygpngghu5it8u4Mr3ym6SEU2Wp2wA66Z91Y1S1g29",
|
||||
"/dnsaddr/nyc1-1.hostnodes.pinata.cloud/p2p/QmRjLSisUCHVpFa5ELVvX3qVPfdxajxWJEHs9kN3EcxAW6",
|
||||
"/dnsaddr/nyc1-2.hostnodes.pinata.cloud/p2p/QmPySsdmbczdZYBpbi2oq2WMJ8ErbfxtkG8Mo192UHkfGP",
|
||||
"/dnsaddr/nyc1-3.hostnodes.pinata.cloud/p2p/QmSarArpxemsPESa6FNkmuu9iSE1QWqPX2R3Aw6f5jq4D5",
|
||||
// Eternum
|
||||
"/dns4/door.eternum.io/tcp/4001/ipfs/QmVBxJ5GekATHi89H8jbXjaU6CosCnteomjNR5xar2aH3q",
|
||||
// Textile
|
||||
"/ip4/104.210.43.77/p2p/QmR69wtWUMm1TWnmuD4JqC1TWLZcc8iR2KrTenfZZbiztd",
|
||||
// 8api.sh
|
||||
"/ip4/78.46.108.24/p2p/12D3KooWGASC2jm3pmohEJXUhuStkxDitPgzvs4qMuFPaiD9x1BA",
|
||||
"/ip4/65.109.19.136/p2p/12D3KooWRbWZN3GvLf9CHmozq4vnTzDD4EEoiqtRJxg5FV6Gfjmm",
|
||||
|
||||
// Storj
|
||||
"/ip4/5.161.92.43/tcp/4001/p2p/12D3KooWFFhc8fPYnQXdWBCowxSV21EFYin3rU27p3NVgSMjN41k",
|
||||
"/ip4/5.161.92.43/udp/4001/quic/p2p/12D3KooWFFhc8fPYnQXdWBCowxSV21EFYin3rU27p3NVgSMjN41k",
|
||||
"/ip6/2a01:4ff:f0:3b1e::1/tcp/4001/p2p/12D3KooWFFhc8fPYnQXdWBCowxSV21EFYin3rU27p3NVgSMjN41k",
|
||||
"/ip6/2a01:4ff:f0:3b1e::1/udp/4001/quic/p2p/12D3KooWFFhc8fPYnQXdWBCowxSV21EFYin3rU27p3NVgSMjN41k",
|
||||
"/ip4/5.161.55.227/tcp/4001/p2p/12D3KooWSW4hoHmDXmY5rW7nCi9XmGTy3foFt72u86jNP53LTNBJ",
|
||||
"/ip4/5.161.55.227/udp/4001/quic/p2p/12D3KooWSW4hoHmDXmY5rW7nCi9XmGTy3foFt72u86jNP53LTNBJ",
|
||||
"/ip6/2a01:4ff:f0:1e5a::1/tcp/4001/p2p/12D3KooWSW4hoHmDXmY5rW7nCi9XmGTy3foFt72u86jNP53LTNBJ",
|
||||
"/ip6/2a01:4ff:f0:1e5a::1/udp/4001/quic/p2p/12D3KooWSW4hoHmDXmY5rW7nCi9XmGTy3foFt72u86jNP53LTNBJ",
|
||||
"/ip4/5.161.92.36/tcp/4001/p2p/12D3KooWSDj6JM2JmoHwE9AUUwqAFUEg9ndd3pMA8aF2bkYckZfo",
|
||||
"/ip4/5.161.92.36/udp/4001/quic/p2p/12D3KooWSDj6JM2JmoHwE9AUUwqAFUEg9ndd3pMA8aF2bkYckZfo",
|
||||
"/ip6/2a01:4ff:f0:3764::1/tcp/4001/p2p/12D3KooWSDj6JM2JmoHwE9AUUwqAFUEg9ndd3pMA8aF2bkYckZfo",
|
||||
"/ip6/2a01:4ff:f0:3764::1/udp/4001/quic/p2p/12D3KooWSDj6JM2JmoHwE9AUUwqAFUEg9ndd3pMA8aF2bkYckZfo",
|
||||
],
|
||||
}) as Components,
|
||||
],
|
||||
transports: [hypercoreTransport({ proxy })],
|
||||
connectionEncryption: [noise() as Components],
|
||||
connectionManager: {
|
||||
autoDial: true,
|
||||
minConnections: 5,
|
||||
maxConnections: 20,
|
||||
},
|
||||
streamMuxers: [yamux(), mplex()],
|
||||
start: false,
|
||||
contentRouters: [delegatedContentRouting(client)],
|
||||
peerRouters: [delegatedPeerRouting(client)],
|
||||
relay: {
|
||||
enabled: true,
|
||||
advertise: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
dht: kadDHT({
|
||||
validators: {
|
||||
ipns: ipnsValidator,
|
||||
},
|
||||
selectors: {
|
||||
ipns: ipnsSelector,
|
||||
},
|
||||
}),
|
||||
pubsub: gossipsub(),
|
||||
});
|
||||
|
||||
const blockstore = new IDBBlockstore("ipfs_blocks");
|
||||
const datastore = new IDBDatastore("ipfs_data");
|
||||
|
||||
await blockstore.open();
|
||||
await datastore.open();
|
||||
|
||||
ipfs = await createHelia({
|
||||
blockstore,
|
||||
datastore,
|
||||
// @ts-ignore
|
||||
libp2p,
|
||||
});
|
||||
|
||||
proxy.on("peerChannelOpen", async () => {
|
||||
if (!ipfs.libp2p.isStarted()) {
|
||||
await ipfs.libp2p.start();
|
||||
networkPeersAvailable.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
swarm.join(PROTOCOL);
|
||||
await swarm.start();
|
||||
await swarm.ready();
|
||||
// @ts-ignore
|
||||
fs = unixfs(ipfs);
|
||||
IPNS = ipns(ipfs as any, [dht(ipfs), pubsub(ipfs as any)]);
|
||||
|
||||
ipfs.libp2p.addEventListener("peer:connect", () => {
|
||||
if (ipfs.libp2p.getPeers().length > 0) {
|
||||
activeIpfsPeersDefer.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
ipfs.libp2p.addEventListener("peer:disconnect", () => {
|
||||
if (ipfs.libp2p.getPeers().length === 0) {
|
||||
activeIpfsPeersDefer = defer();
|
||||
}
|
||||
});
|
||||
|
||||
moduleDefer.resolve();
|
||||
}
|
||||
|
||||
async function handleReady(aq: ActiveQuery) {
|
||||
await ready();
|
||||
|
||||
aq.respond();
|
||||
}
|
||||
|
||||
async function handleStat(aq: ActiveQuery) {
|
||||
await ready();
|
||||
|
||||
if (!("cid" in aq.callerInput)) {
|
||||
aq.reject("cid required");
|
||||
return;
|
||||
}
|
||||
|
||||
let aborted = false;
|
||||
|
||||
aq.setReceiveUpdate?.(() => {
|
||||
aborted = true;
|
||||
});
|
||||
|
||||
try {
|
||||
aq.respond(
|
||||
JSON.parse(
|
||||
JSON.stringify(
|
||||
await fs.stat(
|
||||
getCID(aq.callerInput.cid),
|
||||
aq.callerInput.options ?? {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
aq.reject((e as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLs(aq: ActiveQuery) {
|
||||
await ready();
|
||||
if (!("cid" in aq.callerInput)) {
|
||||
aq.reject("cid required");
|
||||
return;
|
||||
}
|
||||
|
||||
let aborted = false;
|
||||
let nextChunk = defer();
|
||||
|
||||
aq.setReceiveUpdate?.((data: any) => {
|
||||
switch (data) {
|
||||
case "abort":
|
||||
aborted = true;
|
||||
break;
|
||||
case "next":
|
||||
nextChunk.resolve();
|
||||
nextChunk = defer();
|
||||
break;
|
||||
}
|
||||
});
|
||||
const iterable = fs.ls(
|
||||
getCID(aq.callerInput.cid),
|
||||
aq.callerInput.options ?? {},
|
||||
);
|
||||
|
||||
for await (const item of iterable) {
|
||||
if (aborted) {
|
||||
break;
|
||||
}
|
||||
aq.sendUpdate(JSON.parse(JSON.stringify(item)));
|
||||
|
||||
await nextChunk.promise;
|
||||
}
|
||||
|
||||
aq.respond();
|
||||
}
|
||||
|
||||
async function handleCat(aq: ActiveQuery) {
|
||||
await ready();
|
||||
|
||||
if (!("cid" in aq.callerInput)) {
|
||||
aq.reject("cid required");
|
||||
return;
|
||||
}
|
||||
|
||||
let aborted = false;
|
||||
let nextChunk = defer();
|
||||
|
||||
aq.setReceiveUpdate?.((data: any) => {
|
||||
switch (data) {
|
||||
case "abort":
|
||||
aborted = true;
|
||||
break;
|
||||
case "next":
|
||||
nextChunk.resolve();
|
||||
nextChunk = defer();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
const iterable = fs.cat(
|
||||
getCID(aq.callerInput.cid),
|
||||
aq.callerInput.options ?? {},
|
||||
);
|
||||
|
||||
for await (const chunk of iterable) {
|
||||
if (aborted) {
|
||||
break;
|
||||
}
|
||||
|
||||
aq.sendUpdate(chunk);
|
||||
|
||||
await nextChunk.promise;
|
||||
}
|
||||
|
||||
aq.respond();
|
||||
}
|
||||
|
||||
async function handleIpnsResolve(aq: ActiveQuery) {
|
||||
await ready();
|
||||
|
||||
await activeIpfsPeersDefer.promise;
|
||||
|
||||
if (ipfs.libp2p.getPeers().length === 0) {
|
||||
activeIpfsPeersDefer = defer();
|
||||
}
|
||||
|
||||
await activeIpfsPeersDefer.promise;
|
||||
|
||||
if (!aq.callerInput || !("cid" in aq.callerInput)) {
|
||||
aq.reject("cid required");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
return aq.respond(
|
||||
(
|
||||
await IPNS.resolve(
|
||||
peerIdFromCID(getCID(aq.callerInput.cid)),
|
||||
aq.callerInput?.options,
|
||||
)
|
||||
).asCID.toString(),
|
||||
);
|
||||
} catch (e: any) {
|
||||
aq.reject((e as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
function getCID(cid: string): CID {
|
||||
try {
|
||||
return CID.parse(cid);
|
||||
} catch {}
|
||||
|
||||
const prefix = substr(cid, 0, 1);
|
||||
|
||||
if (!(prefix in basesByPrefix)) {
|
||||
throw new Error("invalid multibase found in CID");
|
||||
}
|
||||
|
||||
const base = basesByPrefix[prefix];
|
||||
return CID.parse(cid, base);
|
||||
}
|
||||
|
||||
async function handleGetActivePeers(aq: ActiveQuery) {
|
||||
await ready();
|
||||
|
||||
aq.respond(ipfs.libp2p.getPeers());
|
||||
}
|
||||
|
||||
async function ready() {
|
||||
await moduleDefer.promise;
|
||||
await networkPeersAvailable.promise;
|
||||
}
|
||||
|
||||
function getDelegateConfig(): Options {
|
||||
const delegateString =
|
||||
DELEGATE_LIST[Math.floor(Math.random() * DELEGATE_LIST.length)];
|
||||
const delegateAddr = multiaddr(delegateString).toOptions();
|
||||
|
||||
return {
|
||||
// @ts-ignore
|
||||
host: delegateAddr.host,
|
||||
// @ts-ignore
|
||||
protocol: parseInt(delegateAddr.port) === 443 ? "https" : "http",
|
||||
port: delegateAddr.port,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
import { symbol } from "@libp2p/interface-transport";
|
||||
// @ts-ignore
|
||||
import { TCP, TCPComponents, TCPDialOptions, TCPOptions } from "@libp2p/tcp";
|
||||
import { Multiaddr } from "@multiformats/multiaddr";
|
||||
import { IpcSocketConnectOpts, TcpSocketConnectOpts } from "net";
|
||||
import { logger } from "@libp2p/logger";
|
||||
import { AbortError, CodeError } from "@libp2p/interfaces/errors";
|
||||
// @ts-ignore
|
||||
import { multiaddrToNetConfig } from "@libp2p/tcp/utils";
|
||||
import { Connection } from "@libp2p/interface-connection";
|
||||
// @ts-ignore
|
||||
import { toMultiaddrConnection } from "@libp2p/tcp/socket-to-conn";
|
||||
import * as mafmt from "@multiformats/mafmt";
|
||||
|
||||
const log = logger("libp2p:hypercore");
|
||||
|
||||
import isPrivateIp from "private-ip";
|
||||
import { DummySocket, MultiSocketProxy, Socket } from "@lumeweb/libhyperproxy";
|
||||
|
||||
const CODE_P2P = 421;
|
||||
const CODE_CIRCUIT = 290;
|
||||
const CODE_UNIX = 400;
|
||||
|
||||
export interface HypercoreOptions extends TCPOptions {
|
||||
proxy?: MultiSocketProxy;
|
||||
}
|
||||
class HypercoreTransport extends TCP {
|
||||
private readonly opts?: HypercoreOptions;
|
||||
private metrics: any;
|
||||
constructor(components: TCPComponents, options: HypercoreOptions = {}) {
|
||||
super(components, options);
|
||||
this.opts = options;
|
||||
if (!options.proxy) {
|
||||
throw new Error("options.peerManager is required");
|
||||
}
|
||||
}
|
||||
|
||||
get [symbol](): true {
|
||||
return true;
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag](): string {
|
||||
return "@libp2p/hypercore";
|
||||
}
|
||||
|
||||
async dial(ma: Multiaddr, options: TCPDialOptions): Promise<Connection> {
|
||||
options.keepAlive = options.keepAlive ?? true;
|
||||
|
||||
// options.signal destroys the socket before 'connect' event
|
||||
const socket = await this._connect(ma, options);
|
||||
|
||||
// Avoid uncaught errors caused by unstable connections
|
||||
// @ts-ignore
|
||||
socket.on("error", (err: any) => {
|
||||
log("socket error", err);
|
||||
});
|
||||
|
||||
const maConn = toMultiaddrConnection(socket as any, {
|
||||
remoteAddr: ma,
|
||||
socketInactivityTimeout: this.opts?.outboundSocketInactivityTimeout,
|
||||
socketCloseTimeout: this.opts?.socketCloseTimeout,
|
||||
metrics: this.metrics?.dialerEvents,
|
||||
});
|
||||
|
||||
const onAbort = (): void => {
|
||||
maConn.close().catch((err: any) => {
|
||||
log.error("Error closing maConn after abort", err);
|
||||
});
|
||||
};
|
||||
options.signal?.addEventListener("abort", onAbort, { once: true });
|
||||
|
||||
log("new outbound connection %s", maConn.remoteAddr);
|
||||
const conn = await options.upgrader.upgradeOutbound(maConn);
|
||||
log("outbound connection %s upgraded", maConn.remoteAddr);
|
||||
|
||||
options.signal?.removeEventListener("abort", onAbort);
|
||||
|
||||
if (options.signal?.aborted === true) {
|
||||
conn.close().catch((err) => {
|
||||
log.error("Error closing conn after abort", err);
|
||||
});
|
||||
|
||||
throw new AbortError();
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
async _connect(ma: Multiaddr, options: TCPDialOptions): Promise<Socket> {
|
||||
if (options.signal?.aborted === true) {
|
||||
throw new AbortError();
|
||||
}
|
||||
|
||||
return await new Promise<Socket>(async (resolve, reject) => {
|
||||
const start = Date.now();
|
||||
const cOpts = multiaddrToNetConfig(ma) as IpcSocketConnectOpts &
|
||||
TcpSocketConnectOpts;
|
||||
const cOptsStr = cOpts.path ?? `${cOpts.host ?? ""}:${cOpts.port}`;
|
||||
|
||||
log("dialing %j", cOpts);
|
||||
|
||||
let rawSocket: Socket;
|
||||
|
||||
const onError = (err: Error): void => {
|
||||
err.message = `connection error ${cOptsStr}: ${err.message}`;
|
||||
this.metrics?.dialerEvents.increment({ error: true });
|
||||
|
||||
done(err);
|
||||
};
|
||||
|
||||
const onTimeout = (): void => {
|
||||
log("connection timeout %s", cOptsStr);
|
||||
this.metrics?.dialerEvents.increment({ timeout: true });
|
||||
|
||||
const err = new CodeError(
|
||||
`connection timeout after ${Date.now() - start}ms`,
|
||||
"ERR_CONNECT_TIMEOUT",
|
||||
);
|
||||
// Note: this will result in onError() being called
|
||||
// @ts-ignore
|
||||
rawSocket?.emit("error", err);
|
||||
};
|
||||
|
||||
const onConnect = (): void => {
|
||||
log("connection opened %j", cOpts);
|
||||
this.metrics?.dialerEvents.increment({ connect: true });
|
||||
done();
|
||||
};
|
||||
|
||||
const onAbort = (): void => {
|
||||
log("connection aborted %j", cOpts);
|
||||
this.metrics?.dialerEvents.increment({ abort: true });
|
||||
// @ts-ignore
|
||||
rawSocket?.destroy();
|
||||
done(new AbortError());
|
||||
};
|
||||
|
||||
const done = (err?: any): void => {
|
||||
// @ts-ignore
|
||||
rawSocket?.removeListener("error", onError);
|
||||
// @ts-ignore
|
||||
rawSocket?.removeListener("timeout", onTimeout);
|
||||
// @ts-ignore
|
||||
rawSocket?.removeListener("connect", onConnect);
|
||||
|
||||
if (options.signal != null) {
|
||||
options.signal.removeEventListener("abort", onAbort);
|
||||
}
|
||||
|
||||
if (err != null) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(rawSocket as Socket);
|
||||
};
|
||||
|
||||
try {
|
||||
rawSocket = (await this.opts?.proxy?.createSocket(cOpts)) as Socket;
|
||||
} catch (e: any) {
|
||||
onError(e);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
rawSocket = rawSocket as Socket;
|
||||
|
||||
// @ts-ignore
|
||||
rawSocket?.on("error", onError);
|
||||
// @ts-ignore
|
||||
rawSocket?.on("timeout", onTimeout);
|
||||
// @ts-ignore
|
||||
rawSocket?.on("connect", onConnect);
|
||||
|
||||
if (options.signal != null) {
|
||||
options.signal.addEventListener("abort", onAbort);
|
||||
}
|
||||
|
||||
(rawSocket as DummySocket)?.connect();
|
||||
});
|
||||
}
|
||||
|
||||
filter(multiaddrs: Multiaddr[]): Multiaddr[] {
|
||||
multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs];
|
||||
|
||||
return multiaddrs.filter((ma) => {
|
||||
if (ma.protoCodes().includes(CODE_CIRCUIT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ma.protoCodes().includes(CODE_UNIX)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const addr = ma.nodeAddress();
|
||||
|
||||
if (isPrivateIp(addr.address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mafmt.TCP.matches(ma.decapsulateCode(CODE_P2P));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function hypercoreTransport(
|
||||
init: HypercoreOptions = {},
|
||||
): (components?: TCPComponents) => HypercoreTransport {
|
||||
return (components: TCPComponents = {}) => {
|
||||
return new HypercoreTransport(components, init);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default {
|
||||
|
||||
}
|
Loading…
Reference in New Issue