Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
[js-ipfs][browser] Pubsub chatroom with js-libp2p in js-ipfs node
<!doctype html>
<html>
<head>
<title>Pubsub on libp2p (js-ipfs-0.40)</title>
<script type="module" src="./main-40.js"></script>
</head>
<body>
<h3 id="myid"></h3>
<div>
id: <input id="id" type="text" size="40"/>
<button id="chain">chain</button>
</div>
<div>
message: <input id="msg" type="text" size="40"/>
<button id="send">send</button>
</div>
<hr/>
<pre id="log"></pre>
</body>
</html>
<!doctype html>
<html>
<head>
<title>Pubsub on libp2p</title>
<script type="module" src="./main.js"></script>
</head>
<body>
<h3 id="myid"></h3>
<div>
id: <input id="id" type="text" size="40"/>
<button id="chain">chain</button>
</div>
<div>
message: <input id="msg" type="text" size="40"/>
<button id="send">send</button>
</div>
<hr/>
<pre id="log"></pre>
</body>
</html>
// this bundle maybe non ES-module, but it can import to load as `window.Ipfs`
// (js-ipfs 0.39.0)
import "https://cdn.jsdelivr.net/npm/ipfs@0.40.0/dist/index.js";
//console.log(window.Ipfs);
const promisify = func => function (...args) {
return new Promise((f, e) => func.call(
this, ...args, (err, value) => err ? e(err) : f(value)));
};
const main = async () => {
const node = window.node = await Ipfs.create({
repo: `ipfs-${Math.random()}`,
relay: {enabled: true, hop: {enabled: true, active: true}},
//EXPERIMENTAL: {pubsub: true},
//config: {Pubsub: {Enabled: true}}, // required for pubsub with others
//libp2p: {config: {pubsub: {enabled: true},}},
});
await node.ready;
console.log("IPFS version:", (await node.version()).version);
console.log(`Peer ID:`, (await node.id()).id);
const myid = node.libp2p.peerInfo.id.toB58String();
console.log("libp2p ID:", myid);
for (const ma of node.libp2p.peerInfo.multiaddrs.toArray()) {
console.log("multiaddr:", ma.toString());
}
document.querySelector("#chain").addEventListener("click", ev => {
(async () => {
const id = document.querySelector("#id").value;
const p2pid = `/p2p-circuit/ipfs/${id}`;
//NOTE: For pubsub, directly chained pubsub-enabed peers each other
await node.swarm.connect(p2pid);
document.querySelector("#id").value = "";
document.querySelector("#log").prepend(`(Swarm connected: ${id})\n`);
})().catch(console.error);
});
const topicId = "pubsub-example-topic";
const handle = msg => {
//console.log(msg);
const text = new TextDecoder().decode(msg.data);
document.querySelector("#log").prepend(`${text}\n`);
};
await node.libp2p.pubsub.subscribe(topicId, handle);
console.log("subscribed");
document.querySelector("#send").addEventListener("click", ev => {
(async () => {
const msg = document.querySelector("#msg").value;
const text = `${myid}: ${msg}`;
await node.libp2p.pubsub.publish(
topicId, new TextEncoder().encode(text));
document.querySelector("#msg").value = "";
})().catch(console.error);
});
document.querySelector("#myid").textContent = myid;
};
main().catch(console.error);
// this bundle maybe non ES-module, but it can import to load as `window.Ipfs`
//import "https://cdn.jsdelivr.net/npm/ipfs@0.44.0/dist/index.min.js";
import "https://cdn.jsdelivr.net/npm/ipfs/dist/index.min.js";
//console.log(window.Ipfs);
const promisify = func => function (...args) {
return new Promise((f, e) => func.call(
this, ...args, (err, value) => err ? e(err) : f(value)));
};
const main = async () => {
const node = window.node = await Ipfs.create({
repo: `ipfs-${Math.random()}`,
relay: {enabled: true, hop: {enabled: true, active: true}},
//EXPERIMENTAL: {pubsub: true},
//config: {Pubsub: {Enabled: true}}, // required for pubsub with others
//libp2p: {config: {pubsub: {enabled: true},}},
});
await node.ready;
console.log("IPFS version:", (await node.version()).version);
console.log(`Peer ID:`, (await node.id()).id);
const myid = node.libp2p.peerInfo.id.toB58String();
console.log("libp2p ID:", myid);
// from js-ipfs-0.41.0, swarm.connect() to p2pid with explicit relay required
const connect = async (node, id) => {
// swarm connect with relay
const addrs = new Set((await node.swarm.addrs()).map(({id}) => id));
//console.log(addrs);
if (addrs.has(id)) return;
let relaid = false;
for (const relay of addrs) {
const relayid = `/p2p/${relay}/p2p-circuit/p2p/${id}`;
console.log("relayid", relayid);
try {
await node.swarm.connect(relayid);
relaid = true;
break;
} catch (error) {
//console.log(error);
}
}
if (!relaid) throw Error(`could not relay to ${id}`);
};
document.querySelector("#chain").addEventListener("click", ev => {
(async () => {
const id = document.querySelector("#id").value;
const p2pid = `/p2p-circuit/ipfs/${id}`;
//NOTE: For pubsub, directly chained pubsub-enabed peers each other
await connect(node, id);
document.querySelector("#id").value = "";
document.querySelector("#log").prepend(`(Swarm connected: ${id})\n`);
})().catch(console.error);
});
const topicId = "pubsub-example-topic";
const handle = msg => {
//console.log(msg);
const text = new TextDecoder().decode(msg.data);
document.querySelector("#log").prepend(`${text}\n`);
};
await node.libp2p.pubsub.subscribe(topicId, handle);
console.log("subscribed");
document.querySelector("#send").addEventListener("click", ev => {
(async () => {
const msg = document.querySelector("#msg").value;
const text = `${myid}: ${msg}`;
await node.libp2p.pubsub.publish(
topicId, new TextEncoder().encode(text));
document.querySelector("#msg").value = "";
})().catch(console.error);
});
document.querySelector("#myid").textContent = myid;
};
main().catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment