Skip to content

Commit

Permalink
Merge pull request #30 from d0rich/frontend-files-download
Browse files Browse the repository at this point in the history
Complete files download
  • Loading branch information
d0rich authored Nov 4, 2023
2 parents 3420e8f + 98936c5 commit 6993627
Show file tree
Hide file tree
Showing 21 changed files with 319 additions and 406 deletions.
315 changes: 75 additions & 240 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions ton-drive-backend/src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@ export class AppController {
const status = await this.tonStorageService.prepareDownload(bagId)
if (status.ready) {
return {
ready: true,
...status,
fileName: path.parse(status.filePath).base
}
} else {
return {
ready: false
}
return status
}
}

Expand Down
67 changes: 43 additions & 24 deletions ton-drive-backend/src/ton-storage.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import * as os from 'os';
import * as path from 'path';
import * as process from 'process';

interface PrepareDownloadResponse {
ready: boolean
exists: boolean
filePath?: string
_output?: string | object
}

@Injectable()
export class TonStorageService {

Expand Down Expand Up @@ -38,33 +45,45 @@ export class TonStorageService {
}
}

async prepareDownload(bagId: string): Promise<{ ready: boolean, filePath?: string }> {
const cliRes = await this.execCliCommand(`\"get ${bagId} --json\"`)
.catch(res => {
if (res.data) {
return res.data
} else {
return Promise.reject(res)
}
async prepareDownload(bagId: string): Promise<PrepareDownloadResponse> {
try {
const cliRes = await this.execCliCommand(`\"get ${bagId} --json\"`)
const cliResParsed = JSON.parse(cliRes);
// if bag not found, try to add it
if (cliRes.match(/.+No such torrent/) !== null) {
const output = await this.execCliCommand(`\"add-by-hash ${bagId}\"`)
return {
ready: false,
exists: false,
_output: output
}
)
if (cliRes.match(/.+No such torrent/) !== null) {
await this.execCliCommand(`\"add-by-hash ${bagId}\"`)
return {
ready: false
}
}
const cliResParsed = JSON.parse(cliRes);
if (cliResParsed["torrent"]?.completed) {
const rootPath: string = cliResParsed["torrent"]['root_dir']
const fileName: string = cliResParsed["files"][0]['name']
return {
ready: true,
filePath: path.join(rootPath, fileName).toString()
};
} else {
// if bag is found and ready to download
if (cliResParsed["torrent"]?.completed) {
const rootPath: string = cliResParsed["torrent"]['root_dir']
const fileName: string = cliResParsed["files"][0]['name']
return {
ready: true,
exists: true,
filePath: path.join(rootPath, fileName).toString(),
_output: cliResParsed
};
}
// in any other case
return {
ready: false
ready: false,
exists: true,
_output: cliResParsed
}
} catch (e) {
if (e.data) {
return {
ready: false,
exists: false,
_output: e.data
}
} else {
return Promise.reject(e)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions ton-drive-frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/drive.svg" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TON Drive</title>
<title>BigFiles</title>
</head>
<body>
<div id="root"></div>
Expand Down
2 changes: 1 addition & 1 deletion ton-drive-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"dependencies": {
"@orbs-network/ton-access": "^2.2.2",
"@tanstack/react-query": "^4.24.4",
"@tonconnect/ui-react": "^0.0.14",
"@tonconnect/ui-react": "^2.0.0-beta.4",
"@twa-dev/sdk": "^6.4.2",
"buffer": "^6.0.3",
"is-mobile": "^3.1.1",
Expand Down
Binary file added ton-drive-frontend/public/icon-black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ton-drive-frontend/public/icon-transparent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ton-drive-frontend/public/icon-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions ton-drive-frontend/public/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion ton-drive-frontend/public/tonconnect-manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"url": "https://bigfiles.cloud",
"name": "BigFiles",
"iconUrl": "https://bigfiles.cloud/drive.svg"
"iconUrl": "https://bigfiles.cloud/icon.svg"
}

This file was deleted.

44 changes: 44 additions & 0 deletions ton-drive-frontend/src/features/file/api/createFileContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Sender, TonClient } from "ton";
import {Address, Cell} from "ton-core";
import tonDrive, {storageProviderAddress} from "../../../services/FilesService";
import { apiConfig } from "../../../shared/config/api";

export interface CreateFileContractOptions {
file: File;
bagId: string;
tonClient: {
client: TonClient | undefined;
};
sender: Sender;
wallet: string;
}

// TODO: implement without calling backend
export async function createFileContract({file, bagId, tonClient, sender, wallet}: CreateFileContractOptions) {
if (!tonClient || !sender || !wallet) {
throw new Error("Wallet not connected")
}
const tonDriveService = tonDrive(tonClient.client!!, sender)
const contractParams = new URLSearchParams()
contractParams.append('bagId', bagId)
contractParams.append('providerAddress', storageProviderAddress.toRawString())
// TODO: use POST method body instead of query params
const contractResponse = await fetch(new URL('contracts?' + contractParams.toString(), apiConfig.baseUrl).toString(), {
method: 'POST'
})
const contractFile = await contractResponse.arrayBuffer()

const base64 = btoa(new Uint8Array(contractFile)
.reduce((data, byte) => data + String.fromCharCode(byte), ''))

const msgBody = Cell.fromBase64(base64)
const slice = msgBody.beginParse()
const opQueryId = slice.loadUint(32 + 64)
const torrentHash = slice.loadRef().hash().toString('hex')
console.log(`HEX: ${torrentHash}`, BigInt(`0x${torrentHash}`))
const userCollection = tonDriveService.userCollection(Address.parse(wallet))
return userCollection.createContract(msgBody, {
name: file.name,
size: file.size
})
}
5 changes: 5 additions & 0 deletions ton-drive-frontend/src/features/file/api/getDownloadLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { apiConfig } from "../../../shared/config/api"

export function getDownloadLink(bagId: string, fileName: string): string {
return new URL(`download/${bagId}/${fileName}`, apiConfig.baseUrl).toString()
}
16 changes: 16 additions & 0 deletions ton-drive-frontend/src/features/file/api/prepareDownload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { apiConfig } from "../../../shared/config/api";

export type PrepareDownloadResponse = {
ready: boolean
exists: boolean
fileName: string | null
_output?: string | object
}

export async function prepareDownload(bagId: string): Promise<PrepareDownloadResponse> {
const resRaw = await fetch(new URL(`prepareDownload?bagId=${bagId}`, apiConfig.baseUrl).toString(), {
method: 'POST'
})
const res: PrepareDownloadResponse = await resRaw.json()
return res
}
47 changes: 4 additions & 43 deletions ton-drive-frontend/src/features/file/api/uploadFile.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,14 @@
import { Sender, TonClient } from "ton";
import {Address, Cell} from "ton-core";
import tonDrive, {storageProviderAddress} from "../../../services/FilesService";

export interface FileUploadOptions {
file: File;
tonClient: {
client: TonClient | undefined;
};
sender: Sender;
wallet: string;
}

export async function uploadFile({ file, tonClient, sender, wallet }: FileUploadOptions) {
const host = 'https://api.bigfiles.cloud'
import { apiConfig } from "../../../shared/config/api";

export async function uploadFile(file: File) {
const formData = new FormData()
formData.append('file', file)

if (!tonClient || !sender || !wallet) {
console.log("Wallet not connected")
return;
}
const tonDriveService = tonDrive(tonClient.client!!, sender)
const response = await fetch(`${host}/upload`, {
const response = await fetch(new URL('upload', apiConfig.baseUrl), {
method: 'POST',
body: formData
})

const {bagId} = await response.json() as {bagId: string}
const contractParams = new URLSearchParams()
contractParams.append('bagId', bagId)
contractParams.append('providerAddress', storageProviderAddress.toRawString())
// TODO: use POST method body instead of query params
const contractResponse = await fetch(new URL('/contracts?' + contractParams.toString(), host).toString(), {
method: 'POST'
})
const contractFile = await contractResponse.arrayBuffer()

const base64 = btoa(new Uint8Array(contractFile)
.reduce((data, byte) => data + String.fromCharCode(byte), ''))

const msgBody = Cell.fromBase64(base64)
const slice = msgBody.beginParse()
const opQueryId = slice.loadUint(32 + 64)
const torrentHash = slice.loadRef().hash().toString('hex')
console.log(`HEX: ${torrentHash}`, BigInt(`0x${torrentHash}`))
const userCollection = tonDriveService.userCollection(Address.parse(wallet))
return userCollection.createContract(msgBody, {
name: file.name,
size: file.size
})
return bagId
}
Loading

0 comments on commit 6993627

Please sign in to comment.