【IPFS相关】黑客版的石墨文档?教你在IPFS上存储文档

本文由IPFS原力区收集译制

 

Hacking Graphite是一系列利用分布式,开源代码和创造力的教程。快来破解Graphite并在此过程中学习JavaScript,Blockstack和分布式。

在本系列的第一篇教程中,我们分叉了Graphite存储库,更新了Graphite Sheets,并创建了我们自己的个人API,可以通过简单地更新电子表格中的单元格来控制。看看这里。

在本教程中,我们将探讨IPFS。IPFS是一种p2p存储解决方案,允许永久存储文件。如果您熟悉Git版本控制,则IPFS采用类似的概念 – 如果更改文件,则不会更改文件,但会创建新文件。如果您想保留永久性的变更历史,这非常棒。有关IPFS的更多信息,您可以阅读ConsenSys的这篇介绍,或者您可以直接从源获取您的信息。

Graphite使用Blockstack的SDK和API为用户提供存储在免费的默认存储桶或他们自己选择的存储中心。没有涉及p2p存储,也没有与IPFS的当前集成。让我们改变它!

在开始之前,请注册Graphite帐户或在此处登录:https://app.graphitedocs.com/

Graphite
Graphite允许您创建,交流和共享,而不会放弃您的隐私。app.graphitedocs.com

 

登录后,转到“联系人”,添加新联系人,搜索graphite.id并将该用户添加为联系人。完成后,您可以创建Graphite文档并与之共享graphite.id。以这种方式提出问题并让大家分享你对未来感兴趣的黑客类型真是太棒了。

无论如何,让我们开始吧!

我们将跳过教程的设置部分,因为每节课都是相同的。您可以参考上一个教程,了解有关克隆Graphite存储库,安装依赖项和入门的说明。准备好后,graphite在您选择的文本编辑器中打开文件夹,然后继续。

注意:如果您使用的是上一个教程中的相同代码,那么您将需要重新开始使用Graphite存储库的新克隆。在短短几周内发生了很多变化!

如何以及何时

触发将Graphite文档保存到IPFS的事件有很多选项,但我们将使用本教程中最简单的选项。但首先,让我们来看看创建和编辑Graphite文档时会发生什么。

文档的创建更新索引文件,该文件存储有关文档的足够基本信息以便稍后引用它。要看到这个,请打开src– > components– > helpers。找到documents.js文件并查看第50-71行。单击加号按钮创建新文档时,将调用该函数。它真的在创建/更新两个文件。

首先,它创建一个将被推入整个文档索引数组的对象。您可以value使用第66行的JavaScript扩展运算符看到该对象被推入状态。其次,创建另一个对象以实际创建我们要求系统创建的文档。您会注意到此对象具有比用于索引的属性更多的属性。这是我们保存新单个文档时将使用的对象,并且该单个文档是由其ID在文档索引中引用的。

所有这些对象的创建和保存都是利用用户选择的存储位置或Graphite用户首次创建帐户时可用的默认存储选项。它绝对不使用IPFS,但了解文档的创建方式非常重要,因为接下来我们需要了解文档的更新方式。

看看helpers文件中的同一个文件夹singleDoc.js。这是包含从主文档集合页面单击其链接时获取文档的函数的文件。它也是用于保存文档和文档集合索引文件更新的文件。如果你看第421-466行,你会看到这个handleAutoAdd功能。在对文档进行更改后,此功能每三秒触发一次。如果在该三秒窗口内进行了另一次更改,则取消它(我们不想在用户输入时尝试保存)。

我们可以使用此功能触发自动保存到IPFS。但是,在本教程中,我们不会在每次更改后保存到IPFS。我们将让用户单击一个按钮,并在文件准备好后将其推送到IPFS。但是这个handleAutoAdd功能会发挥作用。所以,坚持下去。

这最终引导我们到本教程的这一部分的哪一部分。我们将在哪里放置允许用户将其Graphite文档存储在IPFS上的操作?将它放在文档标题的下拉菜单中似乎是最有意义的。

从您的终端,启动Graphite with npm run start。我们将查看该文档标题下拉列表。Graphite运行后,打开文档或创建一个新文档。在文档内部,看一下标题:

【IPFS相关】黑客版的石墨文档?教你在IPFS上存储文档

没有一个菜单项非常适合我们正在寻找的东西。如果我们创建一个新的“出口”怎么办?让我们这样做,然后我们可以Post to IPFS在导出下拉列表中嵌套一个按钮。

HTML

