superdoc-sdk 2.25.0

Beta Rust SDK for the SuperDoc document runtime
Documentation
//! Executable adapter for the shared SDK conformance corpus, enabled explicitly.
use crate::{
    generated,
    invoke::Invoker,
    runtime::{process::Transport, routing},
    Client, Error, HostOptions, InvokeOptions, Result,
};
use serde_json::{json, Value};
use std::{collections::BTreeSet, path::Path, sync::Mutex, time::Duration};

#[derive(Default)]
struct Recorder(Mutex<Vec<String>>);
impl Invoker for Recorder {
    async fn invoke(&self, id: &str, _: Value, _: InvokeOptions) -> Result<Value> {
        self.0.lock().unwrap().push(id.to_owned());
        Err(Error::new("RECORDED", "recorded invocation"))
    }
}
fn error(error: Error) -> Value {
    let mut value = json!({"code":error.code});
    if let Some(details) = error.details {
        value["details"] = *details;
    }
    value
}
pub async fn run(cases: &[Value], host: &Path) -> Value {
    let recorder = Recorder::default();
    generated::operations::exercise_callables(&recorder).await;
    let mut ids = recorder.0.into_inner().unwrap();
    let rows: Vec<Value> = serde_json::from_str(generated::OPERATION_INVENTORY_JSON).unwrap();
    assert_eq!(
        ids,
        rows.iter()
            .map(|row| row["operationId"].as_str().unwrap().to_owned())
            .collect::<Vec<_>>()
    );
    let callables: Vec<_> = rows.iter().map(|row| json!({"path":format!("doc.{}",row["methodPath"].as_str().unwrap()),"operationId":row["operationId"]})).collect();
    ids.sort();
    let inventory = json!({"operations":ids,"callables":callables});
    let mut results = serde_json::Map::new();
    for case in cases {
        let value = run_case(case, host).await.unwrap_or_else(error);
        results.insert(case["id"].as_str().unwrap().to_owned(), value);
    }
    json!({"inventory":inventory,"cases":results,"policy":crate::runtime::policy()})
}
async fn run_case(case: &Value, host: &Path) -> Result<Value> {
    let options = InvokeOptions::default();
    let kind = case["kind"].as_str().unwrap();
    if kind == "document-route" {
        return Ok(json!(routing::can_open_document(&case["params"], &options)));
    }
    if kind == "document-invoke" {
        let (method, params) = routing::document_request(
            case["params"]["sessionId"].as_str().unwrap(),
            &case["operation"],
            &case["params"],
            &options,
            &BTreeSet::new(),
        )?;
        return Ok(json!({"method":method,"params":params}));
    }
    let mut host_options =
        HostOptions::new(std::env::var("SUPERDOC_SDK_TEST_NODE").unwrap_or_else(|_| "node".into()));
    host_options.prefix_args.push(host.to_str().unwrap().into());
    host_options.env.insert(
        "SUPERDOC_CONFORMANCE_MODE".into(),
        case["hostMode"].as_str().unwrap_or(kind).into(),
    );
    if kind == "session" {
        let client = Client::connect(host_options).await?;
        let result = async {
            let doc = client
                .open(&generated::types::DocOpenParams::new().with_doc("fixture.docx".into()))
                .await?;
            let text = doc
                .api()
                .get_text(&generated::types::DocGetTextBoundParams::new())
                .await?;
            doc.close(&generated::types::DocCloseBoundParams::new())
                .await?;
            let code = doc
                .api()
                .get_text(&generated::types::DocGetTextBoundParams::new())
                .await
                .unwrap_err()
                .code;
            Ok(json!({"text":text,"closedCode":code}))
        }
        .await;
        client.shutdown().await?;
        return result;
    }
    let transport = Transport::connect(host_options).await?;
    let result=async {
        let mut request=json!({"argv":routing::argv(&case["operation"],&case["params"],&options,None)?,"stdinBase64":case["stdinBase64"].as_str().unwrap_or("")});
        if let Some(auth)=case.get("auth") {
            if !transport.features().contains("collaboration.auth.perOpen") {return Err(Error::new("CAPABILITY_UNSUPPORTED","host does not support per-open authentication"));}
            request["collaborationAuth"]=auth.clone();
        }
        let result=transport.request("cli.invoke",request,None,Duration::from_secs(10),false,false).await?;
        routing::map_cli(&case["operation"],result)
    }.await;
    transport.shutdown().await?;
    result
}