aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/factoids
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/factoids')
-rw-r--r--src/plugins/factoids/database.rs163
-rw-r--r--src/plugins/factoids/mod.rs342
-rw-r--r--src/plugins/factoids/sandbox.lua86
-rw-r--r--src/plugins/factoids/utils.rs25
4 files changed, 0 insertions, 616 deletions
diff --git a/src/plugins/factoids/database.rs b/src/plugins/factoids/database.rs
deleted file mode 100644
index b1fe8dd..0000000
--- a/src/plugins/factoids/database.rs
+++ /dev/null
@@ -1,163 +0,0 @@
-#[cfg(feature = "mysql")]
-extern crate dotenv;
-
-#[cfg(feature = "mysql")]
-use std::sync::Arc;
-use std::collections::HashMap;
-
-#[cfg(feature = "mysql")]
-use diesel::prelude::*;
-#[cfg(feature = "mysql")]
-use diesel::mysql::MysqlConnection;
-#[cfg(feature = "mysql")]
-use r2d2::Pool;
-#[cfg(feature = "mysql")]
-use r2d2_diesel::ConnectionManager;
-#[cfg(feature = "mysql")]
-use failure::ResultExt;
-
-use chrono::NaiveDateTime;
-
-use super::error::*;
-
-#[cfg_attr(feature = "mysql", derive(Queryable))]
-#[derive(Clone, Debug)]
-pub struct Factoid {
- pub name: String,
- pub idx: i32,
- pub content: String,
- pub author: String,
- pub created: NaiveDateTime,
-}
-
-#[cfg_attr(feature = "mysql", derive(Insertable))]
-#[cfg_attr(feature = "mysql", table_name = "factoids")]
-pub struct NewFactoid<'a> {
- pub name: &'a str,
- pub idx: i32,
- pub content: &'a str,
- pub author: &'a str,
- pub created: NaiveDateTime,
-}
-
-pub trait Database: Send {
- fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidsError>;
- fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidsError>;
- fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidsError>;
- fn count_factoids(&self, name: &str) -> Result<i32, FactoidsError>;
-}
-
-// HashMap
-impl Database for HashMap<(String, i32), Factoid> {
- fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidsError> {
- let factoid = Factoid {
- name: String::from(factoid.name),
- idx: factoid.idx,
- content: factoid.content.to_string(),
- author: factoid.author.to_string(),
- created: factoid.created,
- };
-
- let name = factoid.name.clone();
- match self.insert((name, factoid.idx), factoid) {
- None => Ok(()),
- Some(_) => Err(ErrorKind::Duplicate)?,
- }
- }
-
- fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidsError> {
- Ok(self.get(&(String::from(name), idx))
- .cloned()
- .ok_or(ErrorKind::NotFound)?)
- }
-
- fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidsError> {
- match self.remove(&(String::from(name), idx)) {
- Some(_) => Ok(()),
- None => Err(ErrorKind::NotFound)?,
- }
- }
-
- fn count_factoids(&self, name: &str) -> Result<i32, FactoidsError> {
- Ok(self.iter().filter(|&(&(ref n, _), _)| n == name).count() as i32)
- }
-}
-
-// Diesel automatically defines the factoids module as public.
-// We create a schema module to keep it private.
-#[cfg(feature = "mysql")]
-mod schema {
- table! {
- factoids (name, idx) {
- name -> Varchar,
- idx -> Integer,
- content -> Text,
- author -> Varchar,
- created -> Timestamp,
- }
- }
-}
-
-#[cfg(feature = "mysql")]
-use self::schema::factoids;
-
-#[cfg(feature = "mysql")]
-impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> {
- fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidsError> {
- use diesel;
-
- let conn = &*self.get().context(ErrorKind::NoConnection)?;
- diesel::insert_into(factoids::table)
- .values(factoid)
- .execute(conn)
- .context(ErrorKind::MysqlError)?;
-
- Ok(())
- }
-
- fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidsError> {
- let conn = &*self.get().context(ErrorKind::NoConnection)?;
- Ok(factoids::table
- .find((name, idx))
- .first(conn)
- .context(ErrorKind::MysqlError)?)
- }
-
- fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidsError> {
- use diesel;
- use self::factoids::columns;
-
- let conn = &*self.get().context(ErrorKind::NoConnection)?;
- match diesel::delete(
- factoids::table
- .filter(columns::name.eq(name))
- .filter(columns::idx.eq(idx)),
- ).execute(conn)
- {
- Ok(v) => {
- if v > 0 {
- Ok(())
- } else {
- Err(ErrorKind::NotFound)?
- }
- }
- Err(e) => Err(e).context(ErrorKind::MysqlError)?,
- }
- }
-
- fn count_factoids(&self, name: &str) -> Result<i32, FactoidsError> {
- use diesel;
-
- let conn = &*self.get().context(ErrorKind::NoConnection)?;
- let count: Result<i64, _> = factoids::table
- .filter(factoids::columns::name.eq(name))
- .count()
- .get_result(conn);
-
- match count {
- Ok(c) => Ok(c as i32),
- Err(diesel::NotFound) => Ok(0),
- Err(e) => Err(e).context(ErrorKind::MysqlError)?,
- }
- }
-}
diff --git a/src/plugins/factoids/mod.rs b/src/plugins/factoids/mod.rs
deleted file mode 100644
index 2f3690f..0000000
--- a/src/plugins/factoids/mod.rs
+++ /dev/null
@@ -1,342 +0,0 @@
-extern crate rlua;
-
-use std::fmt;
-use std::str::FromStr;
-use std::sync::Mutex;
-use self::rlua::prelude::*;
-use irc::client::prelude::*;
-
-use time;
-use chrono::NaiveDateTime;
-
-use plugin::*;
-pub mod database;
-use self::database::Database;
-
-mod utils;
-use self::utils::*;
-
-use failure::ResultExt;
-use error::ErrorKind as FrippyErrorKind;
-use error::FrippyError;
-use self::error::*;
-
-static LUA_SANDBOX: &'static str = include_str!("sandbox.lua");
-
-#[derive(PluginName)]
-pub struct Factoids<T: Database> {
- factoids: Mutex<T>,
-}
-
-macro_rules! try_lock {
- ( $m:expr ) => {
- match $m.lock() {
- Ok(guard) => guard,
- Err(poisoned) => poisoned.into_inner(),
- }
- }
-}
-
-impl<T: Database> Factoids<T> {
- pub fn new(db: T) -> Factoids<T> {
- Factoids {
- factoids: Mutex::new(db),
- }
- }
-
- fn create_factoid(
- &self,
- name: &str,
- content: &str,
- author: &str,
- ) -> Result<&str, FactoidsError> {
- let count = try_lock!(self.factoids).count_factoids(name)?;
- let tm = time::now().to_timespec();
-
- let factoid = database::NewFactoid {
- name: name,
- idx: count,
- content: content,
- author: author,
- created: NaiveDateTime::from_timestamp(tm.sec, 0u32),
- };
-
- Ok(try_lock!(self.factoids)
- .insert_factoid(&factoid)
- .map(|()| "Successfully added!")?)
- }
-
- fn add(&self, command: &mut PluginCommand) -> Result<&str, FactoidsError> {
- if command.tokens.len() < 2 {
- Err(ErrorKind::InvalidCommand)?;
- }
-
- let name = command.tokens.remove(0);
- let content = command.tokens.join(" ");
-
- Ok(self.create_factoid(&name, &content, &command.source)?)
- }
-
- fn add_from_url(&self, command: &mut PluginCommand) -> Result<&str, FactoidsError> {
- if command.tokens.len() < 2 {
- Err(ErrorKind::InvalidCommand)?;
- }
-
- let name = command.tokens.remove(0);
- let url = &command.tokens[0];
- let content = ::utils::download(url, Some(1024)).context(ErrorKind::Download)?;
-
- Ok(self.create_factoid(&name, &content, &command.source)?)
- }
-
- fn remove(&self, command: &mut PluginCommand) -> Result<&str, FactoidsError> {
- if command.tokens.len() < 1 {
- Err(ErrorKind::InvalidCommand)?;
- }
-
- let name = command.tokens.remove(0);
- let count = try_lock!(self.factoids).count_factoids(&name)?;
-
- match try_lock!(self.factoids).delete_factoid(&name, count - 1) {
- Ok(()) => Ok("Successfully removed"),
- Err(e) => Err(e)?,
- }
- }
-
- fn get(&self, command: &PluginCommand) -> Result<String, FactoidsError> {
- let (name, idx) = match command.tokens.len() {
- 0 => Err(ErrorKind::InvalidCommand)?,
- 1 => {
- let name = &command.tokens[0];
- let count = try_lock!(self.factoids).count_factoids(name)?;
-
- if count < 1 {
- Err(ErrorKind::NotFound)?;
- }
-
- (name, count - 1)
- }
- _ => {
- let name = &command.tokens[0];
- let idx = match i32::from_str(&command.tokens[1]) {
- Ok(i) => i,
- Err(_) => Err(ErrorKind::InvalidCommand)?,
- };
-
- (name, idx)
- }
- };
-
- let factoid = try_lock!(self.factoids)
- .get_factoid(name, idx)
- .context(ErrorKind::NotFound)?;
-
- let message = factoid.content.replace("\n", "|").replace("\r", "");
-
- Ok(format!("{}: {}", factoid.name, message))
- }
-
- fn info(&self, command: &PluginCommand) -> Result<String, FactoidsError> {
- match command.tokens.len() {
- 0 => Err(ErrorKind::InvalidCommand)?,
- 1 => {
- let name = &command.tokens[0];
- let count = try_lock!(self.factoids).count_factoids(name)?;
-
- Ok(match count {
- 0 => Err(ErrorKind::NotFound)?,
- 1 => format!("There is 1 version of {}", name),
- _ => format!("There are {} versions of {}", count, name),
- })
- }
- _ => {
- let name = &command.tokens[0];
- let idx = i32::from_str(&command.tokens[1]).context(ErrorKind::InvalidIndex)?;
- let factoid = try_lock!(self.factoids).get_factoid(name, idx)?;
-
- Ok(format!(
- "{}: Added by {} at {} UTC",
- name, factoid.author, factoid.created
- ))
- }
- }
- }
-
- fn exec(&self, mut command: PluginCommand) -> Result<String, FactoidsError> {
- if command.tokens.len() < 1 {
- Err(ErrorKind::InvalidIndex)?
- } else {
- let name = command.tokens.remove(0);
- let count = try_lock!(self.factoids).count_factoids(&name)?;
- let factoid = try_lock!(self.factoids).get_factoid(&name, count - 1)?;
-
- let content = factoid.content;
- let value = if content.starts_with('>') {
- let content = String::from(&content[1..]);
-
- if content.starts_with('>') {
- content
- } else {
- match self.run_lua(&name, &content, &command) {
- Ok(v) => v,
- Err(e) => format!("\"{}\"", e),
- }
- }
- } else {
- content
- };
-
- Ok(value.replace("\n", "|").replace("\r", ""))
- }
- }
-
- fn run_lua(
- &self,
- name: &str,
- code: &str,
- command: &PluginCommand,
- ) -> Result<String, rlua::Error> {
- let args = command
- .tokens
- .iter()
- .filter(|x| !x.is_empty())
- .map(ToOwned::to_owned)
- .collect::<Vec<String>>();
-
- let lua = unsafe { Lua::new_with_debug() };
- let globals = lua.globals();
-
- globals.set("factoid", code)?;
- globals.set("download", lua.create_function(download)?)?;
- globals.set("sleep", lua.create_function(sleep)?)?;
- globals.set("args", args)?;
- globals.set("input", command.tokens.join(" "))?;
- globals.set("user", command.source.clone())?;
- globals.set("channel", command.target.clone())?;
- globals.set("output", lua.create_table()?)?;
-
- lua.exec::<()>(LUA_SANDBOX, Some(name))?;
- let output: Vec<String> = globals.get::<_, Vec<String>>("output")?;
-
- Ok(output.join("|"))
- }
-}
-
-impl<T: Database> Plugin for Factoids<T> {
- fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
- match message.command {
- Command::PRIVMSG(_, ref content) => if content.starts_with('!') {
- ExecutionStatus::RequiresThread
- } else {
- ExecutionStatus::Done
- },
- _ => ExecutionStatus::Done,
- }
- }
-
- fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> {
- if let Command::PRIVMSG(_, mut content) = message.command.clone() {
- content.remove(0);
-
- let t: Vec<String> = content.split(' ').map(ToOwned::to_owned).collect();
-
- let c = PluginCommand {
- source: message.source_nickname().unwrap().to_owned(),
- target: message.response_target().unwrap().to_owned(),
- tokens: t,
- };
-
- Ok(match self.exec(c) {
- Ok(f) => client
- .send_privmsg(&message.response_target().unwrap(), &f)
- .context(FrippyErrorKind::Connection)?,
- Err(_) => (),
- })
- } else {
- Ok(())
- }
- }
-
- fn command(&self, client: &IrcClient, mut command: PluginCommand) -> Result<(), FrippyError> {
- if command.tokens.is_empty() {
- return Ok(client
- .send_notice(&command.target, "Invalid command")
- .context(FrippyErrorKind::Connection)?);
- }
-
- let target = command.target.clone();
- let source = command.source.clone();
-
- let sub_command = command.tokens.remove(0);
- let result = match sub_command.as_ref() {
- "add" => self.add(&mut command).map(|s| s.to_owned()),
- "fromurl" => self.add_from_url(&mut command).map(|s| s.to_owned()),
- "remove" => self.remove(&mut command).map(|s| s.to_owned()),
- "get" => self.get(&command),
- "info" => self.info(&command),
- "exec" => self.exec(command),
- _ => Err(ErrorKind::InvalidCommand.into()),
- };
-
- Ok(match result {
- Ok(v) => client
- .send_privmsg(&target, &v)
- .context(FrippyErrorKind::Connection)?,
- Err(e) => {
- let message = e.to_string();
- client
- .send_notice(&source, &message)
- .context(FrippyErrorKind::Connection)?;
- Err(e).context(FrippyErrorKind::Factoids)?
- }
- })
- }
-
- fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
- Err(String::from(
- "Evaluation of commands is not implemented for Factoids at this time",
- ))
- }
-}
-
-impl<T: Database> fmt::Debug for Factoids<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Factoids {{ ... }}")
- }
-}
-
-pub mod error {
- #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
- #[error = "FactoidsError"]
- pub enum ErrorKind {
- /// Invalid command error
- #[fail(display = "Invalid Command")]
- InvalidCommand,
-
- /// Invalid index error
- #[fail(display = "Invalid index")]
- InvalidIndex,
-
- /// Download error
- #[fail(display = "Download failed")]
- Download,
-
- /// Duplicate error
- #[fail(display = "Entry already exists")]
- Duplicate,
-
- /// Not found error
- #[fail(display = "Factoid was not found")]
- NotFound,
-
- /// MySQL error
- #[cfg(feature = "mysql")]
- #[fail(display = "Failed to execute MySQL Query")]
- MysqlError,
-
- /// No connection error
- #[cfg(feature = "mysql")]
- #[fail(display = "No connection to the database")]
- NoConnection,
- }
-}
diff --git a/src/plugins/factoids/sandbox.lua b/src/plugins/factoids/sandbox.lua
deleted file mode 100644
index 3fc74cd..0000000
--- a/src/plugins/factoids/sandbox.lua
+++ /dev/null
@@ -1,86 +0,0 @@
-function send(text)
- local text = tostring(text)
- local len = #output
- if len < 1 then
- output = { text }
- else
- output[len] = output[len] .. text
- end
-end
-
-function sendln(text)
- send(text)
- table.insert(output, "")
-end
-
-local sandbox_env = {
- print = send,
- println = sendln,
- eval = nil,
- args = args,
- input = input,
- user = user,
- channel = channel,
- request = download,
- string = string,
- math = math,
- table = table,
- pairs = pairs,
- ipairs = ipairs,
- next = next,
- select = select,
- unpack = unpack,
- tostring = tostring,
- tonumber = tonumber,
- type = type,
- assert = assert,
- error = error,
- pcall = pcall,
- xpcall = xpcall,
- _VERSION = _VERSION
-}
-
-sandbox_env.os = {
- clock = os.clock,
- time = os.time,
- difftime = os.difftime
-}
-
-sandbox_env.string.rep = nil
-sandbox_env.string.dump = nil
-sandbox_env.math.randomseed = nil
-
--- Temporary evaluation function
-function eval(code)
- local c, e = load(code, nil, nil, sandbox_env)
- if c then
- return c()
- else
- error(e)
- end
-end
-
-sandbox_env.eval = eval
-
--- Check if the factoid timed out
-function checktime(event, line)
- if os.time() - time >= timeout then
- error("Timed out after " .. timeout .. " seconds", 0)
- else
- -- Limit the cpu usage of factoids
- sleep(1)
- end
-end
-
-local f, e = load(factoid, nil, nil, sandbox_env)
-
--- Add timeout hook
-time = os.time()
-timeout = 30
-debug.sethook(checktime, "l")
-
-if f then
- f()
-else
- error(e)
-end
diff --git a/src/plugins/factoids/utils.rs b/src/plugins/factoids/utils.rs
deleted file mode 100644
index 70ac8a7..0000000
--- a/src/plugins/factoids/utils.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-extern crate reqwest;
-
-use std::thread;
-use std::time::Duration;
-
-use utils;
-use super::rlua::prelude::*;
-
-use self::LuaError::RuntimeError;
-
-pub fn download(_: &Lua, url: String) -> Result<String, LuaError> {
- match utils::download(&url, Some(1024)) {
- Ok(v) => Ok(v),
- Err(e) => Err(RuntimeError(format!(
- "Failed to download {} - {}",
- url,
- e.to_string()
- ))),
- }
-}
-
-pub fn sleep(_: &Lua, dur: u64) -> Result<(), LuaError> {
- thread::sleep(Duration::from_millis(dur));
- Ok(())
-}