extern crate rusqlite;
extern crate serde_json;
use rusqlite::types::{ToSql};
use rusqlite::{Connection, NO_PARAMS};
use irc::client::prelude::IrcClient;
#[derive(Debug, Clone)]
pub struct AliasRow {
id: u32,
aliases: String,
}
impl PartialEq for AliasRow {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
type Aliases = Vec<String>;
#[derive(Debug, Clone)]
pub struct MessageCacheRow {
id: u32,
pub to_name: String,
pub message: String,
pub in_chan: Option<String>,
pub from_name: String,
}
pub trait DaoTrait {
fn get_message_for(&self, who: &str, in_chan: &str) -> Result<Option<Vec<MessageCacheRow>>, &'static str>;
fn add_message_for(&self, who: &str, what: &str, chan: &Option<&str>, from: &str) -> Result<(), &'static str>;
fn del_message(&self, msg: &MessageCacheRow) -> Result<(), &'static str>;
fn get_alias_for(&self, who: &str) -> Result<(Option<AliasRow>, Aliases), &'static str>;
fn add_alias_for(&self, who: &str, to_add: &str) -> Result<Aliases, &'static str>;
fn del_alias_for(&self, who: &str, to_del: &str) -> Result<Aliases, &'static str>;
}
pub struct Dao {
connection: Connection,
}
impl Dao {
pub fn new(conn: Connection) -> Dao {
Dao { connection: conn }
}
fn _get_message_for_single(&self, who: &str, in_chan: &str) -> Result<Option<Vec<MessageCacheRow>>, &'static str> {
let mut stmt = self.connection
.prepare("SELECT id, to_name, message, in_chan, from_name
FROM MessageCache WHERE to_name IS ?1 AND in_chan is ?2").unwrap();
let iter = stmt.query_map(&[&who as &ToSql, &in_chan as &ToSql], |row| Ok(MessageCacheRow {
id: row.get(0).unwrap(),
to_name: row.get(1).unwrap(),
message: row.get(2).unwrap(),
in_chan: row.get(3).unwrap(),
from_name: row.get(4).unwrap(),
}
)).unwrap();
let res: Vec<MessageCacheRow> = iter.map(|a| a.unwrap()).collect();
return Ok(Some(res))
}
}
impl DaoTrait for Dao {
fn del_message(&self, msg: &MessageCacheRow) -> Result<(), &'static str> {
let res = self.connection
.execute("DELETE FROM MessageCache WHERE id = ?1", &[&msg.id]);
match res {
Ok(_) => Ok(()),
Err(e) => Err("SQL error"),
}
}
fn add_message_for(&self, who: &str, what: &str, chan: &Option<&str>, from: &str) -> Result<(), &'static str> {
let result = self.connection
.execute("INSERT INTO MessageCache (to_name, message, in_chan, from_name)
VALUES (?1, ?2, ?3, ?4)",
&[&who as &ToSql, &what as &ToSql, chan, &from as &ToSql]);
match result {
Ok(_) => Ok(()),
Err(e) => Err("SQL error"),
}
}
fn get_message_for(&self, who: &str, in_chan: &str) -> Result<Option<Vec<MessageCacheRow>>, &'static str> {
let aliases = self.get_alias_for(who).unwrap();
let mut results: Vec<MessageCacheRow> = vec!();
for alias in aliases.1.iter() {
let msgs = self._get_message_for_single(&alias, &in_chan);
if let Ok(opt) = msgs {
if let Some(mut data) = opt {
results.append(&mut data);
}
} else if let Err(e) = msgs {
return Err(e)
}
}
if results.len() == 0 {
Ok(None)
} else {
Ok(Some(results))
}
}
fn get_alias_for(&self, who: &str) -> Result<(Option<AliasRow>, Aliases), &'static str> {
let mut stmt = self.connection
.prepare("SELECT id, aliases FROM Aliases").unwrap();
let iter = stmt.query_map(NO_PARAMS, |row| Ok(AliasRow {
id: row.get(0).unwrap(),
aliases: row.get(1).unwrap(),
})).unwrap();
let mapped: Vec<(AliasRow, Aliases)> = iter
.map(|item| {
let temp = item.unwrap();
let als = serde_json::from_str::<Aliases>(&temp.aliases).unwrap();
(temp, als)
})
.filter(|v| { v.1.contains(&who.to_string()) } )
.collect();
if mapped.len() == 0 {
Ok((None, vec!(String::from(who))))
} else {
Ok((Some(mapped.get(0).unwrap().0.clone()), mapped.get(0).unwrap().1.to_vec()))
}
}
fn add_alias_for(&self, who: &str, to_add: &str) -> Result<Aliases, &'static str> {
let res = self.get_alias_for(who);
let res_to_add = self.get_alias_for(to_add);
if let Ok((Some(ref row0), _)) = res_to_add {
if let Ok((Some(ref row1), _)) = res {
if row0 == row1 {
return Err("Already exists")
}
} else {
return Err("Attempting to assign alias to another group of aliases!")
}
}
if let Ok((Some(row), mut als)) = res {
let mut stmt = self.connection
.prepare("UPDATE Aliases SET aliases = ?1 WHERE id = ?2").unwrap();
als.push(String::from(to_add));
stmt.execute(&[serde_json::to_string(&als).unwrap(), row.id.to_string()]).unwrap();
return Ok(als)
} else if let Ok((None, mut als)) = res {
let mut add_stmt = self.connection
.prepare("INSERT INTO Aliases (aliases) VALUES (?1)").unwrap();
als.push(String::from(to_add));
add_stmt.execute(&[serde_json::to_string(&als).unwrap()]).unwrap();
return Ok(als)
} else {
Err("SQL error")
}
}
fn del_alias_for(&self, who: &str, to_del: &str) -> Result<Aliases, &'static str> {
let res = self.get_alias_for(who);
let res_to_del = self.get_alias_for(to_del);
if let Ok((Some(ref row0), ref al_del)) = res_to_del {
if let Ok((Some(ref row1), _)) = res {
if row0 == row1 {
let new_vec: Aliases = al_del.iter().filter(|e| { **e != String::from(to_del)}).cloned().collect();
let mut stmt = self.connection
.prepare("UPDATE Aliases SET aliases = ?1 WHERE id = ?2").unwrap();
stmt.execute(&[serde_json::to_string(&new_vec).unwrap(), row0.id.to_string()]).unwrap();
return Ok(new_vec)
} else {
return Err("The two are not aliases!");
}
} else {
return Err("Attempting to assign alias to another group of aliases!")
}
}
return Err("The two are not aliases!");
}
}
pub fn get_actual_message(what: &str) -> &str {
let mut counter = 0;
let index = what.find(move|c: char| {
if c.is_whitespace() {
counter = counter + 1;
}
counter >= 2
});
match slice_index(&what, &index) {
Some(s) => s,
None => &what[0..0],
}
}
fn slice_index<'a>(what: &'a str, index: &Option<usize>) -> Option<&'a str> {
match index {
Some(i) => Some(&what[*i+1..]),
None => None,
}
}
pub fn new_config_from_file(file_name: &str) -> Result<irc::client::prelude::Config, irc::error::IrcError> {
irc::client::prelude::Config::load(&file_name)
}