首先,我们需要创建标题为“Export”的菜单项。在Graphite代码中,找到该src/components/documents/Menu.js文件。您会看到每个项目的类名称为“topmenu”,其下方的项目具有“子菜单”类名称。我们需要添加一个新的“topmenu”项目。让我们在“共享”菜单项后添加它:

<li className =“topmenu”> 
  <a>分享</a> 
  <ul className =“submenu”> 
   ... 
  </ ul> 
</ li>
<li className =“topmenu”> 
  <a>导出</a> 
</ li>

下一步是使用Post to IPFS按钮从该菜单项创建下拉列表。要做到这一点,我们只需添加一个嵌套无序列表,就像你看到的其他下拉项一样。不要忘记给无序列表提供“子菜单”的类名。这里的列表项是Post to IPFS按钮,在这种情况下是一个锚元素。

<li className =“topmenu”> 
  <a>导出</a> 
  <ul className =“submenu”> 
    <li> <a>发布到IPFS </a> </ li> 
  </ ul> 
</ li>

保存并立即查看您的文档:

【IPFS相关】黑客版的石墨文档?教你在IPFS上存储文档那个按钮还没有做任何事情,但它会。你不担心,它会。让我们为荣耀的日子做好准备,给它onClick指出我们将使用的最终功能。

<li> <a onClick={this.props.postToIPFS}>发布到IPFS </a> </ li>

你可能会问我们为什么打电话this.props。原因将在一分钟内变得明显,但快速回答是所有SingleDoc.js函数都作为父元素的道具传递。在这种情况下,我们将必要的道具传递给Menu.js组件。

这就是现在的HTML。我们将圈回并添加一个模式,该模式将显示当前链接以及所有过去的链接。

JavaScript

几个月前,Graphite的所有文档组件都经过了重要的重构。因此,与每个容纳其自身功能的Sheets组件不同,Graphite文档组件引用辅助文件中的函数。这些函数绑定在App.js文件中,该文件充当所有其他Graphite组件的父组件(目前除了表格)。把它想象成没有Redux的状态管理。

在世界上做出反应,有很多(MANY实现类似的目标)的方式。Graphite在组件中创建父/子关系的方式可能与您希望的方式不同。没关系。它也超出了本教程的范围。因此,为了本课程的目的,只需知道App.js所有对辅助文件中函数的引用,并将这些函数作为props传递给相应的子组件。

让我们继续创建我们将postToIPFShelpers文件夹和singleDoc.js文件中使用的功能。您可以将此功能放在该文件中的任何位置,但我喜欢将它们添加到最后。

导出函数postToIPFS(){ 
  console.log(“它工作!”)
}

console.log语句将确认我们的函数已正确连接。您会注意到该函数已明确声明为export函数。那是因为我们将这个助手文件导出到App.js然后将该函数传递给适当的组件(SingleDoc.js)。

保存后,进入您的src文件夹并进入该components文件夹,然后找到该App.js文件。这个文件太大了。请记住,在Graphite的情况下,所有函数和其他组件都位于此主要父级中。在第124行添加换行符并添加postToIPFS。当你完成时它应该是这样的:

... 来自./helpers/singleDoc的
postToIPFS 
};

现在,让我们绑定该功能。只有在不使用ES6时才需要绑定功能。这超出了本教程的范围,所以我们要绑定!

Graphite尚未升级到componentWillMount不推荐使用的最新版本的React 。所以,暂时,这就是这些功能受到约束的地方。如果找到第674-710行,您将看到该SingleDoc.js组件使用的所有函数。让我们在这个列表的底部添加一个新的:

this.postToIPFS = postToIPFS.bind(this);

最后,使这个函数与我们的SingleDoc.js组件同步的最后一部分,我们需要将该函数作为prop传递给该组件,然后我们将它从该组件传递给Menu.js。Graphite使用BrowserRouter,react-router-dom因此您将找到SingleDoc.js从第1131行开始并包含在<Route>元素中的组件。您可以看到传递给SingleDoc.js组件的所有现有函数:

componentDidMountData = {this.componentDidMountData} 
handleAutoAdd = {this.handleAutoAdd} 
handleChange = {this.handleChange} 
print = {this.print} 
sharePublicly = {this.sharePublicly} 
handleTitleChange = {this.handleTitleChange} 
handleBack = {this.handleBack} 
sharedInfoSingleDocRTC = {this.sharedInfoSingleDocRTC} 
sharedInfoSingleDocStatic = {this.sharedInfoSingleDocStatic} 
handleStealthy = {this.handleStealthy} 
postToMedium = {this.postToMedium} 
shareToTeam = {this.shareToTeam} 
initialDocLoad = {this.initialDocLoad} 
getYjsConnectionStatus ={this.getYjsConnectionStatus } toggleReadOnly ={this.toggleReadOnly} 
stopSharing = {this.stopSharing} 
stealthyChat = {this.stealthyChat}

