use std::{any::Any, collections::HashMap};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use nu_protocol::{CustomValue, ShellError, Span, Value, record};
use twitch_irc::message::PrivmsgMessage;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TwitchMessage {
pub channel: String,
pub sender: String,
pub message: String,
pub badges: HashMap<String, String>,
pub timestamp: DateTime<Utc>,
}
impl From<PrivmsgMessage> for TwitchMessage {
fn from(value: PrivmsgMessage) -> Self {
Self {
channel: value.channel_login,
sender: value.sender.login,
message: value.message_text,
badges: value
.badges
.iter()
.cloned()
.map(|b| (b.name, b.version))
.collect(),
timestamp: value.server_timestamp,
}
}
}
#[typetag::serde]
impl CustomValue for TwitchMessage {
fn clone_value(&self, span: nu_protocol::Span) -> Value {
Value::custom(Box::new(self.clone()), span)
}
fn type_name(&self) -> String {
"TwitchMessage".into()
}
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
let badges = self
.badges
.iter()
.map(|(k, v)| {
Value::record(
record! {
"id" => Value::string(k, span),
"version" => Value::string(v, span),
},
span,
)
})
.collect::<Vec<_>>();
Ok(Value::record(
record! {
"channel" => Value::string(&self.channel, span),
"sender" => Value::string(&self.sender, span),
"message" => Value::string(&self.message, span),
"badges" => Value::list(badges, span),
"timestamp" => Value::date(self.timestamp.fixed_offset(), span)
},
span,
))
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
fn follow_path_string(
&self,
self_span: Span,
column_name: String,
path_span: Span,
) -> Result<Value, ShellError> {
self.to_base_value(self_span)
.unwrap()
.with_span(path_span)
.get_data_by_key(&column_name)
.ok_or(ShellError::IncompatiblePathAccess {
type_name: self.type_name(),
span: path_span,
})
}
}