Last active
December 9, 2019 07:06
-
-
Save bellbind/3b14fbe091365f0f1ab56931b157c2a8 to your computer and use it in GitHub Desktop.
[IPFS][libp2p][browser] Chat with libp2p peer in IPFS node
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
demo: https://gateway.ipfs.io/ipfs/QmUqn3jroQhL1KpCbx62HY7afc8YyqMT45fmoqezfVtUCp/