sdk: readable clients (no Empty wrapper, no unused error module), documented examples with tests
This commit is contained in:
+13
-7
@@ -68,25 +68,31 @@ pub fn method<P: Params, R: SchemaType>(doc: &mut Value, name: &str, docs: &str)
|
||||
"schema": field,
|
||||
})
|
||||
}).collect();
|
||||
doc["x-sdk-input"]
|
||||
.as_object_mut()
|
||||
.unwrap()
|
||||
.extend(definitions);
|
||||
if !params.is_empty() {
|
||||
doc["x-sdk-input"]
|
||||
.as_object_mut()
|
||||
.unwrap()
|
||||
.extend(definitions);
|
||||
}
|
||||
let mut output = generator(true);
|
||||
let result_schema = serde_json::to_value(output.subschema_for::<R>()).unwrap();
|
||||
doc["x-sdk-output"]
|
||||
.as_object_mut()
|
||||
.unwrap()
|
||||
.extend(output.take_definitions(true));
|
||||
doc["methods"].as_array_mut().unwrap().push(json!({
|
||||
let has_params = !params.is_empty();
|
||||
let mut method = json!({
|
||||
"name":name,
|
||||
"summary":docs.split("\n\n").next().unwrap_or_default(),
|
||||
"description":docs,
|
||||
"paramStructure":"by-name",
|
||||
"params":params,
|
||||
"result":{"name":"result","schema":result_schema},
|
||||
"x-sausage-params":params_ref,
|
||||
}));
|
||||
});
|
||||
if has_params {
|
||||
method["x-sausage-params"] = params_ref;
|
||||
}
|
||||
doc["methods"].as_array_mut().unwrap().push(method);
|
||||
}
|
||||
|
||||
/// Resolve shared schema names after all methods contribute their contracts.
|
||||
|
||||
@@ -33,10 +33,6 @@
|
||||
"text"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"Empty": {
|
||||
"description": "Empty parameters for methods without arguments.",
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -56,10 +52,61 @@
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"summary": "Publish a control endpoint until EOF.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "Publish a control endpoint until EOF."
|
||||
},
|
||||
{
|
||||
"description": "Forward detached progress through the real core.",
|
||||
"name": "relay",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"summary": "Forward detached progress through the real core."
|
||||
},
|
||||
{
|
||||
"description": "Send progress before the final result.",
|
||||
"name": "progress",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"summary": "Send progress before the final result."
|
||||
},
|
||||
{
|
||||
"description": "Start a detached service that survives this caller.",
|
||||
"name": "launch",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Start a detached service that survives this caller."
|
||||
},
|
||||
{
|
||||
"description": "Keep the process alive until the core closes stdin.",
|
||||
"name": "service",
|
||||
"paramStructure": "by-name",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "result",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Keep the process alive until the core closes stdin."
|
||||
},
|
||||
{
|
||||
"description": "Add two numbers.\n\nThe result is their sum.",
|
||||
@@ -136,10 +183,7 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Return an internal serialization error.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "Return an internal serialization error."
|
||||
},
|
||||
{
|
||||
"description": "Return a deliberate error.",
|
||||
@@ -152,10 +196,7 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Return a deliberate error.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "Return a deliberate error."
|
||||
},
|
||||
{
|
||||
"description": "Exercise calls, notifications, and advisory locks.",
|
||||
@@ -168,10 +209,7 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Exercise calls, notifications, and advisory locks.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "Exercise calls, notifications, and advisory locks."
|
||||
},
|
||||
{
|
||||
"description": "Drop an acquisition before the core grants its lock.",
|
||||
@@ -184,10 +222,7 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Drop an acquisition before the core grants its lock.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "Drop an acquisition before the core grants its lock."
|
||||
},
|
||||
{
|
||||
"description": "Wait until EOF, then run the stop hook.",
|
||||
@@ -200,10 +235,7 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Wait until EOF, then run the stop hook.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "Wait until EOF, then run the stop hook."
|
||||
},
|
||||
{
|
||||
"description": "Keep the process alive with a background call.",
|
||||
@@ -216,10 +248,7 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": "Keep the process alive with a background call.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "Keep the process alive with a background call."
|
||||
}
|
||||
],
|
||||
"openrpc": "1.2.6",
|
||||
@@ -239,10 +268,7 @@
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"summary": "Report progress and return a stable counter.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "Report progress and return a stable counter."
|
||||
},
|
||||
{
|
||||
"description": "End the endpoint process after the response.",
|
||||
@@ -255,10 +281,7 @@
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"summary": "End the endpoint process after the response.",
|
||||
"x-sausage-params": {
|
||||
"$ref": "#/components/schemas/Empty"
|
||||
}
|
||||
"summary": "End the endpoint process after the response."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -11,6 +11,23 @@ impl Consumer {
|
||||
.on_notify(|name, _| eprintln!("typed progress: {name}"))
|
||||
.await? as i32)
|
||||
}
|
||||
/// Connect to a world endpoint from the real core.
|
||||
async fn world_endpoint(&self) -> Result<u64> {
|
||||
let control = probe::control::connect("/state/control").await?;
|
||||
let received = std::rc::Rc::new(std::cell::Cell::new(false));
|
||||
let progress = received.clone();
|
||||
let result = control
|
||||
.stats()
|
||||
.on_notify(move |name, value| {
|
||||
progress.set(name == "endpoint-progress" && value["value"] == 7);
|
||||
})
|
||||
.await?;
|
||||
assert!(
|
||||
received.get(),
|
||||
"the endpoint must deliver progress before its result"
|
||||
);
|
||||
Ok(result)
|
||||
}
|
||||
/// Connect to the provider's endpoint and receive its notification.
|
||||
async fn endpoint(&self) -> Result<u64> {
|
||||
let control = probe::control::connect("/endpoint").await?;
|
||||
|
||||
@@ -28,6 +28,32 @@ impl Probe {
|
||||
async fn serve(&self) -> Result<()> {
|
||||
sausage_plugin::listen("/endpoint", std::rc::Rc::new(Control)).await
|
||||
}
|
||||
/// Forward detached progress through the real core.
|
||||
async fn relay(&self) -> Result<i32> {
|
||||
call("probe.progress", json!({}))
|
||||
.detach()
|
||||
.on_notify(move |name, params| {
|
||||
Ctx::default().notify(name, params).unwrap();
|
||||
})
|
||||
.await
|
||||
.map(|value| value.as_i64().unwrap() as i32)
|
||||
}
|
||||
/// Send progress before the final result.
|
||||
fn progress(&self, ctx: &Ctx) -> Result<i32> {
|
||||
ctx.notify("step", json!({"done":true}))?;
|
||||
Ok(42)
|
||||
}
|
||||
/// Start a detached service that survives this caller.
|
||||
async fn launch(&self) -> Result<String> {
|
||||
Ok(sausage_plugin::serde_json::from_value(
|
||||
call("probe.service", json!({})).detach().await?,
|
||||
)?)
|
||||
}
|
||||
/// Keep the process alive until the core closes stdin.
|
||||
async fn service(&self) -> Result<String> {
|
||||
sausage_plugin::listen("/state/control", std::rc::Rc::new(Control)).await?;
|
||||
Ok(sausage_plugin::pid())
|
||||
}
|
||||
/// Add two numbers.
|
||||
///
|
||||
/// The result is their sum.
|
||||
|
||||
@@ -49,6 +49,14 @@ impl Plugin {
|
||||
#[test]
|
||||
fn discovery_and_dispatch() {
|
||||
let doc = Plugin.discover();
|
||||
assert!(doc["components"]["schemas"].get("Empty").is_none());
|
||||
let choice = doc["methods"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|m| m["name"] == "choice")
|
||||
.unwrap();
|
||||
assert!(choice.get("x-sausage-params").is_none());
|
||||
assert!(
|
||||
doc["x-sausage-endpoints"]["control"]["methods"]
|
||||
.as_array()
|
||||
|
||||
Reference in New Issue
Block a user