Allow creation of new document by POST request
A post request to `api/create/<language>` creates a new document and returns the newly generated id. It uses all the input as text.
This commit is contained in:
parent
14dde3c283
commit
cd5bd8fcef
6 changed files with 134 additions and 2871 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1060,6 +1060,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"bytecount",
|
||||
"bytes",
|
||||
"dashmap",
|
||||
"dotenv",
|
||||
"futures",
|
||||
|
|
2923
package-lock.json
generated
2923
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1.0.40"
|
||||
bytes = "1.0"
|
||||
bytecount = "0.6"
|
||||
dashmap = "4.0.2"
|
||||
dotenv = "0.15.0"
|
||||
|
|
|
@ -78,4 +78,14 @@ ON CONFLICT(id) DO UPDATE SET
|
|||
.await?;
|
||||
Ok(row.0 as usize)
|
||||
}
|
||||
|
||||
/// Count the number of documents in the database.
|
||||
pub async fn exists(&self, document_id: &str) -> Result<bool> {
|
||||
|
||||
let row: (i64,) = sqlx::query_as(r#"SELECT count(*) FROM document WHERE id = $1"#)
|
||||
.bind(document_id)
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
Ok(row.0 > 0)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use bytes::Bytes;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use log::{error, info};
|
||||
use rand::Rng;
|
||||
use rand::{thread_rng, Rng};
|
||||
use serde::Serialize;
|
||||
use tokio::time::{self, Instant};
|
||||
use warp::{filters::BoxedFilter, ws::Ws, Filter, Rejection, Reply};
|
||||
|
@ -119,16 +121,24 @@ fn backend(config: ServerConfig) -> BoxedFilter<(impl Reply,)> {
|
|||
.and(state_filter.clone())
|
||||
.and_then(text_handler);
|
||||
|
||||
let text_post =
|
||||
warp::post()
|
||||
.and(warp::path!("create" / String))
|
||||
.and(warp::body::bytes())
|
||||
.and(state_filter.clone())
|
||||
.and_then(text_post_handler);
|
||||
|
||||
let start_time = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("SystemTime returned before UNIX_EPOCH")
|
||||
.as_secs();
|
||||
|
||||
let stats = warp::path!("stats")
|
||||
.and(warp::any().map(move || start_time))
|
||||
.and(state_filter)
|
||||
.and_then(stats_handler);
|
||||
|
||||
socket.or(text).or(stats).boxed()
|
||||
socket.or(text_post).or(text).or(stats).boxed()
|
||||
}
|
||||
|
||||
/// Handler for the `/api/socket/{id}` endpoint.
|
||||
|
@ -172,6 +182,41 @@ async fn text_handler(id: String, state: ServerState) -> Result<impl Reply, Reje
|
|||
})
|
||||
}
|
||||
|
||||
/// Handler for the `/api/text/{id}` endpoint.
|
||||
async fn text_post_handler(language: String, bytes: bytes::Bytes, state: ServerState) -> Result<impl Reply, Rejection> {
|
||||
let mut retry = true;
|
||||
let mut id:String = "".to_string();
|
||||
let maybe_text = String::from_utf8(bytes.to_vec())
|
||||
.map_err(|_| warp::reject());
|
||||
let text = maybe_text.unwrap_or_default();
|
||||
while retry{
|
||||
id = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(6)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
if !state.documents.contains_key(&id){
|
||||
if let Some(db) = state.database.clone() {
|
||||
if let Ok(entryexists) = db.exists(&id).await{
|
||||
if !entryexists {
|
||||
println!("{}", text);
|
||||
let rustpad = Arc::new(Rustpad::from((&language, &text)));
|
||||
tokio::spawn(persister(id.clone(), Arc::clone(&rustpad), db.clone()));
|
||||
state.documents.insert(id.clone(), Document::new(rustpad));
|
||||
retry = false;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
println!("{}", text);
|
||||
let rustpad = Arc::new(Rustpad::from((&language, &text)));
|
||||
state.documents.insert(id.clone(), Document::new(rustpad));
|
||||
retry = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
/// Handler for the `/api/stats` endpoint.
|
||||
async fn stats_handler(start_time: u64, state: ServerState) -> Result<impl Reply, Rejection> {
|
||||
let num_documents = state.documents.len();
|
||||
|
|
|
@ -129,6 +129,27 @@ impl From<PersistedDocument> for Rustpad {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl From<(&String, &String)> for Rustpad {
|
||||
fn from(create: (&String, &String)) -> Self {
|
||||
let language = create.0;
|
||||
let text = create.1;
|
||||
let mut operation = OperationSeq::default();
|
||||
operation.insert(text);
|
||||
|
||||
let rustpad = Self::default();
|
||||
{
|
||||
let mut state = rustpad.state.write();
|
||||
state.text = text.to_string();
|
||||
state.language = Some(language.clone());
|
||||
state.operations.push(UserOperation {
|
||||
id: u64::MAX,
|
||||
operation,
|
||||
})
|
||||
}
|
||||
rustpad
|
||||
}
|
||||
}
|
||||
impl Rustpad {
|
||||
/// Handle a connection from a WebSocket.
|
||||
pub async fn on_connection(&self, socket: WebSocket) {
|
||||
|
|
Loading…
Add table
Reference in a new issue