diff --git a/package.json b/package.json index 1de3715..db5c18a 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ }, "license": "MIT", "dependencies": { + "@ethersproject/experimental": "^5.7.0", "bip39": "^3.0.4", "buffer-split": "^1.0.0", "colors-cli": "^1.0.28", @@ -42,7 +43,7 @@ "install-mac-arm": "yarn pkg && cp ./bin/git3-cli-macos-arm64 /usr/local/bin/git-remote-git3", "pkg": "yarn run build && pkg .", "build:git3": "esbuild ./src/git3/index.js --bundle --platform=node --target=es6 --outfile=dist/git3.js", - "pkg:git3": "yarn build:git3 && pkg dist/git3.js --output bin/git3 && sudo cp bin/git3 /usr/local/bin/git3", + "pkg:git3": "yarn build:git3 && pkg dist/git3.js --output bin/git3 && cp bin/git3 /usr/local/bin/git3", "clean": "rm -rf ./dist ./bin" }, "devDependencies": { diff --git a/src/git/git.ts b/src/git/git.ts index eff5575..37c4a20 100644 --- a/src/git/git.ts +++ b/src/git/git.ts @@ -131,9 +131,12 @@ class Git { let present = Array.from(this.refs.values()) present.push(...Array.from(this.pushed.values())) let objects = GitUtils.listObjects(src, present) + let pendings = [] for (let obj of objects) { - await this.putObject(obj) + pendings.push(this.putObject(obj)) } + await Promise.all(pendings) + let sha = GitUtils.refValue(src) let err = await this.wirteRef(sha, dst, force) if (!err) { diff --git a/src/storage/ETHStorage.ts b/src/storage/ETHStorage.ts index 01755d4..4ef5641 100644 --- a/src/storage/ETHStorage.ts +++ b/src/storage/ETHStorage.ts @@ -1,30 +1,36 @@ import { Ref, Status, Storage } from "./storage" -import { callContractMethod } from "../wallet/index" +import { getWallet } from "../wallet/index" +import { ethers, Signer } from "ethers" +import { NonceManager } from "@ethersproject/experimental" +const abi = '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes","name":"name","type":"bytes"}],"name":"countChunks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"delRef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"}],"name":"download","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"listRefs","outputs":[{"components":[{"internalType":"bytes20","name":"hash","type":"bytes20"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct Git3.refData[]","name":"list","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"nameToRefInfo","outputs":[{"internalType":"bytes20","name":"hash","type":"bytes20"},{"internalType":"uint96","name":"index","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"refs","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refund1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"}],"name":"remove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes20","name":"refHash","type":"bytes20"}],"name":"setRef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"name","type":"bytes"}],"name":"size","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"storageManager","outputs":[{"internalType":"contract IFileOperator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upload","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint256","name":"chunkId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"uploadChunk","outputs":[],"stateMutability":"payable","type":"function"}]' export class ETHStorage implements Storage { repoURI: string + wallet: Signer + contract: ethers.Contract + provider: ethers.providers.JsonRpcProvider constructor(repoURI: string) { this.repoURI = repoURI + this.wallet = getWallet() + this.provider = new ethers.providers.JsonRpcProvider('https://galileo.web3q.io:8545') + this.wallet = this.wallet.connect(this.provider) + this.wallet = new NonceManager(this.wallet) + this.contract = new ethers.Contract('0xb940B75947F64C9fe0b4B2b6c56Fc9DEF03bBb5F', abi, this.wallet) } async download(path: string): Promise<[Status, Buffer]> { - const buffer = await callContractMethod({ - method: 'download', - path, - file: null, - sha: null - }) - return [Status.SUCCEED, buffer] + const res = await this.contract.download(Buffer.from(path)) + const buffer = Buffer.from(res[0].slice(2), 'hex') + console.error(`=== download file ${path} result ===`) + console.error(buffer.toString('utf-8')) + return [Status.SUCCEED, buffer] } async upload(path: string, file: Buffer): Promise { - await callContractMethod({ - method: 'upload', - path, - file, - sha: null - }) + const uploadResult = await this.contract.upload(Buffer.from(path), file) + console.error(`=== upload file ${path} result ===`) + console.error(uploadResult) return Status.SUCCEED } @@ -33,22 +39,16 @@ export class ETHStorage implements Storage { } async listRefs(): Promise { - const result = await callContractMethod({ - method: 'listRefs', - path: null, - file: null, - sha: null - }) - return result + const res: string[][] = await this.contract.listRefs() + let refs = res.map(i => ({ + ref: i[1], + sha: i[0].slice(2) + })) + return refs } async setRef(path: string, sha: string): Promise { - await callContractMethod({ - method: 'setRef', - path, - file: null, - sha - }) + await this.contract.setRef(path, '0x' + sha) return Status.SUCCEED } diff --git a/src/wallet/abi.js b/src/wallet/abi.js deleted file mode 100644 index 9dfbd00..0000000 --- a/src/wallet/abi.js +++ /dev/null @@ -1,260 +0,0 @@ -export default [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "name", - "type": "bytes" - } - ], - "name": "countChunks", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "name": "delRef", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "path", - "type": "bytes" - } - ], - "name": "download", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "listRefs", - "outputs": [ - { - "components": [ - { - "internalType": "bytes20", - "name": "hash", - "type": "bytes20" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "internalType": "struct Git3.refData[]", - "name": "list", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "name": "nameToRefInfo", - "outputs": [ - { - "internalType": "bytes20", - "name": "hash", - "type": "bytes20" - }, - { - "internalType": "uint96", - "name": "index", - "type": "uint96" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "refs", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "val", - "type": "uint256" - } - ], - "name": "refund", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "refund1", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "path", - "type": "bytes" - } - ], - "name": "remove", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "bytes20", - "name": "refHash", - "type": "bytes20" - } - ], - "name": "setRef", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "name", - "type": "bytes" - } - ], - "name": "size", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "storageManager", - "outputs": [ - { - "internalType": "contract IFileOperator", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "path", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upload", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "path", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "chunkId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "uploadChunk", - "outputs": [], - "stateMutability": "payable", - "type": "function" - } -] \ No newline at end of file diff --git a/src/wallet/index.js b/src/wallet/index.js deleted file mode 100644 index ca8bb92..0000000 --- a/src/wallet/index.js +++ /dev/null @@ -1,58 +0,0 @@ -import { mkdirSync, readFileSync, existsSync, statSync } from "fs" -import { ethers } from 'ethers' -import parse from 'parse-git-config' -import abi from './abi.js' - -// path -> /ab/123ab3123 -export async function callContractMethod({ - method = 'upload', - path, - file, - sha -}) { - const wallet = 'default' - const keyPath = process.env.HOME + "/.git3/keys" - mkdirSync(keyPath, { recursive: true }) - - const content = readFileSync(`${keyPath}/${wallet}`).toString() - const [walletType, key] = content.split('\n') - const provider = new ethers.providers.JsonRpcProvider('https://galileo.web3q.io:8545'); - - let etherWallet = walletType === 'privateKey' - ? new ethers.Wallet(key) - : ethers.Wallet.fromMnemonic(key) - - etherWallet = etherWallet.connect(provider) - const contract = new ethers.Contract('0xb940B75947F64C9fe0b4B2b6c56Fc9DEF03bBb5F', abi, etherWallet); - const pathBuffer = path ? Buffer.from(path) : '' - - if (method === 'upload') { - const uploadResult = await contract.upload(pathBuffer, file) - console.error(`=== upload file ${path} result ===`) - console.error(uploadResult) - } - - if (method === 'download') { - const res = await contract.download(pathBuffer) - const buf = Buffer.from(res[0].slice(2), 'hex') - - console.error(`=== download file ${path} result ===`) - console.error(buf.toString('utf-8')) - return buf - } - - if (method === 'setRef') { - const res = await contract.setRef(path, '0x' + sha) - } - - if (method === 'listRefs') { - const res = await contract.listRefs() - let refs = res.map(i => ({ - ref: i[1], - sha: i[0].slice(2) - })) - - // refs = refs.concat([{ ref: 'HEAD', sha: 'refs/heads/main' }]) - return refs - } -} \ No newline at end of file diff --git a/src/wallet/index.ts b/src/wallet/index.ts new file mode 100644 index 0000000..6268634 --- /dev/null +++ b/src/wallet/index.ts @@ -0,0 +1,17 @@ +import { mkdirSync, readFileSync } from "fs" +import { ethers } from 'ethers' + +export function getWallet(): ethers.Wallet { + const wallet = 'default' + const keyPath = process.env.HOME + "/.git3/keys" + mkdirSync(keyPath, { recursive: true }) + + const content = readFileSync(`${keyPath}/${wallet}`).toString() + const [walletType, key] = content.split('\n') + + let etherWallet = walletType === 'privateKey' + ? new ethers.Wallet(key) + : ethers.Wallet.fromMnemonic(key) + + return etherWallet +} diff --git a/yarn.lock b/yarn.lock index 8b952e4..935ebb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -223,6 +223,15 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/transactions" "^5.7.0" +"@ethersproject/experimental@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/experimental/-/experimental-5.7.0.tgz#9759639434d37beaedfd8acab6f3af7db246b92d" + integrity sha512-DWvhuw7Dg8JPyhMbh/CNYOwsTLjXRx/HGkacIL5rBocG8jJC0kmixwoK/J3YblO4vtcyBLMa+sV74RJZK2iyHg== + dependencies: + "@ethersproject/web" "^5.7.0" + ethers "^5.7.0" + scrypt-js "3.0.1" + "@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" @@ -795,7 +804,7 @@ eth-ens-namehash@^2.0.8: idna-uts46-hx "^2.3.1" js-sha3 "^0.5.7" -ethers@^5.7.2: +ethers@^5.7.0, ethers@^5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==