我们要做的就是以相同的方式添加我们的新功能:

... 
stopSharing = {this.stopSharing} stealthyChat 
= {this.stealthyChat} 
postToIPFS = {this.postToIPFS}

保存它,然后找到该src/components/documents/SingleDoc.js文件。在该文件中,找到该Menu组件。它应该在第155行。正如我们所做的那样,App.js我们将把postToIPFS功能传递到Menu.js其他道具的底部。

<Menu 
  downloadDoc = {this.props.downloadDoc} 
  handleaddItem = {this.props.handleaddItem} 
  formatSpacing = {this.props.formatSpacing} 
  print = {this.props.print} 
  graphitePro = {graphitePro} 
  teamDoc = {teamDoc} 
  userRole = {userRole} 
  mediumConnected = {mediumConnected} 
  postToIPFS = {this.props.postToIPFS} 
/>

而已。现在,转到单个文档,打开文档标题中的菜单,然后单击Post to IPFS。打开你的控制台,如果一切顺利,你应该看到It's working!

你可能不相信,但困难的部分已经完成!我们接下来将开始本教程的IPFS部分。

IPFS

IPFS有一个JavaScript实现,可以在像Graphite这样的React应用程序中使用它。但是,值得注意的js-ipfs是仍处于alpha状态,因此它会受到问题的影响。您应始终使用alpha软件,风险自负。

如果您想在本教程之后进一步探索,这里是 IPFS JavaScript存储库的链接。要在Graphite中开始使用它,我们需要返回命令行。在终端窗口中,运行以下命令(如果Graphite仍在运行,则终止它):

npm install ipfs --save

完成安装后,继续启动Graphite备份npm run start,然后再次打开文本编辑器。在该src文件夹中,然后在该components文件夹中,找到该helpers文件夹。再次,找到singleDoc.js帮助文件。这是我们要导入js-ipfs刚刚安装的库的地方。在文件的顶部,在import语句下面添加:

const IPFS = require('ipfs')
const node = new IPFS()

我们还将把这些添加到

src/components/documents/SingleDoc.jsimport语句下面的文件顶部的行。我们在两个地方添加它们的原因是因为我们将使用一个集合来启动节点,另一个集合用于发布和读取文件。

通过这两条线,我们已经启用了我们所需的所有IPFS功能。

现在,在函数src/components/documents/SingleDoc.js

末尾的文件中,componentDidMount初始化IPFS节点

如下所示:

