convert download to promises instead of events

This commit is contained in:
MathieuG-P
2022-06-26 23:33:17 +02:00
parent 1e62040ee0
commit a326bc6d61
4 changed files with 124 additions and 106 deletions
+7 -3
View File
@@ -23,11 +23,15 @@ export interface DownloadInfo {
stay?: boolean
}
ipcMain.on('bs-download.start', async (event, args: DownloadInfo) => {
BSInstallerService.getInstance().downloadBsVersion(args);
ipcMain.on('bs-download.start', async (event, request: IpcRequest<DownloadInfo>) => {
BSInstallerService.getInstance().downloadBsVersion(request.args).then(res => {
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: true, data: res});
}).catch(e => {
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: false, data: e});
});
});
ipcMain.on(`bs-download.${DownloadEventType.GUARD_CODE}`, async (event, args) => {
ipcMain.on(`bs-download.${"[2FA]" as DownloadEventType}`, async (event, args) => {
BSInstallerService.getInstance().sendInputProcess(args);
});
+51 -57
View File
@@ -68,10 +68,10 @@ export class BSInstallerService{
}
}
public downloadBsVersion(downloadInfos: DownloadInfo){
if(this.downloadProcess?.connected){ this.utils.ipcSend(`bs-download.${DownloadEventType.ALREADY_DOAWNLOADING}`); return; }
public async downloadBsVersion(downloadInfos: DownloadInfo): Promise<DownloadEvent>{
if(this.downloadProcess?.connected){ return {type: "[AlreadyDownloading]"}; }
const bsVersion = this.bsVersionService.getVersionDetailFromVersionNumber(downloadInfos.bsVersion.BSVersion);
if(!bsVersion){ this.utils.ipcSend(`bs-download.${DownloadEventType.ERROR}`); return; }
if(!bsVersion){ return {type: "[Error]"}; }
this.utils.createFolderIfNotExist(this.installationFolder);
this.downloadProcess = spawn(
@@ -87,53 +87,56 @@ export class BSInstallerService{
{shell: true, cwd: this.installationFolder}
)
this.downloadProcess.stdout.on('data', async (data) => {
log.info("DL PROCESS OUT " ,data.toString());
const matched = (data.toString() as string).match(/(?:\[(.*?)\])\|(?:\[(.*?)\]\|)?(.*?)(?=$|\[)/gm);
if(!matched || !matched.length){ return; }
return await new Promise((resolve, reject) => {
matched.forEach(match => {
const out = match.split("|");
if(out[0] === DownloadEventType.NOT_LOGGED_IN && downloadInfos.password){
this.sendInputProcess(downloadInfos.password);
}
else if(out[0] === DownloadEventType.NOT_LOGGED_IN){
this.downloadProcess.kill();
this.utils.ipcSend(`bs-download.${DownloadEventType.NOT_LOGGED_IN}`, bsVersion);
}
else if(out[0] === DownloadEventType.GUARD_CODE){
this.utils.ipcSend(`bs-download.${DownloadEventType.GUARD_CODE}`);
}
else if(out[0] === DownloadEventType.TWO_FA_CODE){
this.utils.ipcSend(`bs-download.${DownloadEventType.GUARD_CODE}`);
}
else if(out[0] === DownloadEventType.PROGESS || (out[0] === DownloadEventType.VALIDATION && parseFloat(out[1]) < 100)){
this.utils.ipcSend(`bs-download.${DownloadEventType.PROGESS}`, parseFloat(out[1]));
}
else if(out[0] === DownloadEventType.FINISH || (out[0] === DownloadEventType.VALIDATION && parseFloat(out[1]) == 100)){
this.utils.ipcSend(`bs-download.${DownloadEventType.FINISH}`); this.downloadProcess.kill();
}
else if(out[0] === DownloadEventType.ERROR){
this.utils.ipcSend(`bs-download.${DownloadEventType.ERROR}`);
log.error("Download Event, Error", data.toString())
}
this.downloadProcess.stdout.on('data', data => {
const matched = (data.toString() as string).match(/(?:\[(.*?)\])\|(?:\[(.*?)\]\|)?(.*?)(?=$|\[)/gm) ?? [];
matched.forEach(match => {
const out = match.split("|");
if(out[0] === "[Password]" as DownloadEventType && downloadInfos.password){
this.sendInputProcess(downloadInfos.password);
}
else if(out[0] === "[Password]" as DownloadEventType){
this.downloadProcess.kill();
resolve({type: "[Password]", data: bsVersion});
}
else if(out[0] === "[2FA]" as DownloadEventType){
resolve({type: "[2FA]"});
}
else if(out[0] === "[2FA]" as DownloadEventType){
resolve({type: "[2FA]"});
}
else if(out[0] === "[Progress]" as DownloadEventType || (out[0] === "[Validated]" as DownloadEventType && parseFloat(out[1]) < 100)){
this.utils.newIpcSenc(`bs-download.${"[Progress]" as DownloadEventType}`, {success: true, data: parseFloat(out[1])});
}
else if(out[0] === "[Finished]" as DownloadEventType || (out[0] === "[Validated]" as DownloadEventType && parseFloat(out[1]) == 100)){
resolve({type: "[Finished]"});
this.downloadProcess.kill();
}
else if(out[0] === "[Error]" as DownloadEventType){
reject(out);
log.error("Download Event, Error", data.toString());
}
});
})
this.downloadProcess.stdout.on('error', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
reject(err);
});
this.downloadProcess.stderr.on('data', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
reject(err);
});
this.downloadProcess.stderr.on('error', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
reject(err);
});
})
this.downloadProcess.stdout.on('error', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
this.utils.ipcSend(`bs-download.${DownloadEventType.ERROR}`);
});
this.downloadProcess.stderr.on('data', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
this.utils.ipcSend(`bs-download.${DownloadEventType.ERROR}`);
});
this.downloadProcess.stderr.on('error', (err) => {
log.error("BS-DOWNLOAD ERROR", err.toString());
this.utils.ipcSend(`bs-download.${DownloadEventType.ERROR}`);
});
})
}
}
@@ -153,13 +156,4 @@ export interface DownloadEvent{
data?: any,
}
export enum DownloadEventType{
NOT_LOGGED_IN = "[Password]",
GUARD_CODE = "[Guard]",
TWO_FA_CODE = "[2FA]",
PROGESS = "[Progress]",
VALIDATION = "[Validated]",
FINISH = "[Finished]",
ALREADY_DOAWNLOADING = "[AlreadyDownloading]",
ERROR = "[Error]",
}
export type DownloadEventType = "[Password]" | "[Guard]" | "[2FA]" | "[Progress]" | "[Validated]" | "[Finished]" | "[AlreadyDownloading]" | "[Error]";
+51 -42
View File
@@ -1,7 +1,9 @@
import { BehaviorSubject } from 'rxjs';
import { DownloadEvent } from 'main/services/bs-installer.service';
import { BehaviorSubject, distinctUntilChanged, Observable, Subscription } from 'rxjs';
import { IpcResponse } from 'shared/models/ipc-models.model';
import { DownloadInfo } from '../../main/ipcs/bs-download-ipcs';
import { BSVersion } from '../../main/services/bs-version-manager.service'
import { AuthUserService } from './auth-user.service';
import { BSVersionManagerService } from './bs-version-manager.service';
import { IpcService } from './ipc.service';
import { ModalExitCode, ModalService, ModalType } from './modale.service';
@@ -10,55 +12,33 @@ export class BsDownloaderService{
private static instance: BsDownloaderService;
private readonly modalService: ModalService = ModalService.getInsance();
private readonly modalService: ModalService;
private readonly ipcService: IpcService;
private readonly bsVersionManager: BSVersionManagerService = BSVersionManagerService.getInstance();
private readonly bsVersionManager: BSVersionManagerService;
public readonly authService: AuthUserService;
public readonly currentBsVersionDownload$: BehaviorSubject<BSVersion> = new BehaviorSubject(null);
public readonly downloadProgress$: BehaviorSubject<number> = new BehaviorSubject(0);
public readonly selectedBsVersion$: BehaviorSubject<BSVersion> = new BehaviorSubject(null);
public static getInstance(): BsDownloaderService{
if(!BsDownloaderService.instance){ BsDownloaderService.instance = new BsDownloaderService(); }
return BsDownloaderService.instance;
}
private constructor(){
this.asignListerners();
this.ipcService = IpcService.getInstance();
this.modalService = ModalService.getInsance();
this.bsVersionManager = BSVersionManagerService.getInstance();
this.authService = AuthUserService.getInstance();
this.asignListerners();
}
private asignListerners(): void{
window.electron.ipcRenderer.on(`bs-download.[Password]`, async (bsVersion: BSVersion) => {
const res = await this.modalService.openModal(ModalType.STEAM_LOGIN);
if(res.exitCode !== ModalExitCode.COMPLETED){ return; }
if(res.data.stay){ localStorage.setItem("username", res.data.username); }
window.electron.ipcRenderer.sendMessage('bs-download.start', {bsVersion: bsVersion, username: res.data.username, password: res.data.password, stay: res.data.stay} as DownloadInfo)
this.currentBsVersionDownload$.next(bsVersion);
});
window.electron.ipcRenderer.on("bs-download.[Guard]", async () => {
const res = await this.modalService.openModal(ModalType.GUARD_CODE);
if(res.exitCode != ModalExitCode.COMPLETED){ return; }
window.electron.ipcRenderer.sendMessage("bs-download.[Guard]", res.data);
});
window.electron.ipcRenderer.on("bs-download.[Finished]", async () => {
this.downloadProgress$.next(0);
this.currentBsVersionDownload$.next(null);
this.selectedBsVersion$.next(null);
this.bsVersionManager.askInstalledVersions();
});
window.electron.ipcRenderer.on("bs-download.[Progress]", async (progress: number) => {
this.downloadProgress$.next(progress);
});
window.electron.ipcRenderer.on("bs-download.[Error]", async () => {
this.currentBsVersionDownload$.next(null);
this.downloadProgress$.next(0);
this.ipcService.watch<number>("bs-download.[Progress]").pipe(distinctUntilChanged()).subscribe(response => {
this.downloadProgress$.next(response.data);
});
this.currentBsVersionDownload$.subscribe(version => {
@@ -67,23 +47,52 @@ export class BsDownloaderService{
});
}
public async download(bsVersion?: BSVersion): Promise<void>{
if(!bsVersion){ bsVersion = this.selectedBsVersion$.value; }
let username = localStorage.getItem("username");
if(!username){
private resetDownload(): void{
this.currentBsVersionDownload$.next(null);
this.downloadProgress$.next(0);
this.selectedBsVersion$.next(null);
}
public async send2FA(): Promise<IpcResponse<DownloadEvent>>{
const res = await this.modalService.openModal(ModalType.GUARD_CODE);
if(res.exitCode !== ModalExitCode.COMPLETED){ return {success: false}; }
return this.ipcService.send<DownloadEvent>('bs-download.2FA', {args: res.data});
}
public async download(bsVersion: BSVersion): Promise<IpcResponse<DownloadEvent>>{
let promise;
if(!this.authService.sessionExist()){
const res = await this.modalService.openModal(ModalType.STEAM_LOGIN);
if(res.exitCode !== ModalExitCode.COMPLETED){ return; }
if(res.data.stay){ localStorage.setItem("username", res.data.username); }
window.electron.ipcRenderer.sendMessage('bs-download.start', {bsVersion: bsVersion, username: res.data.username, password: res.data.password, stay: res.data.stay} as DownloadInfo);
if(res.exitCode !== ModalExitCode.COMPLETED){ return {success: false}; }
this.authService.setSteamSession(res.data.username, res.data.stay);
promise = this.ipcService.send<DownloadEvent>('bs-download.start', {args: {bsVersion: bsVersion, username: res.data.username, password: res.data.password, stay: res.data.stay}});
}
else{
window.electron.ipcRenderer.sendMessage('bs-download.start', {bsVersion: bsVersion, username: username} as DownloadInfo);
promise = this.ipcService.send<DownloadEvent>('bs-download.start', {args: {bsVersion: bsVersion, username: this.authService.getSteamUsername()}});
}
this.currentBsVersionDownload$.next(bsVersion);
return promise.then(res => {
if(res.success){
if(res.data.type === "[Password]"){
this.authService.deleteSteamSession();
return this.download(bsVersion);
}
else if(res.data.type === "[2FA]"){
return this.send2FA().then(res => {
this.resetDownload();
return res;
});
}
}
this.resetDownload();
return res;
});
}
public get isDownloading(): boolean{
return !!this.currentBsVersionDownload$.value || !!this.downloadProgress$.value;
return !!this.currentBsVersionDownload$.value;
}
public async getInstallationFolder(): Promise<string>{
+15 -4
View File
@@ -5,12 +5,16 @@ export class IpcService {
private static instance: IpcService;
private readonly channelObservables: Map<string, Observable<IpcResponse<unknown>>>;
public static getInstance(): IpcService{
if(!IpcService.instance){ IpcService.instance = new IpcService(); }
return IpcService.instance;
}
private constructor(){}
private constructor(){
this.channelObservables = new Map<string, Observable<IpcResponse<unknown>>>();
}
public send<T>(channel: string, request?: IpcRequest<any>): Promise<IpcResponse<T>>{
if(!request){ request = {args: null, responceChannel: null}; }
@@ -29,12 +33,19 @@ export class IpcService {
window.electron.ipcRenderer.sendMessage(channel, request);
}
public watch<T>(channel: string): Observable<T>{
return new Observable<T>(observer => {
public watch<T>(channel: string): Observable<IpcResponse<T>>{
if(this.channelObservables.has(channel)){ return this.channelObservables.get(channel) as Observable<IpcResponse<T>>; }
const obs = new Observable<IpcResponse<T>>(observer => {
window.electron.ipcRenderer.on(channel, res => {
observer.next(res);
});
});
})
this.channelObservables.set(channel, obs);
return obs;
}
}