rflog_parser/
info_line.rs1use anyhow::{bail, Context, Result};
2use regex::Regex;
3
4const LOG_MARK: &str = "Riverfall Launcher Log Format";
5
6macro_rules! get_element {
7 ($i:ident,$n:tt,$ii:tt,$t:ty) => {
8 $i.get($ii)
9 .context(anyhow::anyhow!("Unable to get element {} (№{}) of RFLogMark", $n, $ii))?
10 .as_str()
11 .parse::<$t>().ok().context(anyhow::anyhow!("Unable to cast element {} (№{}, &str) to type {}", $n, $ii, stringify!($t))) };
13}
14
15#[derive(Debug, Clone)]
16pub struct Version {
17 pub major: u16,
18 pub minor: u16,
19 pub patch: u16
20}
21
22impl ToString for Version {
23 fn to_string(&self) -> String {
24 format!("{}.{}.{}", self.major, self.minor, self.patch)
25 }
26}
27
28#[derive(Debug, Clone)]
29pub struct RFLogInfoLine {
30 pub launcher_version: Version,
31 pub player_nick: String,
32 pub game_client: String,
33 pub os: String,
34 pub os_version: String
35}
36
37pub(crate) fn parse(line: &str) -> Result<RFLogInfoLine> {
38 let re = Regex::new(r"([^:]+):\[(\d+)\.(\d+)\.(\d+);([^;]+);([^;]+);([^;]+);([^\]]+)\]").unwrap();
39
40 if let Some(caps) = re.captures(line) {
41 let log_mark = caps.get(1).context("Invalid format: Unable to get RFLogMark")?.as_str();
42
43 if log_mark != LOG_MARK {
44 bail!("Invalid format: Unable to get RFLogMark");
45 }
46
47 let major = get_element!(caps, "Version (major)", 2, u16)?;
48 let minor = get_element!(caps, "Version (minor)", 3, u16)?;
49 let patch = get_element!(caps, "Version (patch)", 4, u16)?;
50 let player_nick = get_element!(caps, "Username", 5, String)?;
51 let os = get_element!(caps, "OS", 6, String)?;
52 let os_version = get_element!(caps, "OS Version", 7, String)?;
53 let game_client = get_element!(caps, "Game Client", 8, String)?;
54
55 Ok(
56 RFLogInfoLine {
57 launcher_version: Version { major, minor, patch },
58 player_nick,
59 game_client,
60 os,
61 os_version
62 }
63 )
64 } else {
65 bail!("Invalid format: Unable to get RFLogMark")
66 }
67}