game_manager_lib/commands/
launcher.rs1use crate::commands::games::get_game_by_id;
2use crate::database::AppState;
3use crate::errors::AppError;
4use crate::services::playtime::{has_official_playtime_source, watch_game};
5use crate::utils::launcher::{resolve_launch, LaunchResolution};
6use serde::Serialize;
7use std::path::PathBuf;
8use std::process::Command;
9use tauri::{AppHandle, Manager};
10use tauri_plugin_opener::OpenerExt;
11
12#[derive(Debug, Serialize)]
13#[serde(tag = "kind", rename_all = "camelCase")]
14pub enum LaunchOutcome {
15 Launched,
16 OpenedLauncher { installed: bool },
17 OpenedStore,
18 Unavailable,
19}
20
21#[tauri::command]
22pub async fn launch_game(
23 app: AppHandle,
24 game_id: String,
25 launcher_path_override: Option<String>,
26) -> Result<LaunchOutcome, AppError> {
27 let state = app.state::<AppState>();
28 let game = get_game_by_id(state, game_id.clone())?
29 .ok_or_else(|| AppError::NotFound(format!("Jogo não encontrado: {game_id}")))?;
30
31 let outcome = match resolve_launch(&game, launcher_path_override.as_deref()) {
32 LaunchResolution::Protocol(url) => {
33 app.opener()
34 .open_url(url, None::<&str>)
35 .map_err(|e| AppError::LaunchError(e.to_string()))?;
36 LaunchOutcome::Launched
37 }
38 LaunchResolution::Executable(path) => {
39 Command::new(&path).spawn()?;
40 LaunchOutcome::Launched
41 }
42 LaunchResolution::Launcher(path) => {
43 Command::new(&path).spawn()?;
44 LaunchOutcome::OpenedLauncher {
45 installed: game.installed,
46 }
47 }
48 LaunchResolution::Store(url) => {
49 app.opener()
50 .open_url(url, None::<&str>)
51 .map_err(|e| AppError::LaunchError(e.to_string()))?;
52 LaunchOutcome::OpenedStore
53 }
54 LaunchResolution::Unavailable => LaunchOutcome::Unavailable,
55 };
56
57 let should_track = matches!(
58 outcome,
59 LaunchOutcome::Launched | LaunchOutcome::OpenedLauncher { installed: true }
60 ) && !has_official_playtime_source(&game.platform);
61
62 if should_track {
63 if let Some(exe_path) = game.executable_path.as_ref().map(PathBuf::from) {
64 let install_path = game.install_path.as_ref().map(PathBuf::from);
65 watch_game(app.clone(), game.id.clone(), exe_path, install_path);
66 }
67 }
68
69 Ok(outcome)
70}