Imported API

This commit is contained in:
Maddox Werts 2025-02-11 12:02:42 -05:00
parent 9d58cf7f37
commit 9ab9074912
3 changed files with 215 additions and 0 deletions

101
project/src/api.rs Normal file
View file

@ -0,0 +1,101 @@
// Libraries
mod retreiver;
mod bouncer;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::error::Error;
use tokio::task;
use warp::{self, Filter};
use bouncer::ApiUser;
use crate::base::{conf::Conf, database::Database};
// Structures
pub struct API {
endpoint: String,
port: u16,
database: Arc<Mutex<Database>>
}
// Functions
async fn receive_request(params: HashMap<String, String>, api: Arc<API>) -> Result<impl warp::Reply, warp::Rejection> {
// Checking reqiurements
if !params.contains_key("api") || !params.contains_key("symbol") {
let usage: String = format!("Usage: http(s)://path.to.neurostock/v1?api=[APIKEY]&symbol=[SYMBOL]\n");
return Ok(warp::reply::with_status(usage, warp::http::StatusCode::BAD_REQUEST));
}
// Getting params
let symbol: &String = params.get("symbol").unwrap();
let key: &String = params.get("api").unwrap();
// Getting the API User
let user: ApiUser = bouncer::get_api_user(Arc::clone(&api.database), key).unwrap();
// Verifying the API Key
if !user.success {
return Ok(warp::reply::with_status(
format!("API Key Not Accepted by Server ({}).\n", user.message),
warp::http::StatusCode::FORBIDDEN
));
}
// Success
return Ok(warp::reply::with_status(
format!("{}\n", api.recieve(symbol).unwrap()),
warp::http::StatusCode::OK
));
}
// Implementations
impl API {
// Constructors
pub fn init(conf: &Conf, database: Arc<Mutex<Database>>) -> Result<API, Box<dyn Error>> {
// Getting API Endpoint
let endpoint: String = conf.get_string("api.endpoint")?;
let port: u16 = conf.get_i32("api.port")? as u16;
// Returning API
return Ok(API {
endpoint: endpoint,
port: port,
database: database,
});
}
// Functions
pub fn start(&self, self_reference: Arc<API>) -> Result<task::JoinHandle<()>, Box<dyn Error>> {
// Getting the server port
let address: ([u8; 4], u16) = ([0,0,0,0], self.port.clone());
// Creating a WARP server
let warp_server = warp::path(self.endpoint.clone())
.and(warp::query::<HashMap<String, String>>())
.and(warp::any().map(move || Arc::clone(&self_reference)))
.and_then(receive_request);
// Starting the server on a new thread
let warp_future: task::JoinHandle<()> = task::spawn(async move {
warp::serve(warp_server).run(address).await;
});
// Success
return Ok(warp_future);
}
pub fn recieve(&self, symbol: &str) -> Result<String, Box<dyn Error>> {
// Getting a mutable reference for database
let database: &mut Database = {
&mut self.database.lock().unwrap()
};
// Getting result data
let result: serde_json::Value = retreiver::data_symbol(database, symbol)?;
// Success
return Ok(result.to_string());
}
}

View file

@ -0,0 +1,68 @@
// Libraries
use std::error::Error;
use std::sync::{Arc, Mutex};
use crate::base::database::Database;
// Structures
pub struct ApiUser {
pub success: bool,
pub message: String
}
// Functions
pub fn get_api_user(database: Arc<Mutex<Database>>, key: &str) -> Result<ApiUser, Box<dyn Error>> {
// Unlock Database Mutex
let db: &mut Database = {
&mut *database.lock().unwrap()
};
// Initilize API table
db.inst_table("API", "`key` TEXT, `requests` INT, `limit` INT")?;
// Getting the API User with the key the requester has provided
let rows: Vec<mysql::Row> = db.get(
"API",
"*",
&format!(" WHERE `key`='{}'", key)
)?;
// Going through all rows
for row in rows {
// Getting row details
let row_key: String = row.get(0).unwrap();
let row_requests: u32 = row.get(1).unwrap();
let row_limit: u32 = row.get(2).unwrap();
// Double check the API key
if row_key != key {continue;}
// Checking if our requests is lower than our limit
if row_requests >= row_limit {
return Ok(ApiUser {
success: false,
message: "API Request Limit Reached".to_string()
});
}
// Asking database to increase requests
db.update(
"API",
"requests",
&format!("{}", row_requests + 1),
&format!("`key`='{}'", key)
)?;
// Success!
return Ok(ApiUser {
success: true,
message: "N/A".to_string()
});
}
// Didn't find our user
return Ok(ApiUser {
success: false,
message: "Invalid API Key".to_string()
});
}

View file

@ -0,0 +1,46 @@
// Libraries
use std::error::Error;
use serde_json::{self, json, Value};
use crate::base::database::Database;
// Functions
pub fn data_symbol(database: &mut Database, symbol: &str) -> Result<Value, Box<dyn Error>> {
// Checking if the table exists
if !database.exists_table(symbol)? {
return Ok(json!({
"message": format!("Couldn't find data for {}", symbol)
}));
}
// Query Database to see if we have that symbol collected.
let rows: Vec<mysql::Row> = database.get(symbol, "*", "")?;
// Creating JSON result
let mut result: Vec<Value> = Vec::new();
// Going through all rows
for row in rows {
// Getting column data
let date: String = row.get(0).unwrap();
let open: f32 = row.get(1).unwrap();
let high: f32 = row.get(2).unwrap();
let low: f32 = row.get(3).unwrap();
let close: f32 = row.get(4).unwrap();
// Compiling result
result.push(json!({
"date": date,
"open": open,
"high": high,
"low": low,
"close": close
}));
}
// Success
return Ok(json!({
"symbol": symbol,
"data": result
}));
}