mirror of
https://codeberg.org/icewind/tf-log-parser.git
synced 2026-06-03 18:24:09 +02:00
subject postprocessing
This commit is contained in:
parent
ca61f4ea6a
commit
747ee7d1a9
10 changed files with 2970 additions and 22 deletions
|
|
@ -1,12 +1,31 @@
|
|||
use crate::raw_event::RawSubject;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
use steamid_ng::SteamID;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Ord, PartialOrd)]
|
||||
pub enum Team {
|
||||
Red,
|
||||
Blue,
|
||||
}
|
||||
|
||||
impl Team {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Team::Red => "Red",
|
||||
Team::Blue => "Blue",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Team {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.as_str().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Team {
|
||||
type Err = ();
|
||||
|
||||
|
|
@ -20,7 +39,7 @@ impl FromStr for Team {
|
|||
}
|
||||
|
||||
/// Optimized subject id
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Ord, PartialOrd)]
|
||||
pub enum SubjectId {
|
||||
Player(u8),
|
||||
Team(Team),
|
||||
|
|
@ -40,3 +59,52 @@ impl From<&RawSubject<'_>> for SubjectId {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SubjectData {
|
||||
Player {
|
||||
name: String,
|
||||
user_id: u8,
|
||||
steam_id: SteamID,
|
||||
team: Team,
|
||||
},
|
||||
Team(Team),
|
||||
System(String),
|
||||
Console,
|
||||
World,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SubjectError {
|
||||
#[error("Invalid user id")]
|
||||
InvalidUserId,
|
||||
#[error("Invalid steam id")]
|
||||
InvalidSteamId,
|
||||
#[error("Invalid team name")]
|
||||
InvalidTeam,
|
||||
}
|
||||
|
||||
impl TryFrom<&RawSubject<'_>> for SubjectData {
|
||||
type Error = SubjectError;
|
||||
|
||||
fn try_from(raw: &RawSubject<'_>) -> Result<Self, Self::Error> {
|
||||
Ok(match raw {
|
||||
RawSubject::Player {
|
||||
name,
|
||||
user_id,
|
||||
steam_id,
|
||||
team,
|
||||
} => SubjectData::Player {
|
||||
name: name.to_string(),
|
||||
user_id: user_id.parse().map_err(|_| SubjectError::InvalidUserId)?,
|
||||
steam_id: SteamID::from_steam3(steam_id)
|
||||
.map_err(|_| SubjectError::InvalidSteamId)?,
|
||||
team: team.parse().map_err(|_| SubjectError::InvalidTeam)?,
|
||||
},
|
||||
RawSubject::Team(team) => SubjectData::Team(team.parse().unwrap()),
|
||||
RawSubject::System(name) => SubjectData::System(name.to_string()),
|
||||
RawSubject::Console => SubjectData::Console,
|
||||
RawSubject::World => SubjectData::World,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
39
src/lib.rs
39
src/lib.rs
|
|
@ -1,8 +1,11 @@
|
|||
use crate::common::{SubjectData, SubjectError, SubjectId};
|
||||
use crate::module::EventHandler;
|
||||
use crate::raw_event::RawEvent;
|
||||
use crate::raw_event::{RawEvent, RawSubject};
|
||||
use chrono::{DateTime, Utc};
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Index;
|
||||
use thiserror::Error;
|
||||
|
||||
mod common;
|
||||
|
|
@ -26,12 +29,41 @@ impl<Handler: EventHandler> Debug for Error<Handler> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Handler: EventHandler> From<SubjectError> for Error<Handler> {
|
||||
fn from(e: SubjectError) -> Self {
|
||||
Error::Malformed(e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Handler: EventHandler> From<nom::error::Error<&'_ str>> for Error<Handler> {
|
||||
fn from(e: nom::error::Error<&str>) -> Self {
|
||||
Error::Malformed(e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SubjectMap(BTreeMap<SubjectId, SubjectData>);
|
||||
|
||||
impl Index<SubjectId> for SubjectMap {
|
||||
type Output = SubjectData;
|
||||
|
||||
fn index(&self, index: SubjectId) -> &Self::Output {
|
||||
self.0
|
||||
.get(&index)
|
||||
.expect("subject id created without matching subject data")
|
||||
}
|
||||
}
|
||||
|
||||
impl SubjectMap {
|
||||
pub fn insert(&mut self, raw: &RawSubject) -> Result<SubjectId, SubjectError> {
|
||||
let id = raw.into();
|
||||
if !self.0.contains_key(&id) {
|
||||
self.0.insert(id, raw.try_into()?);
|
||||
}
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_with_handler<Handler: EventHandler>(
|
||||
log: &str,
|
||||
) -> Result<Handler::Output, Error<Handler>> {
|
||||
|
|
@ -43,6 +75,7 @@ pub fn parse_with_handler<Handler: EventHandler>(
|
|||
let mut handler = Handler::default();
|
||||
|
||||
let mut start_time: Option<DateTime<Utc>> = None;
|
||||
let mut subjects = SubjectMap::default();
|
||||
|
||||
for event_res in events {
|
||||
let event = event_res?;
|
||||
|
|
@ -56,10 +89,10 @@ pub fn parse_with_handler<Handler: EventHandler>(
|
|||
}
|
||||
};
|
||||
handler
|
||||
.handle(match_time, (&event.subject).into(), &event)
|
||||
.handle(match_time, subjects.insert(&event.subject)?, &event)
|
||||
.map_err(Error::HandlerError)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(handler.finish())
|
||||
Ok(handler.finish(&subjects))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,50 @@
|
|||
use crate::common::SubjectId;
|
||||
use crate::common::{SubjectData, SubjectId};
|
||||
use crate::module::EventHandler;
|
||||
use crate::raw_event::{RawEvent, RawEventType};
|
||||
use crate::SubjectMap;
|
||||
use std::convert::Infallible;
|
||||
use steamid_ng::SteamID;
|
||||
|
||||
pub struct ChatMessage {
|
||||
struct BareChatMessage {
|
||||
pub time: u32,
|
||||
pub subject: SubjectId,
|
||||
pub message: String,
|
||||
pub chat_type: ChatType,
|
||||
}
|
||||
|
||||
pub struct ChatMessage {
|
||||
pub time: u32,
|
||||
pub name: String,
|
||||
pub steam_id: SteamID,
|
||||
pub message: String,
|
||||
pub chat_type: ChatType,
|
||||
}
|
||||
|
||||
impl ChatMessage {
|
||||
fn from_bare(bare: BareChatMessage, subjects: &SubjectMap) -> Self {
|
||||
let (name, steam_id) = match &subjects[bare.subject] {
|
||||
SubjectData::Player { name, steam_id, .. } => (name.clone(), steam_id.clone()),
|
||||
_ => {
|
||||
unreachable!("only player messages are added");
|
||||
}
|
||||
};
|
||||
ChatMessage {
|
||||
time: bare.time,
|
||||
name,
|
||||
steam_id,
|
||||
message: bare.message,
|
||||
chat_type: bare.chat_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ChatType {
|
||||
All,
|
||||
Team,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ChatHandler(Vec<ChatMessage>);
|
||||
pub struct ChatHandler(Vec<BareChatMessage>);
|
||||
|
||||
impl EventHandler for ChatHandler {
|
||||
type Output = Vec<ChatMessage>;
|
||||
|
|
@ -36,13 +64,13 @@ impl EventHandler for ChatHandler {
|
|||
return Ok(());
|
||||
}
|
||||
match event.ty {
|
||||
RawEventType::SayTeam => self.0.push(ChatMessage {
|
||||
RawEventType::SayTeam => self.0.push(BareChatMessage {
|
||||
time,
|
||||
subject,
|
||||
message: event.params.trim_matches('"').into(),
|
||||
chat_type: ChatType::Team,
|
||||
}),
|
||||
RawEventType::Say => self.0.push(ChatMessage {
|
||||
RawEventType::Say => self.0.push(BareChatMessage {
|
||||
time,
|
||||
subject,
|
||||
message: event.params.trim_matches('"').into(),
|
||||
|
|
@ -53,7 +81,10 @@ impl EventHandler for ChatHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(self) -> Self::Output {
|
||||
fn finish(self, subjects: &SubjectMap) -> Self::Output {
|
||||
self.0
|
||||
.into_iter()
|
||||
.map(|bare| ChatMessage::from_bare(bare, subjects))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::common::SubjectId;
|
||||
use crate::module::EventHandler;
|
||||
use crate::raw_event::{RawEvent, RawEventType};
|
||||
use crate::SubjectMap;
|
||||
use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone, Utc};
|
||||
use std::str::{FromStr, ParseBoolError};
|
||||
use steamid_ng::SteamID;
|
||||
|
|
@ -182,7 +183,7 @@ impl EventHandler for LobbySettingsHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(self) -> Self::Output {
|
||||
fn finish(self, _subjects: &SubjectMap) -> Self::Output {
|
||||
if self.0.id > 0 {
|
||||
Some(self.0)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::common::SubjectId;
|
||||
use crate::raw_event::{RawEvent, RawEventType};
|
||||
use crate::SubjectMap;
|
||||
pub use chat::{ChatHandler, ChatMessage, ChatType};
|
||||
pub use lobbysettings::{
|
||||
LobbySettingsError, LobbySettingsHandler, Location, Settings as LobbySettings,
|
||||
|
|
@ -25,7 +26,7 @@ pub trait EventHandler: Default {
|
|||
event: &RawEvent,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
fn finish(self) -> Self::Output;
|
||||
fn finish(self, subjects: &SubjectMap) -> Self::Output;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -57,8 +58,8 @@ impl<Head: EventHandler, Tail: EventHandler> EventHandler for HandlerStack<Head,
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(self) -> Self::Output {
|
||||
(self.head.finish(), self.tail.finish())
|
||||
fn finish(self, subjects: &SubjectMap) -> Self::Output {
|
||||
(self.head.finish(subjects), self.tail.finish(subjects))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,9 +113,9 @@ impl<Handler: EventHandler> EventHandler for OptionalHandler<Handler> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(self) -> Self::Output {
|
||||
fn finish(self, subjects: &SubjectMap) -> Self::Output {
|
||||
match self {
|
||||
OptionalHandler::Active(handler) => Ok(handler.finish()),
|
||||
OptionalHandler::Active(handler) => Ok(handler.finish(subjects)),
|
||||
OptionalHandler::Failed(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue