Merge pull request #255 from Zagrios/feature/start-steam-if-not-running-and-bs-automatically-after

[feature] Steam now launch automatically if it not running then BS launch just after
This commit is contained in:
MathieuG-P
2023-06-25 22:30:52 +02:00
committed by GitHub
15 changed files with 108 additions and 58 deletions
+1 -1
View File
@@ -362,7 +362,7 @@
"steam":{
"steam-launching":{
"title": "Steam startet!",
"description": "Abhängig von deiner Konfiguration kann es einige Zeit dauern, bis Steam gestartet wird."
"description": "Beat Saber wird automatisch nach Steam gestartet."
}
},
"custom-version": {
+1 -1
View File
@@ -362,7 +362,7 @@
"steam":{
"steam-launching":{
"title": "Steam is launching!",
"description": "Steam may take some time to launch depending on your configuration."
"description": "Beat Saber will automatically launch after Steam."
}
},
"custom-version": {
+1 -1
View File
@@ -361,7 +361,7 @@
"steam":{
"steam-launching":{
"title": "¡Steam se está iniciando!",
"description": "Steam puede tardar un poco en iniciarse dependiendo de tu configuración."
"description": "Beat Saber se lanzará automáticamente después de Steam."
}
},
"custom-version": {
+1 -1
View File
@@ -361,7 +361,7 @@
"steam":{
"steam-launching":{
"title": "Steam se lance !",
"description": "Steam peut mettre quelque temps à se lancer selon votre configuration."
"description": "Beat Saber se lancera automatiquement après Steam."
}
},
"custom-version": {
-1
View File
@@ -21,7 +21,6 @@ import { LocalModelsManagerService } from './services/additional-content/local-m
import { APP_NAME } from './constants';
import { BSLauncherService } from './services/bs-launcher.service';
import { IpcRequest } from 'shared/models/ipc';
import { MSModelType } from '../shared/models/models/model-saber.model';
const isDebug = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';
+18 -2
View File
@@ -10,6 +10,8 @@ import { pathExist } from "../helpers/fs.helpers";
import { rename } from "fs/promises";
import log from "electron-log";
import { timer } from "rxjs";
import { NotificationService } from "./notification.service";
import { NotificationType } from "../../shared/models/notification/notification.model";
export class BSLauncherService{
@@ -19,6 +21,7 @@ export class BSLauncherService{
private readonly steamService: SteamService;
private readonly oculusService: OculusService;
private readonly localVersionService: BSLocalVersionService;
private readonly notification: NotificationService;
private bsProcess: ChildProcessWithoutNullStreams;
@@ -32,6 +35,7 @@ export class BSLauncherService{
this.steamService = SteamService.getInstance();
this.oculusService = OculusService.getInstance();
this.localVersionService = BSLocalVersionService.getInstance();
this.notification = NotificationService.getInstance();
}
private getSteamVRPath(): Promise<string>{
@@ -55,10 +59,22 @@ export class BSLauncherService{
return this.bsProcess?.connected || this.utilsService.taskRunning(BS_EXECUTABLE) === true;
}
// TODO : Rework with shortcuts implementation
public async launch(launchOptions: LauchOption): Promise<LaunchResult>{
if(launchOptions.version.oculus && this.oculusService.oculusRunning() === false){ return "OCULUS_NOT_RUNNING" }
if(!launchOptions.version.oculus && this.steamService.steamRunning() === false){ return "STEAM_NOT_RUNNING" }
if(this.isBsRunning() === true){ return "BS_ALREADY_RUNNING" }
if(launchOptions.version.oculus && this.oculusService.oculusRunning() === false){ return "OCULUS_NOT_RUNNING" }
const steamRunning = await this.steamService.steamRunning().catch(() => true); // True if error (error not not means that steam is not running)
if(!launchOptions.version.oculus && !steamRunning){
this.notification.notifyRenderer({
title: "notifications.steam.steam-launching.title",
desc: "notifications.steam.steam-launching.description",
type: NotificationType.SUCCESS,
});
await this.steamService.openSteam().catch(log.error);
}
const cwd = await this.localVersionService.getVersionPath(launchOptions.version);
const exePath = path.join(cwd, BS_EXECUTABLE);
+1 -1
View File
@@ -44,7 +44,7 @@ export class IpcService {
this.windows.getWindow(window)?.webContents?.send(channel, response);
}
public connectStream(channel: IpcChannel, window: AppWindow, observable: Observable<unknown>): void{
private connectStream(channel: IpcChannel, window: AppWindow, observable: Observable<unknown>): void{
observable.subscribe(data => {
this.send(channel, window, data);
}, error => {
+16 -1
View File
@@ -1,6 +1,8 @@
import { Notification } from "electron";
import { SystemNotificationOptions } from "shared/models/notification/system-notification.model";
import { UtilsService } from "./utils.service";
import { Notification } from "electron";
import { Notification as NotificationRenderer } from "../../shared/models/notification/notification.model";
import { IpcService } from "./ipc.service";
export class NotificationService {
@@ -14,9 +16,11 @@ export class NotificationService {
private readonly APP_ICON: string;
private readonly utils: UtilsService;
private readonly ipc: IpcService;
private constructor(){
this.utils = UtilsService.getInstance();
this.ipc = IpcService.getInstance();
this.APP_ICON = this.utils.getAssetsPath("favicon.ico");
}
@@ -24,4 +28,15 @@ export class NotificationService {
new Notification({...options, icon: this.APP_ICON}).show();
}
// TODO : Make actions work
public notifyRenderer(notification: Omit<NotificationRenderer, "actions">){
try{
this.ipc.send("show-notification", "index.html", notification);
}
catch(e){
console.error(e);
}
}
}
+31 -7
View File
@@ -25,9 +25,20 @@ export class SteamService{
return SteamService.instance;
}
public steamRunning(): boolean | null{
return this.utils.taskRunning('steam.exe');
}
public async getActiveUser(): Promise<number>{
const res = await regedit.promisified.list(["HKCU\\Software\\Valve\\Steam\\ActiveProcess"]);
const keys = res?.["HKCU\\Software\\Valve\\Steam\\ActiveProcess"];
if(!keys?.exists){ throw "Key \"HKCU\\Software\\Valve\\Steam\\ActiveProcess\" not exist"; }
return (keys.values?.ActiveUser.value || undefined) as number;
}
public steamRunning(): Promise<boolean>{
return this.getActiveUser()
.then(userId => !!userId)
.catch(e => {log.error(e); throw e})
}
public async getSteamPath(): Promise<string>{
@@ -71,12 +82,25 @@ export class SteamService{
}
}
public openSteam(): Promise<boolean>{
public openSteam(): Promise<void>{
const process = spawn("start", ["steam://open/games"], {shell: true});
return new Promise(resolve => {
process.on("exit", () => resolve(true));
process.on("error", () => resolve(false));
process.on("error", log.error);
return new Promise(async (resolve, reject) => {
// Every 3 seconds check if steam is running
const interval = setInterval(async () => {
const steamRunning = await this.steamRunning().catch(() => false);
if(!steamRunning){ return; }
clearInterval(interval);
resolve();
}, 3000);
// If steam is not running after 60 seconds, reject
setTimeout(() => {
clearInterval(interval);
reject("Unable to open steam");
}, 60_000);
});
}
@@ -1,4 +1,4 @@
import { NotificationResult, NotificationType, Notification } from "renderer/services/notification.service"
import { NotificationResult, NotificationType, Notification } from "../../../shared/models/notification/notification.model"
import { motion, PanInfo } from "framer-motion"
import { BsmImage } from "../shared/bsm-image.component";
import BeatRunningImg from "../../../../assets/images/apngs/beat-running.png";
+3 -14
View File
@@ -1,9 +1,10 @@
import { LauchOption, LaunchResult } from "shared/models/bs-launch";
import { BSVersion } from 'shared/bs-version.interface';
import { IpcService } from "./ipc.service";
import { NotificationResult, NotificationService } from "./notification.service";
import { NotificationService } from "./notification.service";
import { BsDownloaderService } from "./bs-downloader.service";
import { BehaviorSubject } from "rxjs";
import { NotificationResult } from "shared/models/notification/notification.model";
export class BSLauncherService{
@@ -39,7 +40,7 @@ export class BSLauncherService{
}
// TODO : Rework with shortcuts implementation
public launch(version: BSVersion, oculus: boolean, desktop: boolean, debug: boolean, additionalArgs?: string[]): Promise<NotificationResult|string>{
const lauchOption: LauchOption = {debug, oculus, desktop, version, additionalArgs};
if(this.launchState$.value){ return this.notificationService.notifyError({title: "notifications.bs-launch.errors.titles.BS_ALREADY_RUNNING"}); }
@@ -59,18 +60,6 @@ export class BSLauncherService{
});
}
if(res.data){
// TODO : too much nesting here, need refactor
if(res.data === "STEAM_NOT_RUNNING"){
return new Promise(async resolve => {
const notif = await this.notificationService.notifyError({title: `notifications.bs-launch.errors.titles.${res.data}`, actions: [{id: "0", title: `notifications.bs-launch.errors.actions.${res.data}`}]});
if(notif === "0"){
await this.ipcService.send<boolean>("open-steam");
const lastNotif = await this.notificationService.notifySuccess({title: "notifications.steam.steam-launching.title", desc: "notifications.steam.steam-launching.description"});
resolve(lastNotif);
}
resolve(notif)
})
}
return this.notificationService.notifyError({title: `notifications.bs-launch.errors.titles.${res.data}`});
}
return this.notificationService.notifyError({title: res.data || res.error.title});
@@ -9,9 +9,10 @@ import { Mod, ModInstallProgression } from "shared/models/mods";
import { ProgressionInterface } from "shared/models/progress-bar";
import { IpcService } from "./ipc.service";
import { ModalExitCode, ModalService } from "./modale.service";
import { NotificationService, NotificationType } from "./notification.service";
import { NotificationType } from "../../shared/models/notification/notification.model";
import { OsDiagnosticService } from "./os-diagnostic.service";
import { ProgressBarService } from "./progress-bar.service";
import { NotificationService } from "./notification.service";
export class BsModsManagerService {
+1
View File
@@ -35,6 +35,7 @@ export class IpcService{
window.electron.ipcRenderer.sendMessage(channel, request);
}
// Also need a rework
public watch<T>(channel: string): Observable<IpcResponse<T>>{
if(this.channelObservables.has(channel)){ return this.channelObservables.get(channel) as Observable<IpcResponse<T>>; }
+6 -26
View File
@@ -1,6 +1,7 @@
import { BehaviorSubject } from "rxjs";
import { SystemNotificationOptions } from "shared/models/notification/system-notification.model";
import { IpcService } from "./ipc.service";
import { NotificationResult, NotificationType, Notification } from "../../shared/models/notification/notification.model";
export class NotificationService{
@@ -20,6 +21,11 @@ export class NotificationService{
private constructor(){
this.ipc = IpcService.getInstance();
this.notifications$ = new BehaviorSubject<ResolvableNotification[]>([]);
// TODO : Make actions work and adapt with "watch" remork
this.ipc.watch<Notification>("show-notification").subscribe(notification => {
this.notify(notification as any as Notification);
});
}
public notify(notification: Notification): Promise<NotificationResult|string>{
@@ -64,32 +70,6 @@ export class NotificationService{
}
export interface Notification {
title: string,
type?: NotificationType
desc?: string,
actions?: NotificationAction[],
duration?: number,
}
export enum NotificationType {
SUCCESS = 0,
WARNING = 1,
ERROR = 2,
INFO = 3,
}
export interface NotificationAction {
id: string,
title: string,
cancel?: boolean
}
export enum NotificationResult {
NO_CHOICE = "no_choice",
CLOSE = "close",
}
interface ResolvableNotification{
id: string,
resolver: (value: NotificationResult|string) => void,
@@ -0,0 +1,25 @@
export interface Notification {
title: string,
type?: NotificationType
desc?: string,
actions?: NotificationAction[],
duration?: number,
}
export enum NotificationType {
SUCCESS = 0,
WARNING = 1,
ERROR = 2,
INFO = 3,
}
export interface NotificationAction {
id: string,
title: string,
cancel?: boolean
}
export enum NotificationResult {
NO_CHOICE = "no_choice",
CLOSE = "close",
}