onvif_server/error.rs
1use soap_server::fault::SoapFault;
2
3/// ONVIF-specific error type that maps to SOAP faults with the ONVIF ter: namespace.
4///
5/// Every `into_soap_fault()` call produces a detail field containing
6/// `xmlns:ter="http://www.onvif.org/ver10/error"` as required by the ONVIF spec.
7#[derive(Debug, thiserror::Error)]
8pub enum OnvifError {
9 /// The requested action has not yet been implemented.
10 #[error("Action not implemented")]
11 NotImplemented,
12 /// The caller supplied an invalid argument value.
13 #[error("Invalid argument: {0}")]
14 InvalidArgument(String),
15 /// The device does not support the requested action.
16 #[error("Action not supported")]
17 ActionNotSupported,
18}
19
20impl OnvifError {
21 /// Convert this error into a `SoapFault` with an ONVIF-namespaced detail element.
22 ///
23 /// The `xmlns:ter` declaration is embedded in the detail string because
24 /// soap-server's envelope does not inject it automatically.
25 pub fn into_soap_fault(self) -> SoapFault {
26 match self {
27 OnvifError::NotImplemented | OnvifError::ActionNotSupported => {
28 let subcode = "ter:ActionNotSupported";
29 let detail = format!(
30 r#"<ter:fault xmlns:ter="http://www.onvif.org/ver10/error"><ter:subcode>{subcode}</ter:subcode></ter:fault>"#
31 );
32 // The detail is well-formed XML, so route it via detail_xml: the SOAP 1.2
33 // renderer only emits detail_xml inside <env:Detail> (the text `detail`
34 // field is dropped as element-only, per F-3). Using `detail` here would
35 // silently lose the ter: subcode on the wire for every ONVIF fault.
36 SoapFault::receiver("Action not supported").with_detail_xml(detail)
37 }
38 OnvifError::InvalidArgument(msg) => {
39 let subcode = "ter:InvalidArgVal";
40 let detail = format!(
41 r#"<ter:fault xmlns:ter="http://www.onvif.org/ver10/error"><ter:subcode>{subcode}</ter:subcode></ter:fault>"#
42 );
43 SoapFault::sender(msg).with_detail_xml(detail)
44 }
45 }
46 }
47}
48
49/// Convenience function returning `Err(OnvifError::NotImplemented)`.
50///
51/// Service trait implementations use this as a one-liner stub until the
52/// real implementation is added.
53pub fn not_implemented<T>() -> Result<T, OnvifError> {
54 Err(OnvifError::NotImplemented)
55}