Skip to content

Commit

Permalink
Fixed downloading not shown instantly
Browse files Browse the repository at this point in the history
  • Loading branch information
gafert committed Mar 21, 2021
1 parent 87de33f commit 6061389
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 293 deletions.
3 changes: 3 additions & 0 deletions main_renderer/app/home/simulation/simulation.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const routes: Routes = [
imports: [RouterModule.forChild(routes), CommonModule, MatCheckboxModule, TippyModule,
FormsModule, VirtualScrollerModule, MatButtonModule, MatRippleModule, MatDialogModule],
providers: [],
exports: [
VarDirective
]
})
export class SimulationModule {

Expand Down
176 changes: 0 additions & 176 deletions main_renderer/app/services/toolchain-downloader.service.ts

This file was deleted.

167 changes: 167 additions & 0 deletions main_renderer/app/settings/services/toolchain-downloader.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import * as https from 'https';
import { DataKeys, DataService } from '../../services/data.service';
import { authorize } from '../../utils/google-drive-auth';
import * as fs from 'fs';
import * as zlib from 'zlib';
import * as path from 'path';
import * as tar from 'tar-fs';
import * as electron from 'electron';
import { HttpClient } from '@angular/common/http';

const app = electron.remote.app;

export enum ToolchainDownEnum {
DOWNLOADING,
UNZIPPING,
DOWNLOADED,
WAS_DOWNLOADED,
ERROR,
NOT_DOWNLOADED
}

export class ToolchainDownState {
state: ToolchainDownEnum;
reason: string | number;

constructor(state: ToolchainDownEnum, reason: string | number) {
this.state = state;
this.reason = reason;
}
}

@Injectable({
providedIn: 'root'
})
export class ToolchainDownloaderService {
public toolchainDownloadPath;
public state: BehaviorSubject<ToolchainDownState> = new BehaviorSubject<ToolchainDownState>(new ToolchainDownState(ToolchainDownEnum.NOT_DOWNLOADED, ''));
private isWin = process.platform === 'win32';
private isMac = process.platform === 'darwin';
private isLinux = process.platform === 'linux';
private downloadPath;
private toolchainDownloadZipFile;
private toolchainFolder = 'riscv64-toolchain';

constructor(private dataService: DataService, private http: HttpClient) {
this.downloadPath = path.join(app.getPath('userData'), 'downloads');

// Make new directory if it does not exist
fs.mkdir(this.downloadPath, null, () => null);

this.toolchainDownloadZipFile = path.join(this.downloadPath, 'riscv.tar.gz');
this.toolchainDownloadPath = path.join(this.downloadPath, this.toolchainFolder, 'bin');

dataService.data[DataKeys.TOOLCHAIN_DOWNLOADED].subscribe((value) => {
if (value === true) {
this.state.next(new ToolchainDownState(ToolchainDownEnum.WAS_DOWNLOADED, this.toolchainDownloadPath));
}
});
}

public downloadToolchain() {
this.removeToolchain();
authorize().then(jwtClient => {
this.getNameOfZipFromGoogleDrive(jwtClient, this.getQueryName()).then((item: any) => {
this.downloadZipFromGoogleDrive(jwtClient, item).then(() => {
this.unzip().catch((reason => {
this.state.next(new ToolchainDownState(ToolchainDownEnum.ERROR, reason));
}));
}).catch((reason => {
this.state.next(new ToolchainDownState(ToolchainDownEnum.ERROR, reason));
}));
}).catch((reason => {
this.state.next(new ToolchainDownState(ToolchainDownEnum.ERROR, reason));
}));
});
}

private getQueryName() {
let platform;
if (this.isMac) {
platform = 'mac';
} else if (this.isLinux) {
platform = 'linux';
} else if (this.isWin) {
platform = 'win';
}

if (!platform) this.state.next(new ToolchainDownState(ToolchainDownEnum.ERROR, 'Unsupported platform'));
this.state.next(new ToolchainDownState(ToolchainDownEnum.DOWNLOADING, 0));

return 'name contains \'riscv64-toolchain-' + platform + '\'';
}

private getNameOfZipFromGoogleDrive(jwtClient, query) {
return this.http.get(`https://www.googleapis.com/drive/v3/files?q=${query}`, {
headers: { 'Authorization': 'Bearer ' + jwtClient.credentials.access_token },
reportProgress: true
}).toPromise().then((list: any) => {
return list.files[0].id;
})
}

private downloadZipFromGoogleDrive(jwtClient, item): Promise<any> {
return new Promise((resolve, reject) => {
https.request(`https://www.googleapis.com/drive/v3/files/${item}?alt=media`,
{ headers: { 'Authorization': 'Bearer ' + jwtClient.credentials.access_token } },
(res => {
const writeStream = fs.createWriteStream(this.toolchainDownloadZipFile);
const len = parseInt(res.headers['content-length'], 10);
let downloaded = 0;
res.on('data', (chunk) => {
downloaded += chunk.length;
this.state.next(new ToolchainDownState(ToolchainDownEnum.DOWNLOADING,
Number((downloaded / len * 100).toFixed(0))));
writeStream.write(chunk);
console.log("Downloading", this.state.value.state);
});
res.on('end', () => resolve());
})).on('error', (error) => {
console.log('Error downloading file', error.message);
reject(error.message);
}).end();
});
}

private unzip(): Promise<any> {
return new Promise(((resolve, reject) => {
this.state.next(new ToolchainDownState(ToolchainDownEnum.UNZIPPING, ''));
fs.createReadStream(this.toolchainDownloadZipFile).pipe(zlib.createGunzip()).pipe(tar.extract(this.downloadPath)).on('finish', (err) => {
if (err) {
this.state.next(new ToolchainDownState(ToolchainDownEnum.ERROR, err));
reject(err);
return;
}
// Delete downloaded zip after it was unpacked
fs.unlink(this.toolchainDownloadZipFile, () => null);

this.dataService.data[DataKeys.TOOLCHAIN_DOWNLOADED].next(true);
this.state.next(new ToolchainDownState(ToolchainDownEnum.DOWNLOADED, this.toolchainDownloadPath));
resolve();
});
}))
}

public removeToolchain() {
this.deleteFolderRecursive(path.join(this.downloadPath, this.toolchainFolder));
console.log('Removed toolchain ' + this.downloadPath + '/' + this.toolchainFolder);
this.state.next(new ToolchainDownState(ToolchainDownEnum.NOT_DOWNLOADED, 'Removed Toolchain from ' + this.downloadPath + '/' + this.toolchainFolder));
this.dataService.data[DataKeys.TOOLCHAIN_DOWNLOADED].next(false);
}

private deleteFolderRecursive(folder) {
if (fs.existsSync(folder)) {
fs.readdirSync(folder).forEach((file, index) => {
const curPath = path.join(folder, file);
if (fs.lstatSync(curPath).isDirectory()) { // recurse
this.deleteFolderRecursive(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(folder);
}
}
}
Loading

0 comments on commit 6061389

Please sign in to comment.