node.on('ready',async()=> { 
  const version = await node.version(
  console.log('Version:',version.version)
});

我们来谈谈这是做什么的。我们将此回调放在componentDidMount函数中,因为我们只希望在页面加载后触发它。当它触发时,它正在初始化IPFS节点和控制台记录节点版本。而已。但它对下一步非常重要。

src/components/helpers/singleDoc.js文件中,您现在可以向下滚动到postToIPFS之前创建的功能。在这个函数里面,让我们添加一个简单的测试:

导出函数postToIPFS(){ 
  node.files.add({ 
    path:'helloworld.txt',
    content:Buffer.from('Hello,World')
  })。then((res)=> { 
    console.log(res [ 0] .hash)
  })
}

我们来谈谈这里发生了什么。第一行node.files.add告诉它添加一些文件。这是一个回调本身,它表示当节点准备就绪时,添加一个文件的标题(或路径)helloworld.txt和内容Hello, World。然后,控制台记录生成的哈希。IPFS是一个内容寻址文件系统,这意味着您收到的哈希将特别对应于文件的内容。如果你再次发布同样的东西,你将获得相同的哈希值。但是,如果更改内容,您将获得不同的哈希值。

继续保存,如果需要,再次从终端启动Graphite,打开Graphite文档,打开控制台,单击文档标题中的菜单按钮,然后单击Post to IPFS。如果一切顺利,您应该在控制台中看到生成的哈希:

QmTev1ZgJkHgFYiCX7MgELEDJuMygPNGcinqBa2RmfnGFu

哈希将与您在上面看到的完全相同,因为内容完全相同。事实上,数百名其他人已经看到了完全相同的哈希。关于内容寻址文件存储,这是很酷的事情。

现在,你怎么能用这个呢?好吧,如果您正在运行本地IPFS节点,则可以使用该哈希来访问您的文件。但是,我们不会讨论如何运行IPFS节点。相反,我们将使用公共网关来访问IPFS文件。

如果您导航到以下链接,您将看到我的测试文件。您可以用自己的哈希值替换我的哈希值(Qm字符串)来查看您的文件。

https://ipfs.io/ipfs/QmTev1ZgJkHgFYiCX7MgELEDJuMygPNGcinqBa2RmfnGFu

很酷,对!这是您刚刚创建的内容的永久表示。

但是等等,我们只是将一些文字硬编码到这里。我们想要实际存储我们的Graphite文档,对吗?我们这样做!

回到src/components/helpers/singleDoc.js你可以更新postToIPFS功能,以动态创建正确的标题/文件路径并发布正确的内容。这是如何做:

node.files.add({ 
    path:this.state.title +'。txt',
    content:Buffer.from(JSON.stringify(this.state.content))
  })。then((res)=> { 
    console。 log(res [0] .hash)
  })

它看起来几乎与以前完全相同,只是我们注入状态代替硬编码部分。而不是helloworld.txt我们没有使用文档标题的路径,如表所示this.state.title。对于内容,我们仍然传递一个字符串,但是Hello, World,我们将字符串this.state.content化为Graphite文档的内容,该文档以JSON 格式存储。

继续保存,然后Post to IPFS再次按下按钮。您应该在控制台中获得不同的哈希值,如果您从之前将其弹出到公共IPFS网关链接中,您应该会看到文档的内容(提示:确保首先在文档中键入了某些内容)。

这是我所有lorem ipsum-y善良中的链接:

https://ipfs.io/ipfs/QmTUP7DXHdjqM1f3vA2v4BH8jv5CJWyTTBbkpmKYbpgCwA

很酷!

并且为了证明如果内容发生变化,散列实际上会发生变化,那么让我们继续对Graphite Doc的主体进行更改。将文本更改为您想要的任何内容,只需确保它与您上次发布到IPFS时的不同。

一旦你改变了内容,继续再次点击Post to IPFS按钮并获取控制台中显示的哈希值。在我的例子中,我用粗体和斜体显示了所有lorem ipsum内容,事实上它确实给了我一个不同的哈希:

QmYnxhDsVH72sMAUTDxKCmmtrfPwTfWkuLGxwFow6gpwSK

您可以看到我的哈希值与第一次存储文件时明显不同,当然内容也不同。这是我在公共IPFS网关上的文件:

https://ipfs.io/ipfs/QmYnxhDsVH72sMAUTDxKCmmtrfPwTfWkuLGxwFow6gpwSK

将散列替换为控制台中的散列,您应该看到更新的内容。

结论

我们可以做更多的事情,但教程很长。让我们回顾一下,然后我将向您介绍如何将此增强功能用于Graphite。

首先,我们创建了一种将新内容从Graphite发布到IPFS的方法。然后,我们将IPFS的JavaScript实现安装到Graphite中,并连接一个回调函数,该回调函数将初始化在浏览器中运行的IPFS节点。最后,我们编写了一个函数,该函数触发了一个IPFS回调,该回调将Graphite Doc的内容存储在分布式Web中。

在本教程之上构建的改进潜力几乎是无限的,但这里有一些想法:

  • 每次将文件更新为默认的Graphite存储时保存哈希

  • 创建一个版本控制系统,保留所有哈希值,并允许用户访问过去的版本(这可能很快就会出现在石墨生产中!)

  • 自动保存到IPFS(还记得handleAutoAdd我在本文开头提到的功能吗?

  • 在将内容发送到IPFS之前加密内容

  • 直接从IPFS加载内容而不是Graphite的默认存储

  • 等待

  • 等待

  • 等待

快乐黑客!

【IPFS相关】由IPFS原力区译制整理,收集外网中各领域人士在使用或开发IPFS及其相关应用时所分享的文章内容。

  IPFS原力区官网:http://ipfsforce.com

IPFSER社区: http://ipfser.org
微博:http://weibo.com/ipfsforce

【IPFS相关】黑客版的石墨文档?教你在IPFS上存储文档

原创文章,作者:IPFSforce,如若转载,请注明出处:http://ipfser.org/2018/12/04/ipfsinthewild-hackinggraphite/

发表评论

登录后才能评论

联系我们

在线咨询:点击这里给我发消息

邮件:ipfsforce@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code