mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature] Add notifications for BS download
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user