【操作指南】100行代码实现CMD线聊天应用程序
IPFS原力区
2019-07-18
热度13636

我们生活在一个断开连接,靠电池供电的世界,但我们的技术和最佳实践是过去一直连接并稳定供电的时代遗留下来的。

本文由IPFS原力区收集译制,版权所属原作者

 

下面是为 Nodejs构建 offline-first聊天应用程序的最快方法


William Navarro  Unsplash上​​的照片 

 

引用 offlinefirst.org 的话说,我们生活在一个断开连接,靠电池供电的世界,但我们的技术和最佳实践是过去一直连接并稳定供电的时代遗留下来的纺织,我们发现一种新的应用程序开发前进方向,它包含现代的,分散的网络技术,同时促进以用户为中心的数据控制。但是分散式的应用程序开发仍然处于起步阶段,并且开始时非常困难。这就是纺织不断增长的开发工具套件发挥作用的地方-使得开发人员可以更容易地构建分散的,离线优先的,保护隐私的应用程序,这些应用程序使用的工具与他们期望从更传统的集中框架中获得的工具类型相同。

 

为了展示使用纺织构建有用的应用程序是多么容易,今天的文章将介绍如何构建一个极简主义的CMD线聊天应用程序,它是完全分散的,支持离线消息传递,对等发现等等。我们将用不到100行“客户端”代码来完成。就是“hello world”示例应用程序而言,这个应用程序实际上非常有用。听起来好得令人难以置信?让我们来看看?

 

