Skip to content

Commit

Permalink
This fixes mutliple downloads
Browse files Browse the repository at this point in the history
  • Loading branch information
abrahamYG committed Jun 20, 2019
1 parent 57dc639 commit 42d1067
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 38 deletions.
52 changes: 48 additions & 4 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ function createWindow () {
/*mainWindow.webContents.openDevTools({
mode:"detach"
});*/
mainWindow.on('closed', function () {
mainWindow.on('closed', () => {
mainWindow = null;
})



}
Expand All @@ -75,13 +74,13 @@ function onReady(){

app.on('ready', onReady)

app.on('window-all-closed', function () {
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
})

app.on('activate', function () {
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
Expand Down Expand Up @@ -109,6 +108,51 @@ ipcMain.on(msg.DOWNLOAD_MAP, async (event, arg) => {

})

ipcMain.on(msg.UNZIP_CAMPAIGN,async (event, {source, zipPath, installPath}) =>{
yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => {
if (err) {
throw err;
}
zipfile.readEntry();
zipfile.on("entry", (entry) => {
console.log(entry.fileName);
if (/\/$/.test(entry.fileName)) {
zipfile.readEntry();
} else {
const mod = source.files.find(
mod => entry.fileName === mod.fileEntry
);
if (mod) {
const entryBasePath = installPath;
const entryBaseName = mod.destination;
const entryFullPath = path.join(
entryBasePath,
entryBaseName
);
console.log("entryFullPath", entryFullPath);
fs.ensureDirSync(path.dirname(entryFullPath));
const ds = fs.createWriteStream(entryFullPath);
zipfile.openReadStream(entry, function(
err,
readStream
) {
if (err) throw err;
readStream.on("end", function() {
zipfile.readEntry();
});
readStream.pipe(ds);
});
} else {
zipfile.readEntry();
}
}
});
zipfile.once("end", function() {
zipfile.close();
});
});
});

ipcMain.on(msg.DOWNLOAD_CAMPAIGN, async (event, campaign) => {
let timer = Date.now();
const {maps, mods,installDir} = campaign;
Expand Down
10 changes: 9 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@types/debug": "^4.1.3",
"@types/download": "^6.2.4",
"@types/electron": "^1.6.10",
"@types/fs-extra": "^7.0.0",
"@types/lodash": "^4.14.130",
"@types/react": "^16.8.13",
"@types/react-dom": "^16.8.3",
Expand Down
2 changes: 1 addition & 1 deletion src/classes/Campaign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export default class Campaign {
static downloadCampaign = (campaign:ICampaign) => {
const installDir = Campaign.getCampaignsInstallDir();
Downloader.pushCampaign(campaign);
ipcRenderer.send(msg.DOWNLOAD_CAMPAIGN, {...campaign, installDir:Campaign.getCampaignsInstallDir()});
//ipcRenderer.send(msg.DOWNLOAD_CAMPAIGN, {...campaign, installDir:Campaign.getCampaignsInstallDir()});

}
static playCampaign = (campaign:ICampaign,mapIndex:number=-1) => {
Expand Down
225 changes: 196 additions & 29 deletions src/classes/Downloader.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,203 @@
import { ICampaign, ISC2Component } from "./Campaign";
import Campaign, { ICampaign, ISC2Component } from "./Campaign";
import download = require("download");
import _ from "lodash";
import electron, { remote, ipcRenderer } from "electron";
import path from "path";
import fs from "fs-extra";
import { Progress } from "got";
import yauzl from "yauzl";
import msg from "../constants/ipcmessages";
import store from "../configureStore";
import { setCampaign } from "../store/campaign/actions";

const app: Electron.App = remote.require("electron").app;
interface ISource {
url?:string,
format?:string,
files?:Array<ISC2Component>,
progress?:number
url?: string;
name: string;
format?: string;
files?: Array<ISC2Component>;
progress?: number;
campaignId?: string;
}

interface IDownload {
sources: ISource[];
progress: number;
}
interface IDownloadSet {
[key: string]: IDownload;
}

export default class Downloader {
static downloads:ISource[] = [];
static progress: number = 0;
static pushCampaign(campaign:ICampaign){
let sources: {[key: string]: ISource} = {};
const mods = [...campaign.mods, ...campaign.maps];
mods.forEach(mod =>{
const {source, sourceFormat} = mod;
sources = {
[source]: {
format: sourceFormat,
files:[]
},
...sources
}
this.downloads.push({ url: source, format:sourceFormat, progress:0})

if(sources[source].format === "zip") {
sources[source].files.push(mod);
}
else{
sources[mod.source].files = [mod];
static downloads: IDownloadSet;
static progress: number = 0;
static pushCampaign(campaign: ICampaign) {
console.log("pushCampaign");
let sourcesbyKey: { [key: string]: ISource } = {};
const mods: Array<ISC2Component> = [...campaign.mods, ...campaign.maps];
const sources = _.uniqWith<ISource>(
mods.map(
({ source: url, sourceFormat: format }): ISource => ({
url,
name: path.basename(url),
format,
files: mods.filter(mod => mod.source === url),
progress: 0,
campaignId: campaign.id
})
),
_.isEqual
);

console.log("Downloader.pushCampaign urls", sources);
this.downloads = {
...this.downloads,
[campaign.id]: { sources, progress: 0 }
};
console.log("Downloader downloads", this.downloads);
const promises = sources.map((source, index) =>
this.downloadSource(source, index)
);
Promise.all(promises).then(data => {
console.log("downloads have finished for", campaign.id);
});
}
static async downloadSource(source: ISource, index: number) {
let timer = Date.now();

const tempPath = path.join(
app.getPath("temp"),
app.getName(),
source.campaignId
);
let tempName = source.name;
let tempFullName = path.join(tempPath, tempName);
fs.ensureDirSync(tempPath);

const dl = download(source.url)
.on("response", response => {
console.log(response);
tempName = path.basename(response.url);
tempFullName = path.join(tempPath, tempName);
const ws = fs.createWriteStream(tempFullName);
ws.once("close", () => {
console.log("close streamm");
if (source.format === "zip") {
this.extractContents(source, tempFullName);
} else {
this.copyMaps(source.files[0], tempFullName);
}
});
dl.pipe(ws);
})
.on("downloadProgress", (progress: Progress) => {
if (Date.now() - timer > 1000 || progress.percent >= 1) {
this.onDownloadProgress(source, index, progress);
timer = Date.now();
}
});
return dl;
}
static copyMaps(mod: ISC2Component, originPath: string) {
const destBaseDir = Campaign.getCampaignsInstallDir();
const destBasename = mod.destination;
const destPath = path.join(destBaseDir, destBasename);
console.log("nozip: ", destPath);
fs.ensureDirSync(path.dirname(destPath));
fs.copyFileSync(originPath, destPath);
}
static extractContents(source: ISource, zipPath: string) {
console.log("extractContents zipPath", zipPath);
console.log("extractContents yazul", yauzl);
const installPath = Campaign.getCampaignsInstallDir();
ipcRenderer.send(msg.UNZIP_CAMPAIGN, {
source,
zipPath,
installPath
});
//YAUZL doesnt seem to work within the renderer part of electron, hmph!
/*
yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => {
if (err) {
throw err;
}
});
}
}
zipfile.readEntry();
zipfile.on("entry", (entry: yauzl.Entry) => {
console.log(entry.fileName);
if (/\/$/.test(entry.fileName)) {
zipfile.readEntry();
} else {
const mod = source.files.find(
mod => entry.fileName === mod.fileEntry
);
if (mod) {
const entryBasePath = Campaign.getCampaignsInstallDir();
const entryBaseName = mod.destination;
const entryFullPath = path.join(
entryBasePath,
entryBaseName
);
console.log("entryFullPath", entryFullPath);
fs.ensureDirSync(path.dirname(entryFullPath));
const ds = fs.createWriteStream(entryFullPath);
zipfile.openReadStream(entry, function(
err,
readStream
) {
if (err) throw err;
readStream.on("end", function() {
zipfile.readEntry();
});
readStream.pipe(ds);
});
} else {
zipfile.readEntry();
}
}
});
zipfile.once("end", function() {
zipfile.close();
});
});
*/
}
static onDownloadProgress(
source: ISource,
index: number,
progress: Progress
) {
const newSource = {
...source,
progress: progress.percent
};
const { campaignId } = source;
const downloads = this.downloads;
const sources = Object.assign([...downloads[campaignId].sources], {
[index]: newSource
});

const download: IDownload = {
...downloads[campaignId],
sources,
progress:
sources
.map(src => src.progress)
.reduce(
(total, progress, index, array) => total + progress,
0.0
) / sources.length
};
this.downloads = {
...this.downloads,
[campaignId]: download
};
console.log(campaignId, download.progress);
const campaigns = store.getState().campaignState.campaigns;
const campaignIndex = campaigns.findIndex(c => c.id === campaignId);
const campaign = {
...campaigns[campaignIndex],
progress:download.progress
};
store.dispatch(setCampaign(campaign,campaignIndex));
}
}
1 change: 1 addition & 0 deletions src/constants/ipcmessages.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ declare interface IPCMessages {
DOWNLOAD_CAMPAIGN_FINISH:string;
PLAY_CAMPAIGN:string;
PLAY_MAP:string;
UNZIP_CAMPAIGN:string;

}

Expand Down
1 change: 1 addition & 0 deletions src/constants/ipcmessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = {
DOWNLOAD_MAP: "downloadMap",
DOWNLOAD_MAP_STATUS: "downloadMapProgress",
DOWNLOAD_CAMPAIGN: "downloadCampaign",
UNZIP_CAMPAIGN: "unzipCampaign",
DOWNLOAD_CAMPAIGN_STATUS: "downloadCampaignProgress",
DOWNLOAD_CAMPAIGN_FINISH: "downloadCampaignProgress",
PLAY_CAMPAIGN: "playCampaign",
Expand Down
Loading

0 comments on commit 42d1067

Please sign in to comment.