A Inovação está chamando
Usando a nova e incrível GPT Chat de AI aberta, uma cabeça cheia de ideias e o conhecimento para unir tudo isso, consegui produzir este guia em tempo recorde.
Se você ainda não conferiu isto, divirta-se aqui.
Crie um Aplicativo React
Este guia assume que você tenha uma configuração de nó. Se não tiver, pode instalá-lo daqui.
Crie um novo diretório para nosso aplicativo frontend em sua área de trabalho, abra uma nova janela de terminal e faça um cd (change directory ou mudar diretório) para esse diretório.
Uma vez neste novo diretório, digite o seguinte no terminal para criar um novo aplicativo react:
npx create-react-app FileCompressor
Uma vez instalada, sua nova estrutura de diretório será construída.
Adicione um Formulário de Carregamento Frontend
Vá para src/app.js e navegue até a função App para inserir esta lógica:
import React from "react";
function App(props) {
const handleChange = e => {
const fileReader = new FileReader();
fileReader.readAsText(e.target.files[0], "UTF-8");
fileReader.onload = e => {
if(e.target !== null) {
console.log("e.target.result", e.target.result);
}
};
};
return (
<>
<h1>Upload file</h1>
<input type="file" onChange={handleChange} />
</>
);
}
export default App;
Isto criará uma nova função chamada handleChange que é chamada toda vez que um arquivo é carregado no frontend.
Base64
Nossos arquivos não estão no momento em nenhum formato que a cadeia possa entender. Precisamos, então, transformá-los em um string de base64 que possa ser armazenado on chain.
Volte para seu arquivo app.js onde adicionaremos a lógica base64 ao método handleChange:
import React from "react";
function App(props) {
const handleChange = e => {
const fileReader = new FileReader();
fileReader.readAsDataURL(file)
fileReader.onload = () => {
console.log(fileReader.result);
}
fileReader.onerror = (error) => {
console.log(error);
}
};
return (
<>
<h1>Upload file</h1>
<input type="file" onChange={handleChange} />
</>
);
}
export default App;
Até agora temos um formulário de upload de arquivo que pega o input, converte o arquivo para um string de base64 e console.logs (imprime no console como uma mensagem de log) a saída. Assim, isso é bom, mas é muito mais agradável usar a compactação para reduzir a contagem de bytes.
Compactação de String LZ
Primeiro instale a biblioteca para compactação lz:
npm i lzma-js
Uma vez instalado, modifique o app.js para assemelhar-se ao exemplo abaixo, isto então registrará o string de base64 compactada no terminal:
import React from "react";
import LZMA from "lzma-js";
function App(props) {
const handleChange = e => {
const fileReader = new FileReader();
fileReader.readAsDataURL(file)
fileReader.onload = () => {
// Converter o string codificado de base64 em um Uint8Array
const uint8Array = Uint8Array.from(atob(fileReader.result), c => c.charCodeAt(0));
// Compactar o Uint8Array usando LZMA-JS
LZMA.compress(uint8Array, 9, (result, error) => {
if (error) {
// Tratar o erro
} else {
// Os dados compactados são um Uint8Array, então você precisa convertê-los para um string codificado de base64
const compressedBase64String = btoa(String.fromCharCode(...result));
console.log(compressedBase64String); // Outputs the compressed base64 encoded string
}
});
}
fileReader.onerror = (error) => {
console.log(error);
}
};
return (
<>
<h1>Upload file</h1>
<input type="file" onChange={handleChange} />
</>
);
}
export default App;
O Contrato Inteligente
Este é um contrato inteligente simples que armazena um conjunto de strings de 32 bytes, neste caso nossos 32 bytes são arquivos.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract FileStorage {
mapping (address => bytes32[]) userFiles;
function addFile(string calldata _file) public {
userFiles[msg.sender].push(_file);
}
function deleteFile(uint arrayIndex) public {
delete userFiles[msg.sender][arrayIndex];
}
function getFiles() public view returns (bytes32[] memory) {
return userFiles[msg.sender];
}
}
Isto é o mínimo necessário. Para os casos de produção você provavelmente precisaria muito mais, mas o contrato acima será suficiente para o propósito deste tutorial. Uma vez implantado, você estará pronto para conectar seu aplicativo react ao seu banco de dados de arquivos descentralizado.
Conectando o Dapp
Primeiramente, pegue o abi (interface binária de aplicação) para seu contrato de implantação e armazene em um novo arquivo chamado abi.json.
[
{
"inputs": [
{
"internalType": "string",
"name": "_file",
"type": "string"
}
],
"name": "addFile",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "arrayIndex",
"type": "uint256"
}
],
"name": "deleteFile",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getFiles",
"outputs": [
{
"internalType": "string[]",
"name": "",
"type": "string[]"
}
],
"stateMutability": "view",
"type": "function"
}
]
Se você voltar ao arquivo app.js, a etapa final será substituir nosso log de console do string de arquivos por uma chamada de contrato inteligente. Primeiro puxamos o contrato abi, preenchemos o endereço do contrato, conectamos à MetaMask através do frontend e depois permitimos que o arquivo do usuário seja armazenado após a conexão ter sido estabelecida.
import React from "react";
import LZMA from "lzma-js";
function App(props) {
const abi = require('./abi.json');
const handleChange = e => {
const fileReader = new FileReader();
const CONTRACT_ADDRESS = "0xof";
fileReader.readAsDataURL(file)
fileReader.onload = () => {
// Converter o string de base64 codificado em um Uint8Array
const uint8Array = Uint8Array.from(atob(fileReader.result), c => c.charCodeAt(0));
// Compactar o Uint8Array using LZMA-JS
LZMA.compress(uint8Array, 9, (result, error) => {
if (error) {
console.log(error);
} else {
// Os dados compactados são Uint8Array, então você precisa convertê-los para um string de base64 codificado
const compressedBase64String = btoa(String.fromCharCode(...result));
const { ethereum } = window;
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner()
const connectedContract = new ethers.Contract(CONTRACT_ADDRESS, abi, signer);
let tx = async() => await connectedContract.addFile(compressedBase64String);
console.log(tx); // Emitir o resultado da chamada do contrato inteligente
}
});
}
fileReader.onerror = (error) => {
console.log(error);
}
};
return (
<>
<h1>Upload file</h1>
<input type="file" onChange={handleChange} />
</>
);
}
export default App;
É tudo o que você precisa para compactar documentos de palavras e armazená-los on chain. Não apenas documentos de palavras, mas praticamente qualquer tipo de arquivo que possa ser compreendido pelo carregador baseado no navegador.
Para recuperar seus arquivos e descompactar você precisará criar um novo método para consultar a função getFiles e loop dos contratos inteligentes através de cada um deles. Dentro de cada iteração você simplesmente chamaria o método abaixo e armazenaria os dados descompactados de qualquer forma que se adequasse ao seu caso de uso:
LZMA.decompress(properties, inStream, outStream, outSize);
Há tantas possibilidades para esta abordagem, mas como sempre, este é apenas um guia para levá-lo a uma base sólida e compreensão, mas não está, de forma alguma, pronto para a produção.
Crie !
Esse artigo foi escrito por Robert McMenemy e traduzido por Fátima Lima. O original pode ser lido aqui.
Top comments (0)