2023-03-17 09:36:02 +00:00
|
|
|
import { createLibp2p } from "libp2p";
|
|
|
|
import { MemoryDatastore } from "datastore-core";
|
|
|
|
import { MemoryBlockstore } from "blockstore-core";
|
|
|
|
import { createHelia } from "helia";
|
|
|
|
import { yamux } from "@chainsafe/libp2p-yamux";
|
|
|
|
// @ts-ignore
|
|
|
|
import Hyperswarm from "hyperswarm";
|
|
|
|
import { Peer, Proxy } from "@lumeweb/libhyperproxy";
|
|
|
|
// @ts-ignore
|
|
|
|
import sodium from "sodium-universal";
|
|
|
|
// @ts-ignore
|
|
|
|
import { CustomEvent } from "@libp2p/interfaces/events";
|
|
|
|
// @ts-ignore
|
|
|
|
import { fixed32, raw } from "compact-encoding";
|
|
|
|
import { mplex } from "@libp2p/mplex";
|
|
|
|
import PeerManager from "./peerManager.js";
|
|
|
|
import { hypercoreTransport } from "./libp2p/transport.js";
|
|
|
|
import { UnixFS, unixfs } from "@helia/unixfs";
|
|
|
|
// @ts-ignore
|
|
|
|
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 "libkmodule";
|
|
|
|
import { createClient } from "@lumeweb/kernel-swarm-client";
|
2022-08-31 19:19:35 +00:00
|
|
|
|
|
|
|
onmessage = handleMessage;
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
let moduleLoadedResolve: Function;
|
|
|
|
let moduleLoaded: Promise<void> = new Promise((resolve) => {
|
|
|
|
moduleLoadedResolve = resolve;
|
|
|
|
});
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
let swarm;
|
|
|
|
let proxy: Proxy;
|
|
|
|
let fs: UnixFS;
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
// @ts-ignore
|
|
|
|
BigInt.prototype.toJSON = function () {
|
|
|
|
return this.toString();
|
|
|
|
};
|
2022-08-05 13:25:55 +00:00
|
|
|
|
|
|
|
addHandler("presentSeed", handlePresentSeed);
|
2023-03-17 09:36:02 +00:00
|
|
|
addHandler("stat", handleStat);
|
|
|
|
addHandler("ls", handleLs, { receiveUpdates: true });
|
|
|
|
addHandler("cat", handleCat, { receiveUpdates: true });
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2022-08-13 09:41:36 +00:00
|
|
|
async function handlePresentSeed() {
|
2023-03-17 09:36:02 +00:00
|
|
|
swarm = createClient();
|
|
|
|
|
|
|
|
const client = createIpfsHttpClient(getDelegateConfig());
|
|
|
|
|
|
|
|
PeerManager.instance.ipfs = await createHelia({
|
|
|
|
blockstore: new MemoryBlockstore(),
|
|
|
|
datastore: new MemoryDatastore(),
|
|
|
|
libp2p: await createLibp2p({
|
|
|
|
transports: [hypercoreTransport({ peerManager: PeerManager.instance })],
|
|
|
|
connectionEncryption: [noise()],
|
|
|
|
streamMuxers: [yamux(), mplex()],
|
|
|
|
start: false,
|
|
|
|
contentRouters: [delegatedContentRouting(client)],
|
|
|
|
peerRouters: [delegatedPeerRouting(client)],
|
|
|
|
relay: {
|
|
|
|
enabled: false,
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
});
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
proxy = new Proxy({
|
|
|
|
swarm,
|
|
|
|
listen: true,
|
|
|
|
protocol: PROTOCOL,
|
|
|
|
autostart: true,
|
|
|
|
emulateWebsocket: true,
|
|
|
|
createDefaultMessage: false,
|
|
|
|
onchannel(peer: Peer, channel: any) {
|
|
|
|
PeerManager.instance.handleNewPeerChannel(peer, channel);
|
|
|
|
},
|
|
|
|
onopen() {
|
|
|
|
PeerManager.instance.handleNewPeer();
|
|
|
|
},
|
|
|
|
onclose(peer: Peer) {
|
|
|
|
PeerManager.instance.handleClosePeer(peer);
|
|
|
|
},
|
|
|
|
});
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
swarm.join(PROTOCOL);
|
|
|
|
await swarm.start();
|
|
|
|
// @ts-ignore
|
|
|
|
fs = unixfs(PeerManager.instance.ipfs);
|
|
|
|
moduleLoadedResolve();
|
2022-08-05 13:25:55 +00:00
|
|
|
}
|
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
async function handleStat(aq: ActiveQuery) {
|
|
|
|
await moduleLoaded;
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
if (!("cid" in aq.callerInput)) {
|
|
|
|
aq.reject("cid required");
|
2022-08-05 13:25:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
let aborted = false;
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
aq.setReceiveUpdate?.(() => {
|
|
|
|
aborted = true;
|
|
|
|
});
|
2022-08-05 13:25:55 +00:00
|
|
|
|
|
|
|
try {
|
2023-03-17 09:36:02 +00:00
|
|
|
aq.respond(
|
|
|
|
JSON.parse(
|
|
|
|
JSON.stringify(
|
|
|
|
await fs.stat(aq.callerInput.cid, aq.callerInput.options ?? {})
|
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} catch (e) {
|
|
|
|
aq.reject((e as Error).message);
|
2022-08-05 13:25:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
async function handleLs(aq: ActiveQuery) {
|
|
|
|
await moduleLoaded;
|
|
|
|
if (!("cid" in aq.callerInput)) {
|
|
|
|
aq.reject("cid required");
|
2022-08-05 13:25:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
let aborted = false;
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
aq.setReceiveUpdate?.(() => {
|
|
|
|
aborted = true;
|
|
|
|
});
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
const iterable = fs.ls(aq.callerInput.cid, aq.callerInput.options ?? {});
|
|
|
|
|
|
|
|
for await (const item of iterable) {
|
|
|
|
if (aborted) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
aq.sendUpdate(JSON.parse(JSON.stringify(item)));
|
2022-08-05 13:25:55 +00:00
|
|
|
}
|
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
aq.respond();
|
2022-08-05 13:25:55 +00:00
|
|
|
}
|
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
async function handleCat(aq: ActiveQuery) {
|
|
|
|
await moduleLoaded;
|
2022-08-31 19:19:35 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
if (!("cid" in aq.callerInput)) {
|
|
|
|
aq.reject("cid required");
|
|
|
|
return;
|
2022-08-05 13:25:55 +00:00
|
|
|
}
|
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
let aborted = false;
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
aq.setReceiveUpdate?.(() => {
|
|
|
|
aborted = true;
|
2022-08-05 13:25:55 +00:00
|
|
|
});
|
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
const iterable = fs.cat(aq.callerInput.cid, aq.callerInput.options ?? {});
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
for await (const chunk of iterable) {
|
|
|
|
if (aborted) {
|
|
|
|
break;
|
|
|
|
}
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
aq.sendUpdate(chunk);
|
|
|
|
}
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
aq.respond();
|
2022-08-05 13:25:55 +00:00
|
|
|
}
|
2022-08-31 19:19:35 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
function getDelegateConfig(): Options {
|
|
|
|
const delegateString =
|
|
|
|
DELEGATE_LIST[Math.floor(Math.random() * DELEGATE_LIST.length)];
|
|
|
|
const delegateAddr = multiaddr(delegateString).toOptions();
|
2022-08-05 13:25:55 +00:00
|
|
|
|
2023-03-17 09:36:02 +00:00
|
|
|
return {
|
|
|
|
// @ts-ignore
|
|
|
|
host: delegateAddr.host,
|
|
|
|
// @ts-ignore
|
|
|
|
protocol: parseInt(delegateAddr.port) === 443 ? "https" : "http",
|
|
|
|
port: delegateAddr.port,
|
2022-08-05 13:25:55 +00:00
|
|
|
};
|
|
|
|
}
|