channels modules have newly updated list endpoints

/channels/create requires a rework however
This commit is contained in:
shockrah
2020-11-03 23:16:24 -08:00
parent 188184460f
commit f9bc6b3dc9
2 changed files with 85 additions and 148 deletions

View File

@@ -1,159 +1,40 @@
use hyper::{StatusCode, Response, Body};
use hyper::header::HeaderValue;
use hyper::{
StatusCode, Response, Body,
header::HeaderValue
};
use mysql_async::{Conn, Pool};
use mysql_async::error::Error;
use mysql_async::prelude::{params, Queryable};
use mysql_async::Pool;
use serde_json::Value;
use serde_json::{Value, to_string};
use db::{
self,
UBigInt, VarChar, Integer,
common::FromDB
common::FromDB,
channels::Channel
};
#[derive(Debug)]
pub enum ChannelType {
Voice,
Text,
Undefined
}
impl ChannelType {
// These funcs are mainly here to help translation from mysql
pub fn from_i32(x: i32) -> ChannelType {
match x {
1 => ChannelType::Voice,
2 => ChannelType::Text,
_ => ChannelType::Undefined
}
}
pub fn as_i32(&self) -> i32 {
match self {
ChannelType::Voice => 1,
ChannelType::Text => 2,
ChannelType::Undefined => 3,
}
}
}
// Primary way of interpretting sql data on our channels table
pub struct Channel {
pub id: u64,
pub name: String,
pub description: String,
pub kind: ChannelType
}
#[derive(Debug)]
struct InsertableChannel {
name: String,
kind: ChannelType
}
impl Channel {
/*
* When our sql library queries things we generally get back tuples rather reasily
* we can use this method to get something that makes more sense
*/
fn from_tup(tup: (UBigInt, VarChar, Option<VarChar>, Integer)) -> Channel {
let desc = match tup.2 {
Some(val) => val,
None => "None".into()
};
Channel {
id: tup.0,
name: tup.1,
description: desc,
kind: ChannelType::from_i32(tup.3)
}
}
/*
* When responding with some channel data to the client we use json
* this itemizes a single struct as the following(without the pretty output)
* {
* "id": id<i32>,
* "name": "<some name here>",
* "description": Option<"<description here>">,
* "kind": kind<i32>
* }
*/
fn as_json_str(&self) -> String {
let mut base = String::from("{");
base.push_str(&format!("\"id\":{},", self.id));
base.push_str(&format!("\"name\":\"{}\",", self.name));
base.push_str(&format!("\"description\":\"{}\",", self.description));
base.push_str(&format!("\"kind\":{}}}", self.kind.as_i32()));
return base;
}
}
/*
* Forwarding SQL errors as we can handle those error in caller site for this leaf function
* On success we back a Vec<Channel> which we can JSON'ify later and use as a response
*/
async fn get_channels_vec(conn: Conn) -> Result<Vec<Channel>, Error> {
let rows_db = conn.prep_exec(r"SELECT * FROM channels", ()).await?;
let (_, rows) = rows_db.map_and_drop(|row| {
let (id, name, desc, kind): (UBigInt, VarChar, Option<VarChar>, Integer) = mysql_async::from_row(row);
Channel::from_tup((id, name, desc, kind))
}).await?;
Ok(rows)
}
pub async fn list_channels(pool: &Pool, response: &mut Response<Body>) {
/*
* Primary dispatcher for dealing with the CHANNELS_LIST route
* For the most part this function will have a lot more error handling as it
* should know what kind of issues its child functions will have
* @user-params -> for now none as i don't feel like dealing with it
* @TODO: add in a let var that actually
*/
if let Ok(conn) = pool.get_conn().await {
match get_channels_vec(conn).await {
Ok(chans) => {
*response.status_mut() = StatusCode::OK;
response.headers_mut().insert("Content-Type",
HeaderValue::from_static("application/json"));
// At this point we build the content of our response body
// which is a json payload hence why there is weird string manipulation
// because we're trying to avoid dependancy issues and serializing things ourselves
let mut new_body = String::from("{\"channels\":[");
for chan in chans.iter() {
let s = format!("{},", chan.as_json_str());
new_body.push_str(&s);
}
if new_body.ends_with(',') {new_body.pop();}
new_body.push_str("]}");
return match db::channels::Channel::filter(pool, 0).await {
db::Response::Set(channels) => {
response.headers_mut().insert("Content type",
HeaderValue::from_static("json/application"));
*response.body_mut() = Body::from(new_body);
},
Err(_) => {
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
}
}
}
else {
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
}
}
async fn insert_channel(pool: &Pool, name: &str, desc: &str, kind: i64) -> Result<(), Error>{
let conn = pool.get_conn().await?;
conn.prep_exec(
"INSERT INTO channels (name, description, kind) VALUES (:name, :description, :kind)",
params!{"name" => name, "kind" => kind, "description" => desc}).await?;
Ok(())
*response.body_mut() = Body::from(to_string(&channels).unwrap_or("{}".into()))
},
db::Response::Other(_msg) => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR,
_ => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR,
};
}
pub async fn create_channel(pool: &Pool, response: &mut Response<Body>, params: Value) {
/*
* Create a channel base on a few parameters that may or may not be there
* @responds with the data of the newly created channel
*/
// Theres an extra un-needed unwrap to be cut out from this proc
// specifically with the desc parameter
@@ -165,13 +46,6 @@ pub async fn create_channel(pool: &Pool, response: &mut Response<Body>, params:
};
match req_params {
(Some(name), Some(desc), Some(kind)) => {
match insert_channel(pool, name, desc, kind).await {
Err(e) => {
println!("SERVER ERROR: {}", e);
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
},
_ => {}
}
},
// basically one of the parameter gets failed so we bail on all of this
_ => *response.status_mut() = StatusCode::BAD_REQUEST
@@ -180,7 +54,6 @@ pub async fn create_channel(pool: &Pool, response: &mut Response<Body>, params:
pub async fn delete_channel(pool: &Pool, response: &mut Response<Body>, params: Value) {
// make sure we have the right parameters provided
use db::channels::Channel;
if let Some(name) = params.get("channel_id") {
if let Some(id) = name.as_u64() {
// TODO: something more intelligent with the logging im ngl