use anyhow::Result;
use std::{fmt, path::Path, str::FromStr};
#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use windows::{
DiscordInstall, InstallCandidateReport, LaunchPlan, discover_install, inspect_candidates,
is_process_running,
};
#[cfg(not(windows))]
mod unsupported {
use super::DiscordChannel;
use anyhow::{Result, bail};
use std::path::Path;
use tokio::process::Child;
#[derive(Debug)]
pub struct DiscordInstall;
#[derive(Debug)]
pub struct InstallCandidateReport;
pub struct LaunchPlan;
impl DiscordInstall {
pub fn source(&self) -> &str {
""
}
pub fn channel(&self) -> DiscordChannel {
DiscordChannel::Stable
}
pub fn root(&self) -> &Path {
Path::new("")
}
pub fn app_dir(&self) -> &Path {
Path::new("")
}
pub fn update_exe(&self) -> Option<&Path> {
None
}
pub fn exe_path(&self) -> &Path {
Path::new("")
}
pub fn exe_name(&self) -> &str {
""
}
}
impl LaunchPlan {
pub fn new(_install: DiscordInstall, _proxy_url: String) -> Self {
Self
}
pub fn describe(&self) -> String {
"this MVP currently supports Windows launch plans only".to_string()
}
pub fn spawn(&self) -> Result<Child> {
bail!("this MVP currently supports Windows launch plans only")
}
}
pub fn discover_install(
_channel: DiscordChannel,
_override_dir: Option<&Path>,
) -> Result<DiscordInstall> {
bail!("this MVP currently supports Windows Discord discovery only")
}
pub fn inspect_candidates(
_channel: DiscordChannel,
_override_dir: Option<&Path>,
) -> Vec<InstallCandidateReport> {
Vec::new()
}
pub fn is_process_running(_exe_name: &str) -> bool {
false
}
}
#[cfg(not(windows))]
pub use unsupported::{
DiscordInstall, InstallCandidateReport, LaunchPlan, discover_install, inspect_candidates,
is_process_running,
};
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum DiscordChannel {
Stable,
Canary,
Ptb,
Development,
}
impl DiscordChannel {
pub fn valid_values() -> &'static [&'static str] {
&["stable", "canary", "ptb", "development"]
}
pub fn install_dir_name(self) -> &'static str {
match self {
Self::Stable => "Discord",
Self::Canary => "DiscordCanary",
Self::Ptb => "DiscordPTB",
Self::Development => "DiscordDevelopment",
}
}
pub fn exe_candidates(self) -> &'static [&'static str] {
match self {
Self::Stable => &["Discord.exe"],
Self::Canary => &["DiscordCanary.exe"],
Self::Ptb => &["DiscordPTB.exe"],
Self::Development => &["DiscordDevelopment.exe"],
}
}
}
impl FromStr for DiscordChannel {
type Err = anyhow::Error;
fn from_str(value: &str) -> Result<Self> {
match value.trim().to_ascii_lowercase().as_str() {
"stable" | "discord" => Ok(Self::Stable),
"canary" | "discordcanary" => Ok(Self::Canary),
"ptb" | "discordptb" => Ok(Self::Ptb),
"development" | "dev" | "discorddevelopment" => Ok(Self::Development),
other => anyhow::bail!("unsupported Discord channel: {other}"),
}
}
}
impl fmt::Display for DiscordChannel {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = match self {
Self::Stable => "stable",
Self::Canary => "canary",
Self::Ptb => "ptb",
Self::Development => "development",
};
formatter.write_str(value)
}
}
#[allow(dead_code)]
pub fn discover(_channel: DiscordChannel, _override_dir: Option<&Path>) -> Result<DiscordInstall> {
discover_install(_channel, _override_dir)
}