sausage-plugin part 2: import! with typed clients (sausage_interface::client_rs), TCP endpoints with rpc.endpoint, examples
Part 1 fixes: complete stdout writes, buffered stdin, Rust type names in schemas, enum variant docs, -32603 for serde errors in handlers, crate docs and modules. End-to-end check of a generated consumer through a fake core.
This commit is contained in:
+40
-27
@@ -1,30 +1,43 @@
|
||||
//! Keep notes in `/data/notes.json` and publish them at `/public/notes.txt`.
|
||||
use sausage_actor::{json, messages, reply};
|
||||
|
||||
const DATA: &str = "/data/notes.json";
|
||||
|
||||
fn save(notes: &[String]) {
|
||||
std::fs::write(DATA, serde_json::to_string(notes).unwrap()).unwrap();
|
||||
std::fs::write("/public/notes.txt", notes.join("\n") + "\n").unwrap();
|
||||
//! Persistent notes. Each request reads the shared file instead of process memory.
|
||||
use sausage_plugin::serde_json;
|
||||
use sausage_plugin::{Result, lock, rpc, schema, state_dir, write_atomic};
|
||||
struct Notes;
|
||||
/// Parameters for a new note.
|
||||
#[schema]
|
||||
struct AddParams {
|
||||
/// The complete note text, including any newlines.
|
||||
text: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut notes: Vec<String> = std::fs::read_to_string(DATA)
|
||||
.ok()
|
||||
.and_then(|text| serde_json::from_str(&text).ok())
|
||||
.unwrap_or_default();
|
||||
for message in messages() {
|
||||
let body = &message.body;
|
||||
let response = match message.kind() {
|
||||
"add" => {
|
||||
notes.push(body["text"].as_str().unwrap_or_default().to_string());
|
||||
save(¬es);
|
||||
json!({"type": "added", "count": notes.len()})
|
||||
}
|
||||
"list" => json!({"type": "notes", "items": notes}),
|
||||
"crash" => panic!("asked to crash"),
|
||||
_ => json!({"type": "error", "reason": "unknown message"}),
|
||||
};
|
||||
let _ = reply(&message, response);
|
||||
/// The result after a note enters the list.
|
||||
#[schema]
|
||||
struct Added {
|
||||
/// The number of notes, including the new note.
|
||||
count: usize,
|
||||
}
|
||||
#[rpc]
|
||||
impl Notes {
|
||||
/// Add a note and return the new count.
|
||||
async fn add(&self, AddParams { text }: AddParams) -> Result<Added> {
|
||||
let path = state_dir().join("notes.json");
|
||||
let _guard = lock(&path).await?;
|
||||
let mut notes = load()?;
|
||||
notes.push(text);
|
||||
std::fs::create_dir_all(state_dir())?;
|
||||
write_atomic(path, serde_json::to_vec(¬es)?)?;
|
||||
Ok(Added { count: notes.len() })
|
||||
}
|
||||
/// List all notes, oldest first.
|
||||
fn list(&self) -> Result<Vec<String>> {
|
||||
load()
|
||||
}
|
||||
}
|
||||
fn load() -> Result<Vec<String>> {
|
||||
match std::fs::read(state_dir().join("notes.json")) {
|
||||
Ok(bytes) => Ok(serde_json::from_slice(&bytes)?),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(vec![]),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
sausage_plugin::run(Notes)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user