[feature] Add notifications for BS download

This commit is contained in:
MathieuG-P
2023-08-05 03:50:04 +02:00
parent a92c65be53
commit 1be3b7af31
10 changed files with 84 additions and 52 deletions
+18 -4
View File
@@ -1,6 +1,7 @@
import { ChildProcessWithoutNullStreams, SpawnOptionsWithoutStdio, spawn } from "child_process";
import { Observable, ReplaySubject, Subscriber, filter, map, share } from "rxjs";
import { DepotDownloaderArgsOptions, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderEventTypes, DepotDownloaderSubTypeOfEventType } from "../../shared/models/depot-downloader.model";
import { DepotDownloaderArgsOptions, DepotDownloaderErrorEvent, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderEventTypes, DepotDownloaderInfoEvent, DepotDownloaderWarningEvent } from "../../shared/models/depot-downloader.model";
import { DownloadEvent } from "main/services/bs-installer.service";
export class DepotDownloader {
@@ -22,7 +23,11 @@ export class DepotDownloader {
subscriber.next(`[Info]|[Start]|${JSON.stringify(options.echoStartData) ?? ""}`);
this.process.stdout.on("data", data => subscriber.next(data.toString()));
this.process.stdout.on("data", data => {
const lines: string[] = data.toString().split("\n");
lines.forEach(line => subscriber.next(line));
});
this.process.stderr.on("error", error => subscriber.error(error));
this.process.on("exit", code => subscriber.complete());
@@ -36,9 +41,18 @@ export class DepotDownloader {
}
public $events(): Observable<DepotDownloaderEvent<unknown>>{
const eventTypesArr = Object.values(DepotDownloaderEventType);
const DepotDownloaderSubTypeOfEventType: {[key in DepotDownloaderEventType]: DepotDownloaderEventTypes[]} = {
[DepotDownloaderEventType.Error]: Object.values(DepotDownloaderErrorEvent),
[DepotDownloaderEventType.Warning]: Object.values(DepotDownloaderWarningEvent),
[DepotDownloaderEventType.Info]: Object.values(DepotDownloaderInfoEvent),
}
return this.processOut$.pipe(map(line => {
console.log(line.toString());
console.log(line);
const matched = (line.toString() as string).match(/(?:\[(.*?)\])\|(?:\[(.*?)\]\|)?(.*?)(?=$|\[)/gm)?.[0] ?? null;
@@ -46,7 +60,7 @@ export class DepotDownloader {
const splitedLine = matched.split("|").map(str => str.trim().replaceAll("[", "").replaceAll("]", "")) as [DepotDownloaderEventType, DepotDownloaderEventTypes, unknown];
if(!Object.values(DepotDownloaderEventType).includes(splitedLine[0]) || !Object.values(DepotDownloaderSubTypeOfEventType[splitedLine[0]]).includes(splitedLine[1])){
if(!eventTypesArr.includes(splitedLine[0] as DepotDownloaderEventType) || !DepotDownloaderSubTypeOfEventType[splitedLine[0]].includes(splitedLine[1])){
return null;
}
+10 -2
View File
@@ -35,6 +35,7 @@ import { useService } from "renderer/hooks/use-service.hook";
import { lastValueFrom } from "rxjs";
import { BsmException } from "shared/models/bsm-exception.model";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { AuthUserService } from "renderer/services/auth-user.service";
export function SettingsPage() {
@@ -51,6 +52,7 @@ export function SettingsPage() {
const playlistsManager = useService(PlaylistsManagerService);
const modelsManager = useService(ModelsManagerService);
const versionLinker = useService(VersionFolderLinkerService);
const authService = useService(AuthUserService);
const { firstColor, secondColor } = useThemeColor();
@@ -67,6 +69,9 @@ export function SettingsPage() {
})
.sort((a, b) => a.text.localeCompare(b.text));
const nav = useNavigate();
const t = useTranslation();
const [themeIdSelected, setThemeIdSelected] = useState(themeItem.find(e => e.value === themeService.getTheme()).id);
const [languageSelected, setLanguageSelected] = useState(languagesItems.find(e => e.value === i18nService.currentLanguage).id);
const [installationFolder, setInstallationFolder] = useState(null);
@@ -75,8 +80,7 @@ export function SettingsPage() {
const [playlistsDeepLinkEnabled, setPlaylistsDeepLinkEnabled] = useState(false);
const [modelsDeepLinkEnabled, setModelsDeepLinkEnabled] = useState(false);
const appVersion = useObservable(ipcService.sendV2<string>("current-version"));
const nav = useNavigate();
const t = useTranslation();
const steamSessionExist = useObservable(authService.sessionExist$);
useEffect(() => {
loadInstallationFolder();
@@ -203,6 +207,10 @@ export function SettingsPage() {
<BsmButton className="inline-block grow-0 bg-transparent sticky h-full w-full top-20 right-20 !m-0 rounded-full p-1" onClick={() => nav(-1)} icon="close" withBar={false} />
</div>
<SettingContainer title="pages.settings.steam.title" description="pages.settings.steam.description">
<BsmButton onClick={() => authService.deleteSteamSession()} className="w-fit px-3 py-[2px] text-white rounded-md" withBar={false} text="pages.settings.steam.logout" typeColor="error" disabled={!steamSessionExist}/>
</SettingContainer>
<SettingContainer title="pages.settings.appearance.title" description="pages.settings.appearance.description">
<div className="relative w-full h-8 bg-light-main-color-1 dark:bg-main-color-1 flex justify-center rounded-md py-1">
<SettingColorChooser color={firstColor} onChange={setFirstColorSetting} />
@@ -43,7 +43,7 @@ export function VersionViewer() {
navigate(`/bs-version/${version.BSVersion}`, { state: version });
};
const openFolder = () => ipcService.sendLazy("bs-version.open-folder", { args: state });
const verifyFiles = () => bsDownloaderService.download(state, true);
const verifyFiles = () => bsDownloaderService.verifyBsVersionFiles(state);
const uninstall = async () => {
const modalCompleted = await modalService.openModal(UninstallModal, state);
+41 -15
View File
@@ -1,7 +1,6 @@
import { DownloadEvent, DownloadInfo } from "main/services/bs-installer.service";
import { BehaviorSubject, Observable, Subscription, identity, lastValueFrom, of, throwError } from "rxjs";
import { distinctUntilChanged, filter, map, take, tap, throttleTime } from "rxjs/operators";
import { IpcResponse } from "shared/models/ipc";
import { DownloadInfo } from "main/services/bs-installer.service";
import { BehaviorSubject, Observable, ReplaySubject, Subscription, lastValueFrom, throwError } from "rxjs";
import { distinctUntilChanged, filter, map, share, take, tap, throttleTime } from "rxjs/operators";
import { BSVersion } from "shared/bs-version.interface";
import { AuthUserService } from "./auth-user.service";
import { BSVersionManagerService } from "./bs-version-manager.service";
@@ -12,7 +11,7 @@ import { ProgressBarService } from "./progress-bar.service";
import { LoginModal } from "renderer/components/modal/modal-types/login-modal.component";
import { GuardModal } from "renderer/components/modal/modal-types/guard-modal.component";
import { LinkOpenerService } from "./link-opener.service";
import { DepotDownloaderErrorEvent, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderInfoEvent, DepotDownloaderSubTypeOfEventType, DepotDownloaderWarningEvent } from "../../shared/models/depot-downloader.model";
import { DepotDownloaderErrorEvent, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderInfoEvent, DepotDownloaderWarningEvent } from "../../shared/models/depot-downloader.model";
import equal from "fast-deep-equal";
import { SteamMobileApproveModal } from "renderer/components/modal/modal-types/steam-mobile-approve-modal.component";
@@ -146,7 +145,10 @@ export class BsDownloaderService {
filter(event => event.subType === DepotDownloaderInfoEvent.Finished),
take(1),
).subscribe(() => {
console.log("show success notification");
if(this.isVerification){
return this.notificationService.notifySuccess({title: "notifications.bs-download.success.titles.verification-finished"});
}
return this.notificationService.notifySuccess({title: "notifications.bs-download.success.titles.download-success"});
}));
return subs;
@@ -154,24 +156,37 @@ export class BsDownloaderService {
private handleWarningEvents(events$: Observable<DepotDownloaderEvent>): Subscription[] {
const subs: Subscription[] = [];
const handledWarnings = Object.values(DepotDownloaderWarningEvent);
subs.push(events$.pipe(
filter(event => handledWarnings.includes(event.subType as DepotDownloaderWarningEvent)),
).subscribe(event => {
this.notificationService.notifyWarning({title: "notifications.types.warning", desc: `notifications.bs-download.warnings.msg.${event.subType}`});
}));
return subs;
}
private hanndleErrorEvents(events$: Observable<DepotDownloaderEvent>): Subscription[] {
const subs: Subscription[] = [];
return subs;
private hanndleErrorEvent(errorEvent: DepotDownloaderEvent) {
const handledErrors = Object.values(DepotDownloaderErrorEvent);
if(handledErrors.includes(errorEvent?.subType as DepotDownloaderErrorEvent)){
return this.notificationService.notifyError({title: "notifications.types.error", desc: `notifications.bs-download.errors.msg.${errorEvent.subType}`});
}
return this.notificationService.notifyError({title: "notifications.types.error", desc: `notifications.bs-download.errors.msg.${DepotDownloaderErrorEvent.Unknown}`});
}
private wrapDownload(download$: Observable<DepotDownloaderEvent>): Observable<DepotDownloaderEvent> {
private wrapDownload(download$: Observable<DepotDownloaderEvent>, silent?: boolean): Observable<DepotDownloaderEvent> {
return new Observable<DepotDownloaderEvent>(sub => {
const downloadSub = download$.subscribe(sub);
const downloadSub = download$.subscribe({next: n => sub.next(n), error: e => sub.error(e), complete: () => sub.complete()});
const subs = [
...this.handleInfoEvents(download$.pipe(filter(event => event.type === DepotDownloaderEventType.Info))),
...this.handleWarningEvents(download$.pipe(filter(event => event.type === DepotDownloaderEventType.Warning))),
...this.hanndleErrorEvents(download$.pipe(filter(event => event.type === DepotDownloaderEventType.Error)))
...this.handleWarningEvents(download$.pipe(filter(event => event.type === DepotDownloaderEventType.Warning), throttleTime(10_000))),
];
return () => {
@@ -180,7 +195,13 @@ export class BsDownloaderService {
}
}).pipe(
tap({error: () => this.authService.deleteSteamSession()})
tap({
error: (e) => {
this.authService.deleteSteamSession();
!silent && this.hanndleErrorEvent(e)
}
}),
share({connector: () => new ReplaySubject(1)})
);
}
@@ -193,7 +214,8 @@ export class BsDownloaderService {
const infos: DownloadInfo = {...downloadInfo, username: this.authService.getSteamUsername()}
return this.wrapDownload(
this.ipcService.sendV2<DepotDownloaderEvent>("auto-download-bs-version", { args: infos })
this.ipcService.sendV2<DepotDownloaderEvent>("auto-download-bs-version", { args: infos }),
true
);
}
@@ -272,6 +294,10 @@ export class BsDownloaderService {
return this.doDownloadBsVersion(version).then(() => version);
}
public verifyBsVersionFiles(version: BSVersion): Promise<BSVersion> {
return this.doDownloadBsVersion(version, true).then(() => version);
}
public verifyBsVersion(version: BSVersion): Promise<BSVersion> {
return this.doDownloadBsVersion(version, true).then(() => version);
}
+4 -7
View File
@@ -35,7 +35,7 @@ export enum DepotDownloaderErrorEvent {
DepotNotFound = "DepotNotFound",
NotCompleted = "NotCompleted",
InvalidManifest = "InvalidManifest",
NoValidKeys = "NoValidKeys",
NoValidKeys = "NoValidKey",
NoManifestCode = "NoManifestCode",
_401 = "401",
_404 = "404",
@@ -46,17 +46,14 @@ export enum DepotDownloaderErrorEvent {
ConnectionError = "ConnectionError",
TokenRejected = "TokenRejected",
LicenceError = "LicenceError",
AccessDenied = "AccessDenied",
Unknown = "Unknown",
}
export enum DepotDownloaderWarningEvent {
ManifestChecksum = "ManifestChecksum",
}
export const DepotDownloaderSubTypeOfEventType = {
[DepotDownloaderEventType.Error]: DepotDownloaderErrorEvent,
[DepotDownloaderEventType.Warning]: DepotDownloaderWarningEvent,
[DepotDownloaderEventType.Info]: DepotDownloaderInfoEvent,
ConnectionTimeout = "ConnectionTimeout",
Unknown = "Unknown",
}
export interface DepotDownloaderArgsOptions {