use serde_json::Value;
pub const TRUST_TASK_ERROR_PREFIX: &str = "https://trusttasks.org/spec/trust-task-error/";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Inbound {
Request,
Response,
Error,
}
impl Inbound {
#[must_use]
pub fn may_dispatch(self) -> bool {
!matches!(self, Self::Error)
}
#[must_use]
pub fn may_answer(self) -> bool {
!matches!(self, Self::Error)
}
}
#[must_use]
pub fn classify(document: &Value) -> Inbound {
let type_uri = document
.get("type")
.and_then(Value::as_str)
.unwrap_or_default();
if type_uri.starts_with(TRUST_TASK_ERROR_PREFIX) {
return Inbound::Error;
}
match document.get("threadId").and_then(Value::as_str) {
Some(t) if !t.is_empty() => Inbound::Response,
_ => Inbound::Request,
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn a_fresh_document_is_a_request() {
let doc =
json!({"id": "urn:uuid:1", "type": "https://trusttasks.org/spec/keys/create/0.1"});
assert_eq!(classify(&doc), Inbound::Request);
assert!(classify(&doc).may_dispatch());
assert!(classify(&doc).may_answer());
}
#[test]
fn a_threaded_document_is_response_shaped_but_may_still_be_a_request() {
let doc = json!({
"id": "urn:uuid:2",
"threadId": "urn:uuid:1",
"type": "https://trusttasks.org/spec/did-management/did/problem-report/0.1",
});
assert_eq!(classify(&doc), Inbound::Response);
assert!(classify(&doc).may_dispatch());
assert!(classify(&doc).may_answer());
}
#[test]
fn an_error_is_terminal_even_when_it_is_threaded() {
let doc = json!({
"id": "urn:uuid:3",
"threadId": "urn:uuid:1",
"type": "https://trusttasks.org/spec/trust-task-error/0.5",
"payload": {"code": "malformed_request"},
});
assert_eq!(
classify(&doc),
Inbound::Error,
"error-ness outranks threading"
);
assert!(!classify(&doc).may_answer(), "answering this is the loop");
}
#[test]
fn an_unthreaded_error_is_still_never_answered() {
let doc =
json!({"id": "urn:uuid:4", "type": "https://trusttasks.org/spec/trust-task-error/0.5"});
assert_eq!(classify(&doc), Inbound::Error);
assert!(!classify(&doc).may_answer());
}
#[test]
fn a_future_error_version_is_still_an_error() {
let doc = json!({"id": "urn:uuid:5", "type": format!("{TRUST_TASK_ERROR_PREFIX}9.9")});
assert_eq!(classify(&doc), Inbound::Error);
}
}