【IPFS相关】构建可加载图片的分布式应用程序
本文由IPFS原力区收集译制
分布式应用程序(DApps)是在计算机的P2P网络上运行的应用程序,而不是单个计算机,其代码库是公开开放的,作为可供访问和定制的开源。DApps分布在多个服务器上,而不是位于集中式服务器上,这有助于管理大量数据和流量需求。
比特币是分布式应用程序的一个例子,由于最近获得的兴趣,我们将更多地讨论它。
Blockchain并不是关于Cryptocurrencies(加密货币)和ICO(代币发行)人们认为的,围绕它的技术是令人着迷的。
“区块链是一个不可摧毁的经济交易数字分类账,可编程记录不仅仅是金融交易,而是几乎所有有价值的东西。”Don&Alex Tapscott,作者Blockchain Revolution(2016)
这正是区块链的所在。区块链上的信息作为共享 – 并且不断调和 – 数据库存在,这意味着互联网上的每个人都可以访问数据。
使用区块链存储大型文件或数据是很昂贵的,我们在InterPlanetary文件系统(IPFS)上保存大型文件,之后我们将哈希存储在区块链上。
InterPlanetary文件系统是一种协议和网络,旨在创建一种内容可寻址的点对点方法,用于在分布式文件系统中存储和共享超媒体
“IPFS和Blockchain完美匹配!您可以使用IPFS处理大量数据,并将不可变的永久IPFS链接放入区块链事务中。这个时间戳和保护您的内容,而不必将数据放在链本身上。“作者Michael Chan
现在我们了解所有区块链的全部内容。让我们构建一些东西!我们将构建一个允许用户上传图片的移动应用程序,该图片保存在IPFS上,并将IPFS哈希值保存在以太坊区块链上。
如何构建它:
Prequisite:
-
Node.js :它是基于谷歌Chrome的JavaScript引擎(V8引擎)构建的服务器端平台
-
MetaMask:它是一个桥梁,允许您今天在浏览器中访问明天的分布式网络。它允许您直接在浏览器中运行Ethereum dApp,而无需运行完整的以太坊节点
-
松露:它是以太坊的一个开发环境,它提供了一系列工具,如ganache-core,它模拟了localhost中的以太网网络,非常适合入门。
-
Web3:它是一组库,允许您使用HTTP或IPC连接与本地或远程以太它节点进行交互 。此处提供了更多信息。
因此,服务器将构建在Node.js和具有React-native的移动应用程序上。
我们将从编写一个获取并保存哈希的简单智能合约开始。
既然我们已经需要将可靠性代码转换为Javascript,我们将使用名为solc的npm模块。
在solc定义的模块的帮助下,将可靠性代码转换为Javascript对象,并将其导入我们的文件中。然后使用web3它与智能合约进行交互。
const code =fs.readFileSync('./contracts/StoreHash.sol').toString(); const solc = require('solc'); const compiledCode = solc.compile(code); const abi =JSON.parse(compiledCode.contracts[':SaveAddress'].interface); const SavingContract = new web3.eth.Contract(abi, '0xb1caf625d9d29421dfd8dae4a7a9083b4175f80a'); // where 0xb1caf625d9d29421dfd8dae4a7a9083b4175f80a is the ethereum address
现在,我们有我们的智能合同规定,让我们继续前进,上传file.Going通过定义images.js 在这里 ,我主要做的是:
1.从移动应用程序获取我们的文件
exports.uploadFile = async (req, res, next) => { if (!req.file) { return res.status(422).json({ error: 'File needs to be provided.', }); } const mime = req.file.mimetype; if (mime.split('/')[0] !== 'image') { fs.unlink(req.file.path); return res.status(422).json({ error: 'File needs to be an image.', }); } const fileSize = req.file.size; if (fileSize > MAX_SIZE) { fs.unlink(req.file.path); return res.status(422).json({ error: `Image needs to be smaller than ${MAX_SIZE} bytes.`, }); } const data = fs.readFileSync(req.file.path); return ipfs.add(data) .then((file) => { if (file) { req.data = file; next(); } else { res.status(400).send('Error processing file'); } }) .catch((err) => { res.status(500).send(err.message); }); };
2.将其上传到IPFS
3.将哈希值保存在以太坊区块链上
exports.postData = async (req, res, next) => { try { const { hash } = req.data[0]; const accounts = await web3.eth.getAccounts(); const resp = await SavingContract.methods.saveHash(hash) .send({ from: accounts[0], }); const data = Object.assign({ ipfsHash: hash }, resp); req.data = data; next(); } catch (err) { res.status(500).send(err.message); } };
4.在我们的mongo数据库中保存区块链哈希和IPFS哈希
exports.create = async (req, res) => { try { const data = { label: req.body.label, ipfsHash: req.data.ipfsHash, ipfsAddress: `https://gateway.ipfs.io/ipfs/${req.data.ipfsHash}`, transactionHash: req.data.ipfsHash, blockHash: req.data.blockHash, }; const resp = await Image.create(data); res.send(resp); } catch (err) { res.status(500).send(err.message); } };
完整的后端源代码可以在这里找到https://github.com/linux08/Dapp/tree/master/backend
让我们移动到移动应用程序,我们使用创建一个新的应用程序
react-native init dapp
这将为您创建一个新的react-native应用程序。从这里https://github.com/linux08/Dapp/blob/master/frontend/dapp/App.js我们可以看到我们正在启动API调用我们的API服务器已启动以获取上传的所有图像
componentDidMount() { const config = { method: 'GET', headers: { Accept: 'application/json' }, }; fetch('http://10.0.2.2:5000/images', config) .then((resp) => resp.json()) .then((res) => { this.setState({ images: res, fetchLoading: false }) }) .catch((err) => { console.log('err', err.message) this.setState({ fetchLoading: false, error: err.message }); }) }
如果没有可用的图像,我们可以上传新的图像。我们将使用
在我们的本机应用程序中上传图像。我们声明了两个函数:
1.从我们的手机阅读图像
selectImage = async () => { ImagePicker.showImagePicker(options, async (response) => { if (response.didCancel) { this.setState({ error: 'Image upload failed', loading: null }); } else if (response.error) { this.setState({ error: 'Image upload failed', loading: null }); } else if (response.customButton) { this.setState({ error: 'Image upload failed', loading: null }); } else { const source = { uri: response.uri }; this.setState({ uploadStatus: true, avatarSource: source, uri: response.uri, type: response.type, name: response.fileName, originalName: response.fileName }); global.data = new FormData(); data.append('file', { uri: response.uri, type: response.type, name: response.fileName, originalname: response.fileName, }); const config = { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'multipart/form-data', }, body: data, }; } }) }
2.将图像上传到本地服务器
upload = async () => { this.setState({ loading: true }); if (!this.state.uploadStatus) { this.setState({ loading: null }) return alert('Image yet to be uploaded') } if (this.state.label === '') { this.setState({ loading: null }) return alert('Enter image label') } else { data.append('label', this.state.label); const config = { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'multipart/form-data', }, body: data, }; fetch('http://10.0.2.2:5000/upload', config) .then((resp) => resp.json()) .then((res) => { this.setState((prevState) => ({ label: res.label, hash: res.ipfsHash, address: res.ipfsAddress, transactionHash: res.transactionHash, blockHash: res.blockHash, loading: false, images: prevState.images.concat(res), })) }) .catch((err) => { this.setState({ loading: false, error: err.message }); }) }
【IPFS相关】由IPFS原力区译制整理,收集外网中各领域人士在使用或开发IPFS及其相关应用时所分享的文章内容。
IPFS原力区官网:http://ipfsforce.com
IPFSER社区: http://ipfser.org
微博:http://weibo.com/ipfsforce

原文始发于微信公众号(IPFS原力区):【IPFS相关】构建可加载图片的分布式应用程序