use regex::Regex;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[typeshare]
#[derive(Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub enum ProtocolVerb {
InstallMod,
InstallURL,
InstallPreRelease,
InstallZip,
RunGame,
Unknown,
}
impl ProtocolVerb {
pub fn parse(raw_str: &str) -> Self {
match raw_str {
"install-mod" => Self::InstallMod,
"install-url" => Self::InstallURL,
"install-prerelease" => Self::InstallPreRelease,
"install-zip" => Self::InstallZip,
"run-game" => Self::RunGame,
_ => Self::Unknown,
}
}
}
#[allow(rustdoc::bare_urls)]
#[typeshare]
#[derive(Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ProtocolPayload {
pub verb: ProtocolVerb,
pub payload: String,
}
impl ProtocolPayload {
fn failed() -> Self {
Self {
verb: ProtocolVerb::Unknown,
payload: "".to_string(),
}
}
pub fn parse(raw_str: &str) -> Self {
let re = Regex::new(r"^owmods://([^/]+)/(.+)$").unwrap();
if let Some(matches) = re.captures(raw_str) {
let verb = matches
.get(1)
.map(|m| ProtocolVerb::parse(m.as_str()))
.unwrap_or(ProtocolVerb::Unknown);
let payload = matches.get(2).map(|m| m.as_str());
if let Some(payload) = payload {
Self {
verb,
payload: payload.to_string(),
}
} else {
Self::failed()
}
} else {
Self::failed()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_protocol_payload() {
let payload = ProtocolPayload::parse("owmods://install-mod/Bwc9876.TimeSaver");
assert!(matches!(payload.verb, ProtocolVerb::InstallMod));
assert_eq!(payload.payload, "Bwc9876.TimeSaver");
let payload = ProtocolPayload::parse("owmods://install-url/https://example.com/Mod.zip");
assert!(matches!(payload.verb, ProtocolVerb::InstallURL));
assert_eq!(payload.payload, "https://example.com/Mod.zip");
let payload = ProtocolPayload::parse("owmods://install-zip//home/user/Downloads/Mod.zip");
assert!(matches!(payload.verb, ProtocolVerb::InstallZip));
assert_eq!(payload.payload, "/home/user/Downloads/Mod.zip");
let payload = ProtocolPayload::parse("owmods://install-prerelease/Raicuparta.NomaiVR");
assert!(matches!(payload.verb, ProtocolVerb::InstallPreRelease));
assert_eq!(payload.payload, "Raicuparta.NomaiVR");
}
#[test]
fn test_protocol_payload_invalid() {
let payload = ProtocolPayload::parse("ow://asdf");
assert!(matches!(payload.verb, ProtocolVerb::Unknown));
assert_eq!(payload.payload, "");
let payload = ProtocolPayload::parse("owmods://install-mod");
assert!(matches!(payload.verb, ProtocolVerb::Unknown));
assert_eq!(payload.payload, "");
let payload = ProtocolPayload::parse("owmods://install-url");
assert!(matches!(payload.verb, ProtocolVerb::Unknown));
assert_eq!(payload.payload, "");
let payload = ProtocolPayload::parse("owmods://install-zip");
assert!(matches!(payload.verb, ProtocolVerb::Unknown));
assert_eq!(payload.payload, "");
let payload = ProtocolPayload::parse("owmods://install-prerelease");
assert!(matches!(payload.verb, ProtocolVerb::Unknown));
assert_eq!(payload.payload, "");
}
}