Skip to content

Commit

Permalink
Merge pull request #4 from dragynfruit/error_handling
Browse files Browse the repository at this point in the history
Error handling
  • Loading branch information
drakeerv authored Aug 23, 2024
2 parents c38e8a6 + d8e1289 commit 4d9253b
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 141 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pasted"
version = "1.2.13"
version = "1.2.14"
edition = "2021"
authors = ["drakeerv <drakeerv@outlook.com>"]
description = "A pastebin frontend written in Rust"
Expand Down
55 changes: 36 additions & 19 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,51 @@ pub struct Client {
agent: Agent,
}

#[derive(Debug)]
pub enum ClientError {
UreqError(ureq::Error),
IoError(std::io::Error)
}

impl From<ureq::Error> for ClientError {
fn from(value: ureq::Error) -> Self {
ClientError::UreqError(value)
}
}

impl From<std::io::Error> for ClientError {
fn from(value: std::io::Error) -> Self {
ClientError::IoError(value)
}
}

impl Client {
pub fn new() -> Self {
Self {
agent: AgentBuilder::new().redirects(0).build(),
}
}

pub fn get_response(&self, url: &str) -> ureq::Response {
self.agent.get(url).call().unwrap()
pub fn get_response(&self, url: &str) -> Result<ureq::Response, ClientError> {
Ok(self.agent.get(url).call()?)
}

pub fn post_response(&self, url: &str, form: (String, Vec<u8>)) -> ureq::Response {
self.agent
pub fn post_response(&self, url: &str, form: (String, Vec<u8>)) -> Result<ureq::Response, ClientError> {
Ok(self.agent
.post(url)
.set("Content-Type", &form.0)
.send_bytes(&form.1)
.unwrap()
.send_bytes(&form.1)?)
}

pub fn get_string(&self, url: &str) -> String {
self.get_response(url).into_string().unwrap()
pub fn get_string(&self, url: &str) -> Result<String, ClientError> {
Ok(self.get_response(url)?.into_string()?)
}

pub fn post_string(&self, url: &str, form: (String, Vec<u8>)) -> String {
self.post_response(url, form).into_string().unwrap()
pub fn post_string(&self, url: &str, form: (String, Vec<u8>)) -> Result<String, ClientError> {
Ok(self.post_response(url, form)?.into_string()?)
}

pub fn get_bytes(&self, url: &str) -> Vec<u8> {
pub fn get_bytes(&self, url: &str) -> Result<Vec<u8>, ClientError> {
let mut data = Vec::new();
self.agent
.get(url)
Expand All @@ -42,15 +59,15 @@ impl Client {
.into_reader()
.read_to_end(&mut data)
.unwrap();
data
Ok(data)
}

pub fn get_html(&self, url: &str) -> Html {
Html::parse_document(&&self.get_string(url))
pub fn get_html(&self, url: &str) -> Result<Html, ClientError> {
Ok(Html::parse_document(&&self.get_string(url)?))
}

pub fn post_html(&self, url: &str, form: (String, Vec<u8>)) -> Html {
Html::parse_document(&self.post_string(url, form))
pub fn post_html(&self, url: &str, form: (String, Vec<u8>)) -> Result<Html, ClientError> {
Ok(Html::parse_document(&self.post_string(url, form)?))
}
}

Expand All @@ -61,21 +78,21 @@ mod tests {
#[test]
fn test_client() {
let client = Client::new();
let response = client.get_response("https://pastebin.com").status();
let response = client.get_response("https://pastebin.com").unwrap().status();
assert_eq!(response, 200);
}

#[test]
fn test_get_string() {
let client = Client::new();
let response = client.get_string("https://pastebin.com");
let response = client.get_string("https://pastebin.com").unwrap();
assert!(response.contains("Pastebin.com"));
}

#[test]
fn test_get_bytes() {
let client = Client::new();
let response = client.get_bytes("https://pastebin.com");
let response = client.get_bytes("https://pastebin.com").unwrap();
assert!(response.len() > 0);
}
}
44 changes: 27 additions & 17 deletions src/routes/archive.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use axum::{
body::Body, extract::{Path, State}, response::{IntoResponse, Response}, routing, Json, Router
body::Body,
extract::{Path, State},
response::{IntoResponse, Response},
routing, Json, Router,
};
use tera::Context;

Expand All @@ -10,6 +13,8 @@ use crate::{
templates::TEMPLATES,
};

use super::error;

pub fn get_router(state: AppState) -> Router {
Router::new()
.route("/", routing::get(archive))
Expand All @@ -30,25 +35,30 @@ fn get_url(format: Option<Path<String>>) -> String {

async fn archive(State(state): State<AppState>, format: Option<Path<String>>) -> impl IntoResponse {
let dom = state.client.get_html(&get_url(format));
let archive_page = ArchivePage::from_html(&dom);

Response::builder()
.status(200)
.header("Content-Type", "text/html")
.body(Body::new(
TEMPLATES
.render(
"archive.html",
&Context::from_serialize(archive_page).unwrap(),
)
.unwrap(),
))
.unwrap()
match dom {
Ok(dom) => Response::builder()
.status(200)
.header("Content-Type", "text/html")
.body(Body::new(
TEMPLATES
.render(
"archive.html",
&Context::from_serialize(ArchivePage::from_html(&dom)).unwrap(),
)
.unwrap(),
))
.unwrap(),
Err(err) => error::construct_error(err),
}
}

async fn archive_json(State(state): State<AppState>, format: Option<Path<String>>) -> Json<ArchivePage> {
let dom = state.client.get_html(&get_url(format));
async fn archive_json(
State(state): State<AppState>,
format: Option<Path<String>>,
) -> Json<ArchivePage> {
let dom = state.client.get_html(&get_url(format)).unwrap(); //fix
let archive_page = ArchivePage::from_html(&dom);

Json(archive_page)
}
}
36 changes: 27 additions & 9 deletions src/routes/error.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
use axum::{
body::Body, http::StatusCode, response::{IntoResponse, Response}
body::Body,
http::StatusCode,
response::{IntoResponse, Response},
};
use serde::Serialize;
use tera::Context;

use crate::client::ClientError;
use crate::templates::TEMPLATES;

#[derive(Serialize)]
pub struct Error {
status: u16,
message: Option<String>
message: Option<String>,
}

pub fn render_error(error: Error) -> impl IntoResponse {
pub fn render_error(error: Error) -> Response<Body> {
Response::builder()
.status(error.status)
.header("Content-Type", "text/html")
.body(Body::new(
TEMPLATES
.render(
"error.html",
&Context::from_serialize(&error).unwrap()
)
.render("error.html", &Context::from_serialize(&error).unwrap())
.unwrap(),
))
.unwrap()
Expand All @@ -30,10 +30,28 @@ pub fn render_error(error: Error) -> impl IntoResponse {
pub async fn error_404() -> impl IntoResponse {
return render_error(Error {
status: StatusCode::NOT_FOUND.as_u16(),
message: None
message: None,
});
}

pub fn construct_error(error: ClientError) -> Response<Body> {
match error {
ClientError::UreqError(error) => {
let response = error.into_response().unwrap();
render_error(Error {
status: response.status(),
message: None,
})
.into_response()
}
ClientError::IoError(error) => render_error(Error {
status: 500,
message: Some(error.to_string()),
})
.into_response(),
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -43,4 +61,4 @@ mod tests {
let response = error_404().await;
assert_eq!(response.into_response().status(), StatusCode::NOT_FOUND);
}
}
}
2 changes: 1 addition & 1 deletion src/routes/imgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async fn icon(
let icon = if tree.contains_key(&path).unwrap() {
tree.get(&path).unwrap().unwrap().to_vec()
} else {
let icon = state.client.get_bytes(format!("{URL}/cache/img/{path}.jpg").as_str());
let icon = state.client.get_bytes(format!("{URL}/cache/img/{path}.jpg").as_str()).unwrap(); //fix
tree.insert(&path, icon.clone()).unwrap();
icon
};
Expand Down
14 changes: 11 additions & 3 deletions src/routes/post.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ use tera::Context;
use ureq_multipart::MultipartBuilder;

use crate::{
constants::URL, state::AppState, templates::TEMPLATES, parsers::paste::get_csrftoken
constants::URL, parsers::paste, state::AppState, templates::TEMPLATES
};

use super::error;

#[derive(Deserialize)]
struct Post {
text: String,
Expand Down Expand Up @@ -43,7 +45,13 @@ async fn post() -> impl IntoResponse {
}

async fn post_create(State(state): State<AppState>, Form(data): Form<Post>) -> impl IntoResponse {
let csrf = get_csrftoken(&state.client.get_html(format!("{URL}/").as_str()));
let csrf = state.client.get_html(format!("{URL}/").as_str());

if csrf.is_err() {
return error::construct_error(csrf.err().unwrap());
}

let csrf = paste::get_csrftoken(&csrf.unwrap());

let form = MultipartBuilder::new()
.add_text("_csrf-frontend", &csrf)
Expand Down Expand Up @@ -79,7 +87,7 @@ async fn post_create(State(state): State<AppState>, Form(data): Form<Post>) -> i
.finish()
.unwrap();

let response = state.client.post_response(format!("{URL}/").as_str(), form);
let response = state.client.post_response(format!("{URL}/").as_str(), form).unwrap(); // Fix
let paste_id = response
.header("Location")
.unwrap()
Expand Down
42 changes: 25 additions & 17 deletions src/routes/users.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
use axum::{
body::Body, extract::{Path, State}, response::{IntoResponse, Response}, routing, Json, Router
body::Body,
extract::{Path, State},
response::{IntoResponse, Response},
routing, Json, Router,
};
use tera::Context;

use crate::{
constants::URL,
parsers::{user::User, FromHtml as _},
state::AppState, templates::TEMPLATES,
state::AppState,
templates::TEMPLATES,
};

use super::error;

pub fn get_router(state: AppState) -> Router {
Router::new()
.route("/:username", routing::get(user))
Expand All @@ -18,25 +24,27 @@ pub fn get_router(state: AppState) -> Router {

async fn user(State(state): State<AppState>, Path(username): Path<String>) -> impl IntoResponse {
let dom = state.client.get_html(&format!("{URL}/u/{username}"));
let user = User::from_html(&dom);

Response::builder()
.status(200)
.header("Content-Type", "text/html")
.body(Body::new(
TEMPLATES
.render(
"user.html",
&Context::from_serialize(user).unwrap(),
)
.unwrap(),
))
.unwrap()
match dom {
Ok(dom) => Response::builder()
.status(200)
.header("Content-Type", "text/html")
.body(Body::new(
TEMPLATES
.render(
"user.html",
&Context::from_serialize(User::from_html(&dom)).unwrap(),
)
.unwrap(),
))
.unwrap(),
Err(err) => error::construct_error(err),
}
}

async fn json_user(State(state): State<AppState>, Path(username): Path<String>) -> Json<User> {
let dom = state.client.get_html(&format!("{URL}/u/{username}"));
let dom = state.client.get_html(&format!("{URL}/u/{username}")).unwrap(); // fix
let user = User::from_html(&dom);

Json(user)
}
}
Loading

0 comments on commit 4d9253b

Please sign in to comment.