use actix_settings::BasicSettings;
use serde::{Serialize, Deserialize};
use crate::{settings, shortener};
use mysql::prelude::*;
use mysql::*;
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
pub enum ContentType {
Url,
Pastebin,
Unimplemented,
All
}
impl From<u8> for ContentType {
fn from(item: u8) -> Self {
match item {
0 => ContentType::Url,
1 => ContentType::Pastebin,
255 => ContentType::All,
_ => ContentType::Unimplemented
}
}
}
impl From<ContentType> for u8 {
fn from(item: ContentType) -> Self {
match item {
ContentType::Url => 0,
ContentType::Pastebin => 1,
ContentType::All => 255,
_ => 255
}
}
}
#[derive(Debug)]
pub struct RetrievedUrl {
pub url: String,
pub success: bool
}
#[derive(Debug)]
pub struct SubmittedUrl {
pub shortened: String,
pub success: bool,
}
pub struct SubmittedEntry {
pub shortened: String,
pub success: bool,
}
pub struct RetrievedEntry {
pub content: String,
pub success: bool,
pub content_type: ContentType
}
pub async fn init (settings: &BasicSettings<settings::AppSettings>) -> Pool {
let database_settings = &settings.application.database;
let url = format!("mysql://{}:{}@{}:{}/{}", database_settings.username, database_settings.password, database_settings.host, database_settings.port, database_settings.database);
let pool = Pool::new(url.as_str()).unwrap();
let mut connection = pool.get_conn().unwrap();
if create_entries_table(&mut connection).await {
println!("Created table `entries`");
} else {
println!("Table `entries` already exists, no need to create it");
}
pool
}
pub async fn retrieve_url (connection: &mut PooledConn, shortened: &str) -> RetrievedUrl {
let mut result = connection.exec_iter("SELECT url FROM urls WHERE shortened = :shortened", params! {
"shortened" => shortened
}).unwrap();
let row = result.next().unwrap();
let url = row.unwrap().get::<String, _>("url").unwrap();
RetrievedUrl {
url,
success: true
}
}
pub async fn submit_url (connection: &mut PooledConn, url: &str, shortened: &str) -> SubmittedUrl {
let row = connection.exec_iter("SELECT shortened FROM urls WHERE shortened = :shortened", params! {
"shortened" => shortened
}).unwrap().next();
if row.is_some() {
SubmittedUrl {
shortened: shortened.to_string(),
success: false
}
} else {
let row = connection.exec_iter("SELECT shortened FROM urls WHERE url = :url", params! {
"url" => url
}).unwrap().next();
if row.is_some() {
let shortened = row.unwrap().unwrap().get::<String, _>("shortened").unwrap();
SubmittedUrl {
shortened,
success: true
}
} else {
connection.exec_drop("INSERT INTO urls (url, shortened) VALUES (:url, :shortened)", params! {
"url" => url,
"shortened" => shortened
}).unwrap();
SubmittedUrl {
shortened: shortened.to_string(),
success: true
}
}
}
}
pub async fn count_entries (connection: &mut PooledConn, content_type: ContentType) -> u64 {
if content_type == ContentType::All {
let mut result = connection.exec_iter("SELECT COUNT(*) FROM entries", ()).unwrap();
let row = result.next().unwrap();
let count = row.unwrap().get::<u64, _>("COUNT(*)").unwrap();
return count;
}
let mut result = connection.exec_iter("SELECT COUNT(*) FROM entries WHERE content_type = :content_type", params! {
"content_type" => content_type as u8
}).unwrap();
let row = result.next().unwrap();
let count = row.unwrap().get::<u64, _>("COUNT(*)").unwrap();
count
}
pub async fn retrieve_entry (connection: &mut PooledConn, shortened: &str) -> RetrievedEntry {
let mut result = connection.exec_iter("SELECT content, content_type FROM entries WHERE shortened = :shortened", params! {
"shortened" => shortened
}).unwrap();
let row = result.next().unwrap();
let content = row.as_ref().unwrap().get::<String, _>("content").unwrap();
let content_type = ContentType::from(row.as_ref().unwrap().get::<u8, _>("content_type").unwrap());
RetrievedEntry {
content,
success: true,
content_type
}
}
pub async fn submit_entry (connection: &mut PooledConn, content: &str, content_type: &ContentType) -> SubmittedEntry {
let shortened = shortener::base64(count_entries(connection, ContentType::All).await);
let row = connection.exec_iter("SELECT shortened FROM entries WHERE shortened = :shortened", params! {
"shortened" => shortened.clone()
}).unwrap().next();
if row.is_some() {
SubmittedEntry {
shortened: shortened.clone().to_string(),
success: false
}
} else {
connection.exec_drop("INSERT INTO entries (content, shortened, content_type) VALUES (:content, :shortened, :content_type)", params! {
"content" => content,
"shortened" => shortened.clone(),
"content_type" => u8::from(content_type.clone())
}).unwrap();
SubmittedEntry {
shortened: shortened.clone().to_string(),
success: true
}
}
}
pub async fn create_entries_table (connection: &mut PooledConn) -> bool {
let mut result = connection.exec_iter("CREATE TABLE IF NOT EXISTS entries (content TEXT(65535) NOT NULL, shortened VARCHAR(255) NOT NULL, content_type TINYINT NOT NULL, PRIMARY KEY (shortened))", ()).unwrap();
let row = result.next();
if row.is_some() {
true
} else {
false
}
}