Browse Source

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.
Matthias Bilger 2 năm trước cách đây
mục cha
commit
cd5bd8fcef

+ 1 - 0
Cargo.lock

@@ -1060,6 +1060,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "bytecount",
+ "bytes",
  "dashmap",
  "dotenv",
  "futures",

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 2843
package-lock.json


+ 1 - 0
rustpad-server/Cargo.toml

@@ -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"

+ 10 - 0
rustpad-server/src/database.rs

@@ -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)
+    }
 }

+ 47 - 2
rustpad-server/src/lib.rs

@@ -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();

+ 21 - 0
rustpad-server/src/rustpad.rs

@@ -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) {

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác