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:
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "sdk-consumer"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
[workspace]
|
||||
[dependencies]
|
||||
sausage-plugin = { path = "../../.." }
|
||||
@@ -0,0 +1,268 @@
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Add": {
|
||||
"description": "The values to add.",
|
||||
"properties": {
|
||||
"a": {
|
||||
"description": "The first number.",
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"b": {
|
||||
"description": "The second number.",
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"a",
|
||||
"b"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"Echo": {
|
||||
"description": "A large payload.",
|
||||
"properties": {
|
||||
"text": {
|
||||
"description": "The text to return unchanged.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"text"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"Empty": {
|
||||
"description": "Empty parameters for methods without arguments.",
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"title": "sdk-probe",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"methods": [
|
||||
{
|
||||
"description": "Publish a control endpoint until EOF.",
|
||||
"name": "serve",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"summary": "Publish a control endpoint until EOF.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Add two numbers.\n\nThe result is their sum.",
|
||||
"name": "add",
|
||||
"paramStructure": "by-name",
|
||||
"params": [
|
||||
{
|
||||
"description": "The first number.",
|
||||
"name": "a",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"description": "The first number.",
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "The second number.",
|
||||
"name": "b",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"description": "The second number.",
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"summary": "Add two numbers.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Add"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Echo a payload larger than a host I/O buffer.",
|
||||
"name": "echo",
|
||||
"paramStructure": "by-name",
|
||||
"params": [
|
||||
{
|
||||
"description": "The text to return unchanged.",
|
||||
"name": "text",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"description": "The text to return unchanged.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Echo a payload larger than a host I/O buffer.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Echo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Return an internal serialization error.",
|
||||
"name": "serde_error",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Return an internal serialization error.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Return a deliberate error.",
|
||||
"name": "fail",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Return a deliberate error.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Exercise calls, notifications, and advisory locks.",
|
||||
"name": "exercise",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Exercise calls, notifications, and advisory locks.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Drop an acquisition before the core grants its lock.",
|
||||
"name": "late",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Drop an acquisition before the core grants its lock.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Wait until EOF, then run the stop hook.",
|
||||
"name": "wait",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Wait until EOF, then run the stop hook.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Keep the process alive with a background call.",
|
||||
"name": "start",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Keep the process alive with a background call.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
}
|
||||
],
|
||||
"openrpc": "1.2.6",
|
||||
"x-sausage-endpoints": {
|
||||
"control": {
|
||||
"methods": [
|
||||
{
|
||||
"description": "Report progress and return a stable counter.",
|
||||
"name": "stats",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"summary": "Report progress and return a stable counter.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "End the endpoint process after the response.",
|
||||
"name": "stop",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"summary": "End the endpoint process after the response.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"x-sausage-grace": 12,
|
||||
"x-sausage-imports": {}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//! Consumer of the probe's actual discovered interface.
|
||||
use sausage_plugin::{Result, rpc};
|
||||
sausage_plugin::import!("probe");
|
||||
struct Consumer;
|
||||
#[rpc]
|
||||
impl Consumer {
|
||||
/// Route an imported call through the core.
|
||||
async fn run(&self) -> Result<i32> {
|
||||
Ok(probe::add(probe::Add { a: 2, b: 3 })
|
||||
.detach()
|
||||
.on_notify(|name, _| eprintln!("typed progress: {name}"))
|
||||
.await? as i32)
|
||||
}
|
||||
/// Connect to the provider's endpoint and receive its notification.
|
||||
async fn endpoint(&self) -> Result<u64> {
|
||||
let control = probe::control::connect("/endpoint").await?;
|
||||
control
|
||||
.stats()
|
||||
.on_notify(|name, _| eprintln!("endpoint notification: {name}"))
|
||||
.await
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
sausage_plugin::run(Consumer)
|
||||
}
|
||||
@@ -16,14 +16,32 @@ struct Retired {
|
||||
/// The previous hash.
|
||||
previous: String,
|
||||
}
|
||||
#[rpc(grace_seconds = 12)]
|
||||
/// A large payload.
|
||||
#[schema]
|
||||
struct Echo {
|
||||
/// The text to return unchanged.
|
||||
text: String,
|
||||
}
|
||||
#[rpc(grace_seconds = 12,endpoints(control=Control))]
|
||||
impl Probe {
|
||||
/// Publish a control endpoint until EOF.
|
||||
async fn serve(&self) -> Result<()> {
|
||||
sausage_plugin::listen("/endpoint", std::rc::Rc::new(Control)).await
|
||||
}
|
||||
/// Add two numbers.
|
||||
///
|
||||
/// The result is their sum.
|
||||
fn add(&self, p: Add) -> Result<i32> {
|
||||
Ok(p.a + p.b)
|
||||
}
|
||||
/// Echo a payload larger than a host I/O buffer.
|
||||
fn echo(&self, p: Echo) -> Result<String> {
|
||||
Ok(p.text)
|
||||
}
|
||||
/// Return an internal serialization error.
|
||||
fn serde_error(&self) -> Result<String> {
|
||||
Ok(sausage_plugin::serde_json::from_str::<String>("invalid")?)
|
||||
}
|
||||
/// Return a deliberate error.
|
||||
fn fail(&self) -> Result<String> {
|
||||
Err(sausage_plugin::Error::new(-32010, "deliberate"))
|
||||
@@ -109,6 +127,20 @@ async fn join(
|
||||
})
|
||||
.await
|
||||
}
|
||||
struct Control;
|
||||
#[rpc]
|
||||
impl Control {
|
||||
/// Report progress and return a stable counter.
|
||||
fn stats(&self, ctx: &Ctx) -> Result<u64> {
|
||||
ctx.notify("endpoint-progress", json!({"value":7}))?;
|
||||
Ok(7)
|
||||
}
|
||||
/// End the endpoint process after the response.
|
||||
fn stop(&self, ctx: &Ctx) -> Result<()> {
|
||||
ctx.exit_after_response();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
sausage_plugin::run(Probe)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user