vaguely working upload/download implementation
This commit is contained in:
commit
00f4dce4f9
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/target
|
||||
db/punt.sqlite
|
||||
uploads
|
1542
Cargo.lock
generated
Normal file
1542
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
Cargo.toml
Normal file
27
Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "punt"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rocket = {version = "0.5.0-rc.1", features = ["json"]}
|
||||
serde = {version = "1", features = ["derive"]}
|
||||
tokio = {version = "1", features = ["fs"]}
|
||||
serde_json = "1"
|
||||
rand = "0.8"
|
||||
|
||||
[dependencies.libsqlite3-sys]
|
||||
version = ">=0.17.2, <0.24.0"
|
||||
features = ["bundled"]
|
||||
|
||||
[dependencies.diesel]
|
||||
version = "1.4"
|
||||
default-features = false
|
||||
features = ["sqlite"]
|
||||
|
||||
[dependencies.rocket_sync_db_pools]
|
||||
version = "0.1.0-rc.1"
|
||||
default-features = false
|
||||
features = ["diesel_sqlite_pool"]
|
4
Rocket.toml
Normal file
4
Rocket.toml
Normal file
@ -0,0 +1,4 @@
|
||||
# Temporary, will be replaced by env vars and hard-coded defaults eventually so that Punt can function as a single-binary application
|
||||
|
||||
[global.databases]
|
||||
punt = {url = "db/punt.sqlite"}
|
1
db/migrations/2022-01-16-214545_initial/down.sql
Normal file
1
db/migrations/2022-01-16-214545_initial/down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE uploads;
|
5
db/migrations/2022-01-16-214545_initial/up.sql
Normal file
5
db/migrations/2022-01-16-214545_initial/up.sql
Normal file
@ -0,0 +1,5 @@
|
||||
CREATE TABLE uploads (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
name TEXT,
|
||||
created_at INTEGER
|
||||
);
|
9
diesel.toml
Normal file
9
diesel.toml
Normal file
@ -0,0 +1,9 @@
|
||||
# For documentation on how to configure this file,
|
||||
# see diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/schema.rs"
|
||||
|
||||
# this will start working whenever Diesel CLI gets around to releasing v1.4.4
|
||||
# [migrations_directory]
|
||||
# file = "db/migrations"
|
40
src/data.rs
Normal file
40
src/data.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use rocket_sync_db_pools::database;
|
||||
use rocket::serde::Serialize;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::schema::uploads;
|
||||
|
||||
|
||||
#[database("punt")]
|
||||
pub struct DbConn(diesel::SqliteConnection);
|
||||
|
||||
|
||||
#[derive(Queryable, Insertable, Serialize)]
|
||||
#[table_name="uploads"]
|
||||
pub struct FileInfo {
|
||||
pub id: String,
|
||||
pub name: Option<String>,
|
||||
pub created_at: Option<i32> // figure out how to marshal this to a proper time type later
|
||||
}
|
||||
|
||||
|
||||
pub async fn get_file_info(id: String, conn: DbConn) -> QueryResult<FileInfo> {
|
||||
conn.run(|c| uploads::table.find(id).first(c)).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn put_file_info(id: &str, name: Option<&str>, conn: DbConn) -> QueryResult<()> {
|
||||
let file_info = FileInfo {
|
||||
id: id.to_owned(),
|
||||
name: name.map(|n| n.to_owned()),
|
||||
created_at: Some(1642371865),
|
||||
};
|
||||
|
||||
conn.run(|c| {
|
||||
diesel::insert_into(uploads::table)
|
||||
.values(file_info)
|
||||
.execute(c)
|
||||
}).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
25
src/lib.rs
Normal file
25
src/lib.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use rand::{Rng, distributions::Alphanumeric};
|
||||
use tokio::fs::create_dir;
|
||||
use std::io::ErrorKind;
|
||||
use rocket::fs::TempFile;
|
||||
|
||||
|
||||
pub fn gen_id() -> String {
|
||||
rand::thread_rng()
|
||||
.sample_iter(Alphanumeric)
|
||||
.map(|c| c as char)
|
||||
.take(16)
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
pub async fn persist_file(file: &mut TempFile<'_>, filename: &str) -> std::io::Result<()> {
|
||||
let dst = format!("uploads/{filename}");
|
||||
match file.persist_to(&dst).await {
|
||||
Err(e) if e.kind() == ErrorKind::NotFound => {
|
||||
create_dir("uploads").await?;
|
||||
file.persist_to(&dst).await
|
||||
},
|
||||
other => other,
|
||||
}
|
||||
}
|
44
src/main.rs
Normal file
44
src/main.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use rocket::{get, post, routes, fs::TempFile};
|
||||
use rocket::http::Status;
|
||||
use rocket::serde::json::Json;
|
||||
#[macro_use] extern crate diesel;
|
||||
|
||||
mod data;
|
||||
mod lib;
|
||||
mod schema;
|
||||
use data::{DbConn, FileInfo};
|
||||
|
||||
|
||||
#[get("/")]
|
||||
fn test() -> &'static str {
|
||||
return "Hello, world!";
|
||||
}
|
||||
|
||||
|
||||
#[get("/<id>")]
|
||||
async fn download(id: String, conn: DbConn) -> Result<Json<FileInfo>, Status> {
|
||||
data::get_file_info(id, conn).await
|
||||
.map(|info| Json(info))
|
||||
.map_err(|_| Status::InternalServerError)
|
||||
}
|
||||
|
||||
|
||||
#[post("/upload", data = "<file>")]
|
||||
async fn upload(mut file: TempFile<'_>, conn: DbConn) -> Result<String, Status> {
|
||||
let id = lib::gen_id();
|
||||
data::put_file_info(&id, file.name(), conn).await
|
||||
.map_err(|_| Status::InternalServerError)?;
|
||||
|
||||
|
||||
lib::persist_file(&mut file, &id).await
|
||||
.map_err(|_| Status::InternalServerError)?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
|
||||
#[rocket::launch]
|
||||
fn rocket() -> _ {
|
||||
rocket::build()
|
||||
.attach(DbConn::fairing())
|
||||
.mount("/", routes![test, upload, download])
|
||||
}
|
7
src/schema.rs
Normal file
7
src/schema.rs
Normal file
@ -0,0 +1,7 @@
|
||||
table! {
|
||||
uploads (id) {
|
||||
id -> Text,
|
||||
name -> Nullable<Text>,
|
||||
created_at -> Nullable<Integer>,
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user