Skip to content

Instantly share code, notes, and snippets.

@bellbind
Last active December 9, 2019 07:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bellbind/3b14fbe091365f0f1ab56931b157c2a8 to your computer and use it in GitHub Desktop.
Save bellbind/3b14fbe091365f0f1ab56931b157c2a8 to your computer and use it in GitHub Desktop.
[IPFS][libp2p][browser] Chat with libp2p peer in IPFS node
<!doctype html>
<html>
<head>
<title>Chat on libp2p</title>
<script type="module" src="./main.js"></script>
</head>
<body>
<h3 id="myid"></h3>
<div>
to: <input id="to" type="text" size="40"/>
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/dist/index.js";
//console.log(window.Ipfs);
// util1: pull-stream source from ES iterator
const iterableSource = iterable => {
const itor = iterable[Symbol.iterator]();
return (abort, cb) => {
if (abort) {
if (typeof itor.return === "function") itor.return(abort);
return cb(abort);
}
const {value, done} = itor.next();
return cb(done, value);
};
};
// util2: pull-stream sink that turns a pull-stream source as ES async itor
const asyncIterSink = source => ({
[Symbol.asyncIterator]: () => ({
next: () => new Promise(
f => source(false, (done, value) => f({done, value}))),
}),
});
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 = new Ipfs({
repo: `ipfs-${Math.random()}`,
relay: {enabled: true, hop: {enabled: true, active: 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());
}
const protocolId = "chat-example-proto";
node.libp2p.handle(protocolId, async (funcs, conn) => {
const pid = await promisify(conn.getPeerInfo.bind(conn))();
const id = pid.id.toB58String();
const msg = [];
for await (const buf of asyncIterSink(conn.source)) {
msg.push(new TextDecoder().decode(buf.buffer));
}
document.querySelector("#log").prepend(`${id}: ${"".concat(msg)}\n`);
});
document.querySelector("#send").addEventListener("click", ev => {
(async () => {
const id = document.querySelector("#to").value;
const msg = document.querySelector("#msg").value;
const p2pid = `/p2p-circuit/ipfs/${id}`;
const conn = await node.libp2p.dialProtocol(p2pid, protocolId);
conn.sink(iterableSource([new TextEncoder().encode(msg)]));
document.querySelector("#msg").value = "";
document.querySelector("#log").prepend(`${myid}: ${msg}\n`);
})().catch(console.error);
});
document.querySelector("#myid").textContent = myid;
};
main().catch(console.error);
@bellbind
Copy link
Author

bellbind commented Dec 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment