diff --git a/app/src/Lethalize.ts b/app/src/Lethalize.ts index aaec91b..38a1098 100644 --- a/app/src/Lethalize.ts +++ b/app/src/Lethalize.ts @@ -4,7 +4,7 @@ import { initialize, enable } from '@electron/remote/main'; import * as path from 'path'; import * as fs from 'fs'; -import { AppUpdates, DiscordRPC } from './modules'; +import { AppUpdate, DiscordRPC, IpcMain } from './controllers'; let win: BrowserWindow | null = null; const args = process.argv.slice(1), @@ -70,7 +70,8 @@ try { setTimeout(createWindow, 400); new DiscordRPC().connect(); - new AppUpdates(win).check(); + new IpcMain(win).listen(); + new AppUpdate(win).check(); }); // Quit when all windows are closed. diff --git a/app/src/modules/AppUpdates.ts b/app/src/controllers/appUpdate.ts similarity index 98% rename from app/src/modules/AppUpdates.ts rename to app/src/controllers/appUpdate.ts index 8d62e92..95fa2aa 100644 --- a/app/src/modules/AppUpdates.ts +++ b/app/src/controllers/appUpdate.ts @@ -1,7 +1,7 @@ import { BrowserWindow } from 'electron'; import { autoUpdater, UpdateDownloadedEvent } from 'electron-updater'; -export class AppUpdates { +export class AppUpdate { win: BrowserWindow | null = null; constructor(window: BrowserWindow | null) { diff --git a/app/src/modules/DiscordRPC.ts b/app/src/controllers/discordRpc.ts similarity index 100% rename from app/src/modules/DiscordRPC.ts rename to app/src/controllers/discordRpc.ts diff --git a/app/src/controllers/index.ts b/app/src/controllers/index.ts new file mode 100644 index 0000000..f1ad6d1 --- /dev/null +++ b/app/src/controllers/index.ts @@ -0,0 +1,3 @@ +export * from './appUpdate'; +export * from './ipcMain'; +export * from './discordRpc'; diff --git a/app/src/controllers/ipc/Download.ts b/app/src/controllers/ipc/Download.ts new file mode 100644 index 0000000..eda1288 --- /dev/null +++ b/app/src/controllers/ipc/Download.ts @@ -0,0 +1,79 @@ +import { BrowserWindow, IpcMainEvent } from 'electron'; +import fs from 'fs'; +import axios from 'axios'; + +import { calculateProgress, temporaryLocation } from '../../modules'; + +export async function DownloadFile( + event: IpcMainEvent, + fileUrl: string, + savePath: string, + win: BrowserWindow | null +) { + // Create a temporary location for our saved files + const tmpLoc = temporaryLocation(savePath); + + try { + // Download the file + const file = await axios({ + method: 'get', + url: fileUrl, + responseType: 'stream', + }); + + // Write the file into the temporary location + const write = fs.createWriteStream(tmpLoc); + file.data.pipe(write); + + // Keep track of download progress + let receivedBytes = 0; + file.data.on('data', (chunk: any[]) => { + // How many bytes have we gotten so far? + receivedBytes += chunk.length; + + // Calculate the progress as a percentage + const progress = calculateProgress( + receivedBytes, + parseInt(file.headers['Content-Length'] as string) + ); + + // Set the browser downloading state + win?.setProgressBar(progress / 100); + + // Send updates to the client + event.sender.send('download-progress', { + fileUrl, + savePath, + progress, + finished: false, + }); + }); + + // Once the file is complete + write.on('finish', () => { + event.sender.send('download-progress', { + fileUrl, + savePath, + progress: 100, + finished: true, + }); + }); + + // Handle any stream errors + write.on('error', (err) => { + event.sender.send('download-error', { + fileUrl, + savePath, + error: err.message, + }); + + fs.unlink(tmpLoc, () => {}); // Delete the temporary file on error + }); + } catch (error: any) { + event.sender.send('download-error', { + fileUrl, + savePath, + error: error.message, + }); + } +} diff --git a/app/src/controllers/ipc/index.ts b/app/src/controllers/ipc/index.ts new file mode 100644 index 0000000..4436f19 --- /dev/null +++ b/app/src/controllers/ipc/index.ts @@ -0,0 +1 @@ +export * from './Download'; diff --git a/app/src/controllers/ipcMain.ts b/app/src/controllers/ipcMain.ts new file mode 100644 index 0000000..8dd5de8 --- /dev/null +++ b/app/src/controllers/ipcMain.ts @@ -0,0 +1,24 @@ +import { BrowserWindow, ipcMain } from 'electron'; + +import { DownloadFile } from './ipc/Download'; + +export class IpcMain { + win: BrowserWindow | null = null; + + constructor(window: BrowserWindow | null) { + this.win = window; + } + + listen(): void { + // Create a download file listener + ipcMain.on( + 'download-file', + async (event, fileUrl, savePath) => + await DownloadFile(event, fileUrl, savePath, this.win) + ); + + // Create the extract file listener + + // Create the update file listener + } +} diff --git a/app/src/modules/calculateProgress.ts b/app/src/modules/calculateProgress.ts new file mode 100644 index 0000000..117f8fb --- /dev/null +++ b/app/src/modules/calculateProgress.ts @@ -0,0 +1,4 @@ +// Calculate a percentage of how much progress is left. +export function calculateProgress(receivedBytes: number, totalBytes: number) { + return Math.round((receivedBytes / totalBytes) * 100); +} diff --git a/app/src/modules/index.ts b/app/src/modules/index.ts index bf35547..885e373 100644 --- a/app/src/modules/index.ts +++ b/app/src/modules/index.ts @@ -1,2 +1,2 @@ -export * from './AppUpdates'; -export * from './DiscordRPC'; +export * from './temporaryLocation'; +export * from './calculateProgress'; diff --git a/app/src/modules/temporaryLocation.ts b/app/src/modules/temporaryLocation.ts new file mode 100644 index 0000000..5474b5a --- /dev/null +++ b/app/src/modules/temporaryLocation.ts @@ -0,0 +1,7 @@ +import os from 'os'; +import path from 'path'; + +// Create a temporary file location for downloaded files +export function temporaryLocation(fileName: string) { + return path.join(os.tmpdir(), fileName); +}