对于没有耐心的人,这里是完整的代码。(原文链接查看

 

开始

 

首先,我们要在分散式开发工具的纺织生态系统上构建我们的应用。特别是,我们将利用纺织桌面托盘应用程序运行Textile / IPFS节点,js-http-client 库来与上述节点进行接口,以及其他几个的NodeJS库来帮助清理基于终端的用户界面。因此,让我们从下载并安装最新的桌面应用程序开始。对于本演示的目的,您还可以在创建纺织帐户时创建一个新的帐户应用。程序的登录屏幕应该会帮助你开始。但在你深深了解之前,我强烈建议你看看纺织之旅。我们将在这篇文章中引用该文档中的一些部分,另外它还解释了什么是纺织品钱包帐户,为什么要创建一个呢,以及如何与之互动......

 

设置

现在您是纺织技术方面的专家,已经下载并安装了托盘应用程序,让我们开始构建首先,我们将创建一个最小的项目的NodeJS,并安装一些初始依赖。:

    mkdir txtlcd txtlyarn init

    按照提示生成 JSON文件,我的是这样的:

      { "name": "txtl", "version": "1.0.0", "description": "A simple cli chat app using Textile", "main": "index.js", "author": "Textile", "license": "MIT"}

      如果您想对这个项目进行版本控制,您还可以 git init  curl https://www.gitignore.io/api/node> .gitignore 初始化一个带有有用的 .gitignore 文件的回购。

       

      依赖关系

      接下来,让我们添加一些依赖项。我们前面提到 js-http-client (这就是我们如何将访问纺织托盘程序的API),让我们抓住这一个还有三个附加的库,简化cmd-line应用Nodejs(cac  - 构建我们cmd-line接口,chalk - 终端串样式和颜色,和node-emoji - 因为我们需要emojis):

        yarn add @textile/js-http-client cac chalk node-emoji

        好了,有了这些东西,让我们想想我们要做什么。基本上我们要模拟库来与上述节点进行接口,以及其他几个的NodeJS库来帮助清理基于终端的用户界面。因此,让我们从下载并安装最新的桌面应用程序开始。对于本演示的目的,您还可以在创建纺织帐户时创建一个新的帐户。应用程序的登录屏幕应该会帮助你开始。但在你深入了解之前,我强烈建议你看看 Tour of Textile 开始聊天部分,但在我们的示例中,一个(或两个)对等节点将使用自定义Nodejs聊天接口。如果你看看它的一部分,你会看到我们有一个非常简单的CMD在线聊天应用程序,你开始与纺织聊天在标准输入和接收输入,并将输出写入标准输出,和一些不错的颜色,使它更有趣的事情。很简单对吧?我们开始吧。

         

        设置界面

        首先,我们将创建 CMD线接口,然后添加实际的基于文本的代码,然后添加一些颜色和调整。我们将在此过程中添加所需的导入,这样您就可以看到每个更改来自何处。因此,首先在主项目文件夹中创建index.js 文件(我使用VSCode,但您可以坚持使用任何编辑器):

          #!/usr/bin/env node
          const cli = require('cac')('txtl')
          const { log } = console
          // Create 'default' chat commandcli.command('', 'Starts an interactive chat session in a thread.') .action((opts) => { log('do something') }) .option('--thread [thread]', 'Thread ID. Omit to use the \'default\' thread.', { default: 'default', type: [String] })
          // Display help message when `-h` or `--help` appearscli.help()// Display version number when `-v` or `--version` appearscli.version('1.0.0')// Parse stdincli.parse()

          这里没什么特别的,我们只是 cac 文档中复制粘贴。我们正在模拟 go-textile cmd-line客户机的接口,所以这里也添加了--thread 选项。接下来,我们将使用 readline 模块向 cmd-line 。工具添加一些交互性以下是我们需要做的更新

            diff --git a/index.js b/index.jsindex 11b46ac..4cf1473 100644--- a/index.js+++ b/index.js@@ -1,6 +1,7 @@ #!/usr/bin/env node const cli = require('cac')('txtl')+var readline = require('readline') const { log } = console @@ -8,6 +9,19 @@ const { log } = console cli.command('', 'Starts an interactive chat session in a thread.') .action((opts) => { log('do something') // Specify our readline interface const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }) // Run callback for each input on stdin rl.on('line', (line) => { if (line !== '') { log(line) rl.prompt() } }) }) .option('--thread [thread]', 'Thread ID. Omit to use the \'default\' thread.', {     default'default',

            我们只需指定 readline的接口,然后在每次输入新行时将输入回显到终端。还不是很有用 ......所以让我们添加一些纺织功能,使其有用。我们假设您已经有一个去纺织或桌面托盘应用程序运行,因此我们将直接与该应用程序交互

             

            与纺织交互

              diff --git a/index.js b/index.jsindex 4cf1473..598b1d1 100644--- a/index.js+++ b/index.js@@ -1,6 +1,7 @@ #!/usr/bin/env node const cli = require('cac')('txtl')+const textile = require('@textile/js-http-client').default var readline = require('readline') const { log } = console@@ -8,7 +9,6 @@ const { log } = console // Create 'default' chat command cli.command('', 'Starts an interactive chat session in a thread.') .action((opts) => {- log('do something') // Specify our readline interface const rl = readline.createInterface({ input: process.stdin,@@ -18,10 +18,22 @@ cli.command('', 'Starts an interactive chat session in a thread.') // Run callback for each input on stdin rl.on('line', (line) => { if (line !== '') { log(line) rl.prompt() textile.messages.add(opts.thread, line) .then(() => { rl.prompt() }) } }) // Get our 'local' profile info... textile.profile.get() .then((peer) => { // ... and then create a custom prompt rl.setPrompt(peer.name || peer.address.slice(7) + '\t') rl.prompt() // Display prompt to get started // Only subscribe to text events on the specified thread textile.subscribe.stream(['TEXT'], opts.thread) .then((stream) => { log('do something') }) }) }) .option('--thread [thread]', 'Thread ID. Omit to use the \'default\' thread.', {default: 'default',

              好了,这部分还没有完全完成,接下来是

               

              • 在第 9行,我们从textile 库导入了默认的 textile实例。这个实例假设您正在http://127.0.0.1:40600 上运行 Textile REST API(默认情况下是这个API)。如果在其他端口上运行,则必须导入Textile(类),并使用const Textile = new Textile({url:...,port:...,version:0})创建一个新实例。

              • 在第 27行中,我们已经指定,对于来自终端的每个新输入,我们将把消息发送到指定的线程,然后在下一行打印出一个漂亮的提示符

              •  31-42行只是获取我们的本地概要文件,并使用我们的显示名称(如果它存在,否则是地址的第一部分)作为输入提示符。然后,我们订阅指定线程上的所有文本事件,并且... ...到目前为止什么都没有做。

               

              订阅更新

              现在我们已经基本设置好了,让我们对订阅 API做一些实际操作,这样当新的聊天消息添加到线程中时,我们就可以得到通知。

                diff --git a/index.js b/index.jsindex 598b1d1..963d96f 100644--- a/index.js+++ b/index.js@@ -31,7 +31,31 @@ cli.command('', 'Starts an interactive chat session in a thread.') // Only subscribe to text events on the specified thread textile.subscribe.stream(['TEXT'], opts.thread) .then((stream) => { log('do something') // All js-http-client stream endpoints return a ReadableSream const reader = stream.getReader() const read = (result) => { if (result.done) { return } // Extract the text update and display it nicely... try { const item = result.value.payload const name = item.user.name || item.user.address.slice(7) if (item.user.address !== peer.address) { readline.clearLine(process.stdout, 0) readline.cursorTo(process.stdout, 0) log(name + '\t' + item.body) rl.prompt() } } catch (err) { reader.cancel(undefined) return } // Keep reading from the stream reader.read().then(read) } // Start reading from the stream reader.read().then(read) }) })})

                这是迄今为止最复杂的一步,请注意,我们没有做任何错误检查或类似的事情来保持事情的简单。现在,注意所有的 js-http-client 流端点都返回一个ReadableStream(在Nodejs和浏览器中,多亏了一些同态的魔力!)这个流可以通过管道连接到转换流或任何可写流,并且您可以获取一个阅读器来从流中读取更新,这就是我们在这里所做的。在上面的示例中(与MDN网络上的文档示例非常相似),我们只是递归地调用,直到流(只要您的对等程序运行,流就应该保持打开状态)。任何时候我们有一个新的更新,我们都会抓取它,找出添加它的用户,如果不是我们,我们就清除当前行,添加新的消息,并记录一个新的提示。简单!

                 

                让它珀迪......

                上面的例子已经准备好了,但是如果我们真的想要模拟(并构建)go-textile 版本,我们需要一些最后的润色

                  diff --git a/index.js b/index.jsindex 963d96f..6e7bfc1 100644--- a/index.js+++ b/index.js@@ -3,6 +3,8 @@ const cli = require('cac')('txtl') const textile = require('@textile/js-http-client').default var readline = require('readline')const chalk = require('chalk')const { emojify } = require('node-emoji') const { log } = console @@ -18,7 +20,7 @@ cli.command('', 'Starts an interactive chat session in a thread.') // Run callback for each input on stdin rl.on('line', (line) => { if (line !== '') { textile.messages.add(opts.thread, line) textile.messages.add(opts.thread, emojify(line)) .then(() => { rl.prompt() }) } })@@ -26,7 +28,7 @@ cli.command('', 'Starts an interactive chat session in a thread.') textile.profile.get() .then((peer) => { // ... and then create a custom prompt rl.setPrompt(peer.name || peer.address.slice(7) + '\t') rl.setPrompt(chalk.green(peer.name || peer.address.slice(7)) + '\t') rl.prompt() // Display prompt to get started // Only subscribe to text events on the specified thread textile.subscribe.stream(['TEXT'], opts.thread)@@ -44,7 +46,7 @@ cli.command('', 'Starts an interactive chat session in a thread.') if (item.user.address !== peer.address) { readline.clearLine(process.stdout, 0) readline.cursorTo(process.stdout, 0) log(name + '\t' + item.body) log(chalk.cyan(name) + '\t' + chalk.grey(item.body)) rl.prompt() }} catch (err) {

                  现在我们有了表情符号功能和一些漂亮的颜色来改善我们的聊天体验。您现在应该能够运行这个示例了。因此,在“纺织之旅”中回到开始聊天的示例,在启动默认聊天会话纺织聊天线程= ” 12D3K ... )的步骤中,使用新的自定义聊天应用程序 /index.js-thread= “ 12D3K ... (运行使用chmod + X .index.js 之后)。

                   

                  想要给你新的 cmd-line应用程序添加更多的功能吗?将以下内容添加到包中。指定二进制cms -line工具的json文件:

                    "bin": { "txtl": "index.js"  }

                    现在当你运行像 yarn add -g txtl这样的东西时,你将拥有一个方便时髦的cmd在线聊天工具!等等,还有呢,想要在打字稿中完成整个过程吗?容易。

                     

                    该等超级打印稿

                    首先添加一些 dev ependencies 

                      yarn add --dev typescript @types/node @types/node-emoji

                      然后,一旦安装完成,就使用 tsconfig初始化tsconfig.json文件:

                        yarn tsc --init

                        您可能可以保留它的默认值,但我建议至少启用声明源地图,并将 outDir 设置为 “./dist” 

                         

                        现在写一些打字稿。几乎不需要做任何更改,但是这里有一个完整工作的打字稿版本的要点,其中有一些额外的检查。

                         

                        现在,只需运行 yarn tsc,就可以得到新生成的commonjs风格的Javascript代码,以及(存根)声明文件。如果您真的想发布这个项目,您可能想要更新bin 条目,并向包中添加某种准备package.json文件,但还是将它作为练习吧。 

                         

                        离线怎么样

                        我们还没有真正提到离线的第一部分,首先,为什么离线先?有很多重要的原因,特别是世界上大多数日常使用的 web仍然是由移动设备,带宽限制和电池驱动的交互驱动的。作为一个第一手的例子,写这篇文章的时候,正在世界上互联网极不完善的地方远程办公.Medium web-ui实际上是不可用的,所以用VSCode编写这个文件,并最终将文件上传到中等以便发布。不是最理想的。聊天应用程序和其他协作工具更受这个问题的困扰。如果和你聊天的人不在网上呢?或者你的网络中断了谈话?如果您都连接到相同的本地网状网络,但没有外部网络访问怎么办?难道你就不能和别人聊天吗?

                         

                        这就是离线首先发挥作用的地方,我的本地纺织(感谢IPFS)像冠军一样为我处理这个问题。如果我在离线时正在写一条消息,我的本地对等点将把消息添加到我的本地IPFS实例中,下一次我在线时,它将向我的对等点声明它(就UX而言,它感觉就像消息被“发送”了)。更棒的是,如果我的同事已经在咖啡馆注册了,它就会把我的信息发送到我同事的收件箱,这样他们下次上网时就能收到我的信息。与此同时,任何等待我的消息都将被自动获取,随时可以阅读和交互。对于聊天,照片和文件这样的事情,这可能意味着与朋友和家人保持联系,即使你的互联网连接充其量是断断续续的

                         

                        最好的部分?上面的场景是以完全分散的方式发生的。不需要集中式服务器(即使咖啡馆也只是连接到分散式IPFS网络的额外对等点)。这甚至适用于无法接入更广泛互联网的地区。通过使用纺织品作为聊天的“后端”,您可以“免费”获得所有这些离线优先的功能。

                        - 全文完 - 


                        本文由IPFS原力区编译,原文链接:

                        https://medium.com/textileio/decentralized-offline-first-cmd-line-chat-app-in-100-lines-of-code-43ed71a70950

                        本文源自公众号「IPFS原力区」(WX号:IPFS-FORCE),定时更新优质讯息

                        本内容旨在传递行业动态,不构成投资建议或承诺。
                        为你推荐

                        商务合作:TG:@Lottie96