implement basic KV binding
This commit is contained in:
parent
0547cdd0c3
commit
243a64b7b9
|
@ -13,6 +13,7 @@ default = ["console_error_panic_hook", "wee_alloc"]
|
|||
[dependencies]
|
||||
cfg-if = "0.1.2"
|
||||
lazy_static = "1.4"
|
||||
js-sys = "0.3"
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
serde_json = "1.0"
|
||||
wasm-bindgen = "0.2"
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// Utility functions and structs for the blogging system
|
||||
// Due to limitations of the Cloudflare Workers KV, we do not
|
||||
// store the entire state in one record; instead, different
|
||||
// parts are stroed in different records. This also increases
|
||||
// efficiency, since the program won't need to load anything
|
||||
// unnecessary from KV.
|
||||
use crate::store;
|
||||
use crate::utils::*;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::vec::Vec;
|
||||
|
||||
// A list of the UUIDs of all published blog posts
|
||||
// This should be SORTED with the newest posts at lower indices (closer to 0)
|
||||
// The user may edit this via KV UI to change ordering and such
|
||||
// by default new posts are always added to the top
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct PostsList(pub Vec<String>);
|
||||
|
||||
impl PostsList {
|
||||
pub async fn load() -> PostsList {
|
||||
match store::get_obj("posts_list").await {
|
||||
Ok(v) => PostsList(v),
|
||||
// Don't panic on empty
|
||||
// TODO: What if the user messed up when editing?
|
||||
// That would cause a decode failure and all data will be gone
|
||||
// if a new post is added or updated (overwriting the KV value)
|
||||
// under this logic
|
||||
// (if no new post is added then nothing bad would happen;
|
||||
// the user would probably notice when trying to visit the blog home page)
|
||||
Err(_) => PostsList(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_post(&self, uuid: &str) -> bool {
|
||||
self.0.contains(&uuid.into())
|
||||
}
|
||||
|
||||
// Add a post to the list and then update the record in KV
|
||||
// Also consumes self, as this should normally be the last action
|
||||
// in an API call
|
||||
pub async fn add_post(mut self, uuid: &str) -> MyResult<()> {
|
||||
self.0.insert(0, uuid.into());
|
||||
store::put_obj_pretty("posts_list", self.0).await
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ extern crate lazy_static;
|
|||
#[macro_use]
|
||||
mod utils;
|
||||
mod router;
|
||||
mod store;
|
||||
mod blog;
|
||||
mod sn;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
|
13
src/sn.rs
13
src/sn.rs
|
@ -1,5 +1,5 @@
|
|||
// Interface for Standard Notes (Actions)
|
||||
use crate::CONFIG;
|
||||
use crate::{CONFIG, blog};
|
||||
use crate::router::Router;
|
||||
use crate::utils::*;
|
||||
use serde::{Serialize, Serializer};
|
||||
|
@ -28,8 +28,17 @@ async fn get_actions(_req: Request, url: Url) -> MyResult<Response> {
|
|||
let origin = url.origin();
|
||||
let mut actions = vec![];
|
||||
|
||||
// Show different options depending on whether the post already exists
|
||||
let post_exists = match params.get("item_uuid") {
|
||||
Some(uuid) => {
|
||||
let posts = blog::PostsList::load().await;
|
||||
posts.has_post(&uuid)
|
||||
},
|
||||
None => false
|
||||
};
|
||||
|
||||
actions.push(Action {
|
||||
label: "Publish".into(),
|
||||
label: if post_exists { "Update".into() } else { "Publish".into() },
|
||||
url: format!("{}/post?secret={}", origin, CONFIG.secret.clone()),
|
||||
verb: Verb::Post,
|
||||
context: Context::Item,
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Bindings to Cloudflare Workers KV
|
||||
use crate::utils::*;
|
||||
use js_sys::Promise;
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = PAPRIKA, js_name = "get")]
|
||||
fn kv_get(key: &str) -> Promise;
|
||||
#[wasm_bindgen(js_namespace = PAPRIKA, js_name = "put")]
|
||||
fn kv_put_str(key: &str, value: &str) -> Promise;
|
||||
}
|
||||
|
||||
pub async fn get_str(key: &str) -> MyResult<String> {
|
||||
Ok(JsFuture::from(kv_get(key)).await.internal_err()?.as_string().unwrap())
|
||||
}
|
||||
|
||||
pub async fn get_obj<T: DeserializeOwned>(key: &str) -> MyResult<T> {
|
||||
let res = get_str(key).await?;
|
||||
Ok(serde_json::from_str(&res).internal_err()?)
|
||||
}
|
||||
|
||||
pub async fn put_str(key: &str, value: &str) -> MyResult<()> {
|
||||
JsFuture::from(kv_put_str(key, value)).await.internal_err()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn put_obj<T: Serialize>(key: &str, value: T) -> MyResult<()> {
|
||||
put_str(key, &serde_json::to_string(&value).internal_err()?).await
|
||||
}
|
||||
|
||||
// Some objects may be available for manual editing; thus making it pretty may be helpful
|
||||
// For example, the user may want to manually edit the order in which posts appear
|
||||
pub async fn put_obj_pretty<T: Serialize>(key: &str, value: T) -> MyResult<()> {
|
||||
put_str(key, &serde_json::to_string_pretty(&value).internal_err()?).await
|
||||
}
|
Loading…
Reference in New Issue