Libp2p.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. <template>
  2. <main>
  3. <!-- Page Section -->
  4. <section class="content">
  5. <div class="container-fluid">
  6. <div class="row">
  7. <div class="col-md-6">
  8. <!-- <Navbar /> -->
  9. <div class="card">
  10. <div class="card-body">
  11. <form role="form">
  12. <div class="card-body">
  13. <div class="form-group">
  14. <label for="exampleInputEmail1">Email address</label>
  15. <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
  16. </div>
  17. <div class="form-group">
  18. <label for="exampleInputPassword1">Password</label>
  19. <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
  20. </div>
  21. </div>
  22. <!-- /.card-body -->
  23. <div class="custom-control custom-checkbox">
  24. <input class="custom-control-input" type="checkbox" value="relay.apecs.dev" checked>
  25. <label for="customCheckbox1" class="custom-control-label">relay.apecs.dev</label>
  26. </div>
  27. <div class="custom-control custom-checkbox">
  28. <input class="custom-control-input" type="checkbox" value="wss.fullstack.cash">
  29. <label for="customCheckbox2" class="custom-control-label">wss.fullstack.cash</label>
  30. </div>
  31. <div class="row">
  32. <div class="col-12 col-sm-6">
  33. <div class="form-group">
  34. <label>Chat Room</label>
  35. <select multiple class="form-control">
  36. <option value="4cc225a23cdb830b6978b55e76f4b7966ec08c30a74d1d203fb57e23ebcdcccd">#lobby:apecs.dev</option>
  37. <option value="customPubsubRoom123">customPubsubRoom123</option>
  38. </select>
  39. </div>
  40. </div>
  41. <div class="col-12 col-sm-6">
  42. <div class="form-group">
  43. <label>Peers</label>
  44. <select multiple class="form-control">
  45. <option value="QmPTaa3Azg269K8UeKhTdj1cmkWPZ5hcLGHFp6r3sqCXnB">messenger.apecs.dev</option>
  46. <option value="QmaUW4oCVPUFLRqeSjvhHwGFJHGWrYWLBEt7WxnexDm3Xa">chat.fullstackcash.nl</option>
  47. <option value="QmZD1c7sNgFdF7DgG9kFFnjfMCJKpUzFkpeaj4wv7NfhWB">localhost browser (test only)</option>
  48. <option value="QmNvgo499ZUVKV61ZtU8jAYx5ZUEn6eJn4b1LAGtM6nftS">localhost node.js (test only)</option>
  49. <option value="QmQpV2FcL8swjYuarqBWGAvgBBp98JiTYymhSBvktUujK4">localhost incognito (test only)</option>
  50. <option value="">cashshuffle</option>
  51. <option value="">cashfusion</option>
  52. </select>
  53. </div>
  54. </div>
  55. </div>
  56. <div class="card-footer">
  57. <button type="submit" class="btn btn-primary" @click="sendTest">Submit</button>
  58. </div>
  59. </form>
  60. <div v-for="log of debugLog" :key="log.id">
  61. {{log.body}}
  62. </div>
  63. <div class="card">
  64. <div class="card-header">
  65. <h3 class="card-title">Fixed Header Table</h3>
  66. <div class="card-tools">
  67. <div class="input-group input-group-sm" style="width: 150px;">
  68. <input type="text" name="table_search" class="form-control float-right" placeholder="Search">
  69. <div class="input-group-append">
  70. <button type="submit" class="btn btn-default"><i class="fas fa-search"></i></button>
  71. </div>
  72. </div>
  73. </div>
  74. </div>
  75. <!-- /.card-header -->
  76. <div class="card-body table-responsive p-0" style="height: 300px;">
  77. <table class="table table-head-fixed text-nowrap">
  78. <thead>
  79. <tr>
  80. <th>ID</th>
  81. <th>User</th>
  82. <th>Date</th>
  83. <th>Status</th>
  84. <th>Reason</th>
  85. </tr>
  86. </thead>
  87. <tbody>
  88. <tr>
  89. <td>183</td>
  90. <td>John Doe</td>
  91. <td>11-7-2014</td>
  92. <td><span class="tag tag-success">Approved</span></td>
  93. <td>Bacon ipsum dolor sit amet salami venison chicken flank fatback doner.</td>
  94. </tr>
  95. <tr>
  96. <td>219</td>
  97. <td>Alexander Pierce</td>
  98. <td>11-7-2014</td>
  99. <td><span class="tag tag-warning">Pending</span></td>
  100. <td>Bacon ipsum dolor sit amet salami venison chicken flank fatback doner.</td>
  101. </tr>
  102. <tr>
  103. <td>657</td>
  104. <td>Bob Doe</td>
  105. <td>11-7-2014</td>
  106. <td><span class="tag tag-primary">Approved</span></td>
  107. <td>Bacon ipsum dolor sit amet salami venison chicken flank fatback doner.</td>
  108. </tr>
  109. <tr>
  110. <td>175</td>
  111. <td>Mike Doe</td>
  112. <td>11-7-2014</td>
  113. <td><span class="tag tag-danger">Denied</span></td>
  114. <td>Bacon ipsum dolor sit amet salami venison chicken flank fatback doner.</td>
  115. </tr>
  116. <tr>
  117. <td>134</td>
  118. <td>Jim Doe</td>
  119. <td>11-7-2014</td>
  120. <td><span class="tag tag-success">Approved</span></td>
  121. <td>Bacon ipsum dolor sit amet salami venison chicken flank fatback doner.</td>
  122. </tr>
  123. <tr>
  124. <td>494</td>
  125. <td>Victoria Doe</td>
  126. <td>11-7-2014</td>
  127. <td><span class="tag tag-warning">Pending</span></td>
  128. <td>Bacon ipsum dolor sit amet salami venison chicken flank fatback doner.</td>
  129. </tr>
  130. <tr>
  131. <td>832</td>
  132. <td>Michael Doe</td>
  133. <td>11-7-2014</td>
  134. <td><span class="tag tag-primary">Approved</span></td>
  135. <td>Bacon ipsum dolor sit amet salami venison chicken flank fatback doner.</td>
  136. </tr>
  137. <tr>
  138. <td>982</td>
  139. <td>Rocky Doe</td>
  140. <td>11-7-2014</td>
  141. <td><span class="tag tag-danger">Denied</span></td>
  142. <td>Bacon ipsum dolor sit amet salami venison chicken flank fatback doner.</td>
  143. </tr>
  144. </tbody>
  145. </table>
  146. </div>
  147. <!-- /.card-body -->
  148. </div>
  149. <!-- /.card -->
  150. </div>
  151. </div>
  152. </div>
  153. <div class="col-md-6">
  154. <div class="card">
  155. <div class="card-header">
  156. <h3 class="card-title">
  157. <i class="fas fa-info-circle mr-1"></i>
  158. Libp2p Guide
  159. </h3>
  160. </div>
  161. <div class="card-body">
  162. <dl class="row">
  163. <dt class="col-sm-4">Description lists</dt>
  164. <dd class="col-sm-8">A description list is perfect for defining terms.</dd>
  165. <dt class="col-sm-4">Euismod</dt>
  166. <dd class="col-sm-8">Vestibulum id ligula porta felis euismod semper eget lacinia odio sem nec elit.</dd>
  167. <dd class="col-sm-8 offset-sm-4">Donec id elit non mi porta gravida at eget metus.</dd>
  168. <dt class="col-sm-4">Malesuada porta</dt>
  169. <dd class="col-sm-8">Etiam porta sem malesuada magna mollis euismod.</dd>
  170. <dt class="col-sm-4">Felis euismod semper eget lacinia</dt>
  171. <dd class="col-sm-8">Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo
  172. sit amet risus.
  173. </dd>
  174. </dl>
  175. </div>
  176. </div>
  177. </div>
  178. </div>
  179. </div>
  180. </section>
  181. </main>
  182. </template>
  183. <script>
  184. /* Import modules. */
  185. // import IPFS from 'ipfs-core'
  186. import { v4 as uuidv4 } from 'uuid'
  187. export default {
  188. data: () => {
  189. return {
  190. ipfs: null,
  191. nodeid: null,
  192. roomName: null,
  193. bootstrapNodes: null,
  194. debugLog: null,
  195. }
  196. },
  197. computed: {
  198. //
  199. },
  200. methods: {
  201. /**
  202. * Start IPFS
  203. *
  204. * Top level function for controlling the IPFS node.
  205. */
  206. async startIpfs() {
  207. try {
  208. console.log('Setting up instance of IPFS...')
  209. /* Create new IPFS instance. */
  210. // this.ipfs = await IPFS.create()
  211. // Pass the IPFS instance to the window object. Makes it easy to debug IPFS
  212. // issues in the browser console.
  213. if (typeof window !== 'undefined') {
  214. window.ipfs = this.ipfs
  215. }
  216. /* Initialize IPFS. */
  217. await this.initIpfs()
  218. // Get this nodes IPFS ID
  219. const id = await this.ipfs.id()
  220. this.ipfsid = id.id
  221. console.log(`This IPFS node ID: ${this.ipfsid}`)
  222. console.log('IPFS node setup complete.')
  223. /* Subscribe to the BUMP (pubsub) room. */
  224. await this.ipfs.pubsub.subscribe(this.roomName, msg => {
  225. // print out any messages recieved.
  226. console.log(msg.data.toString())
  227. this.debugLog.push({
  228. id: uuidv4(),
  229. body: msg.data.toString(),
  230. })
  231. })
  232. console.log(`Subscribed to BUMP (pubsub) room ${this.roomName}`)
  233. // Periodically broadcast identity on the pubsub channel
  234. // setInterval(async () => {
  235. // await this.broadcastMyInfo()
  236. // }, 45000)
  237. // Periodically renew connections to other pubsub channel peers
  238. setInterval(async () => {
  239. await this.connectToPeers()
  240. }, 30000)
  241. } catch (err) {
  242. console.error('Error in startIpfs(): ', err)
  243. console.log('Error trying to initialize IPFS node!')
  244. }
  245. },
  246. // Initialize the IPFS node and try to connect to the PSF bootstrap node.
  247. async initIpfs() {
  248. try {
  249. this.ipfs = await this.ipfs
  250. console.log('IPFS node is ready.')
  251. // Periodically renew connection to the bootstrap nodes.
  252. const intervalHandle = setInterval(() => {
  253. this.connectToBootstrapNodes()
  254. }, 15000)
  255. // Also connect to bootstrap nodes immediately.
  256. await this.connectToBootstrapNodes()
  257. return intervalHandle
  258. } catch (err) {
  259. console.error('Error in initIpfs()')
  260. throw err
  261. }
  262. },
  263. // Attempt to connect to the bootstrap nodes. Cycles through each node in the
  264. // bootstrapNodes array.
  265. async connectToBootstrapNodes() {
  266. try {
  267. const now = new Date()
  268. for (let i = 0; i < this.bootstrapNodes.length; i++) {
  269. const name = this.bootstrapNodes[i].name
  270. const multiaddr = this.bootstrapNodes[i].multiaddr
  271. try {
  272. await this.ipfs.swarm.connect(multiaddr)
  273. // console.log('...IPFS node connected PSF node!')
  274. console.log(
  275. `${now.toLocaleString()} - Successfully connected to ${name}`
  276. )
  277. this.bootstrapNodes[i].hasConnected = true
  278. } catch (err) {
  279. console.log(
  280. `${now.toLocaleString()} - Failed to connect to ${name} - ${multiaddr}`
  281. )
  282. this.bootstrapNodes[i].hasConnected = false
  283. }
  284. }
  285. } catch (err) {
  286. console.error('Error in connectToBootstrapNodes()')
  287. throw err
  288. }
  289. },
  290. // Broadcast the connection information for this IPFS node.
  291. async broadcastMyInfo() {
  292. try {
  293. const now = new Date()
  294. // Date-stamped connection information.
  295. const connectionInfo = {
  296. date: now.toLocaleString(),
  297. ipfsid: this.ipfsid,
  298. message: `Message from browser app @ ${now.toLocaleString()}`
  299. }
  300. const msgBuf = Buffer.from(JSON.stringify(connectionInfo))
  301. // Publish the message to the pubsub channel.
  302. await this.ipfs.pubsub.publish(this.roomName, msgBuf)
  303. console.log(`Published message to ${this.roomName}\n`)
  304. } catch (err) {
  305. console.error('Error in broadcastMyInfo()')
  306. throw err
  307. }
  308. },
  309. // Renew connections to pubsub room peers.
  310. async connectToPeers() {
  311. try {
  312. // TODO: In the future this should use an array of objects to cycle through
  313. // any new peers that connect to the pubsub channel.
  314. /* Find a circuit relay that has successfully connected. */
  315. const circuitRelay = this.bootstrapNodes.filter(elem => elem.hasConnected)
  316. /* Connect to node via circuit relay. */
  317. await this.ipfs.swarm.connect(
  318. `${circuitRelay[0].multiaddr}/p2p-circuit/p2p/${this.nodeid}`
  319. )
  320. console.log(`Connected to messaging peer [ ${this.nodeid} ]`)
  321. } catch (err) {
  322. console.error('Error in connectToPeers()')
  323. throw err
  324. }
  325. },
  326. async sendTest() {
  327. const msgBuf = Buffer.from(`hi there! [ ${new Date()} ]`)
  328. // Publish the message to the pubsub channel.
  329. await this.ipfs.pubsub.publish(this.roomName, msgBuf)
  330. },
  331. },
  332. created: async function () {
  333. this.debugLog = []
  334. // const IPFS = require('ipfs-core')
  335. // console.log('IPFS', IPFS)
  336. // const ipfs = await IPFS.create()
  337. // console.log('ipfs', ipfs)
  338. // const { cid } = await ipfs.add('Hello Bitcoin!')
  339. // console.info(cid)
  340. // Run the node.js app first and get it's IPFS ID.
  341. // this.nodeid = 'QmNvgo499ZUVKV61ZtU8jAYx5ZUEn6eJn4b1LAGtM6nftS' // localhost
  342. this.nodeid = 'QmaZidHAzv6fc2XT2dpHULnKS9rZhzq8KDu4jr2hCe9LVR' // messenger.apecs.dev
  343. // this.nodeid = 'QmQpV2FcL8swjYuarqBWGAvgBBp98JiTYymhSBvktUujK4' // incognito
  344. // Pubsub channel that nodes will use to coordinate.
  345. this.roomName = '4cc225a23cdb830b6978b55e76f4b7966ec08c30a74d1d203fb57e23ebcdcccd' // #lobby:apecs.dev
  346. // Known IPFS nodes to connect to for bootstrapping.
  347. this.bootstrapNodes = [
  348. // {
  349. // name: 'relay.apecs.dev',
  350. // multiaddr: `/dns4/relay.apecs.dev/tcp/443/wss/p2p/QmarVJPsEf8KahYQamALpmpnTbkB4Az2HMDnwopyJjJYzS`,
  351. // hasConnected: false
  352. // }
  353. {
  354. name: 'relay.apecs.dev',
  355. multiaddr: `/dns4/relay.apecs.dev/tcp/443/wss/p2p/12D3KooWRpNvnBDVQ5NVwjxPuj7EY5u42kmFQaP8y5jYfcCpCGSW`,
  356. hasConnected: false
  357. }
  358. // {
  359. // name: 'wss.fullstack.cash',
  360. // multiaddr: `/dns4/wss.fullstack.cash/tcp/443/wss/p2p/QmNZktxkfScScnHCFSGKELH3YRqdxHQ3Le9rAoRLhZ6vgL`,
  361. // hasConnected: false,
  362. // },
  363. ]
  364. /* Start IPFS. */
  365. // await this.startIpfs()
  366. },
  367. mounted: function () {
  368. //
  369. },
  370. }
  371. </script>