kumo_api_types/
xfer.rs

1use serde::{Deserialize, Serialize};
2use url::Url;
3use utoipa::{ToResponse, ToSchema};
4
5#[derive(Deserialize, Serialize, Debug, Clone, ToSchema, PartialEq)]
6pub struct XferProtocol {
7    /// Expected to be an HTTP url prefix like:
8    /// `https://host.name:8008`
9    /// `http://127.0.0.1:8000`
10    // TODO: support multiple, as well as resolving the hostname
11    // to multiple candidates so that we can immediately retry
12    // transient issues on subsequent candidates
13    #[schema(examples("http://127.0.0.1:8000", "https://host.name:8008"))]
14    pub target: Url,
15}
16
17const XFER_QUEUE_SUFFIX: &str = ".xfer.kumomta.internal";
18
19impl XferProtocol {
20    pub fn is_xfer_queue_name(name: &str) -> bool {
21        name.ends_with(XFER_QUEUE_SUFFIX)
22    }
23
24    pub fn to_queue_name(&self) -> String {
25        format!("{}{XFER_QUEUE_SUFFIX}", self.target)
26    }
27
28    pub fn from_queue_name(name: &str) -> Option<Self> {
29        let name = name.strip_suffix(XFER_QUEUE_SUFFIX)?;
30        let target: Url = name.parse().ok()?;
31        Some(Self { target })
32    }
33}
34
35/// Describes which messages should be transferred to another
36/// kumomta node.
37/// The criteria apply to the scheduled queue associated
38/// with a given message.
39#[derive(Serialize, Deserialize, Debug, ToSchema)]
40pub struct XferV1Request {
41    /// The campaign name to match. If omitted, any campaign will match.
42    #[serde(default)]
43    pub campaign: Option<String>,
44
45    /// The tenant to match. If omitted, any tenant will match.
46    #[serde(default)]
47    pub tenant: Option<String>,
48
49    /// The domain name to match. If omitted, any domain will match.
50    #[serde(default)]
51    #[schema(example = "example.com")]
52    pub domain: Option<String>,
53
54    /// The routing_domain name to match. If omitted, any routing_domain will match.
55    #[serde(default)]
56    pub routing_domain: Option<String>,
57
58    /// Reason to log in the delivery log. Each matching message will log
59    /// with an AdminRebind record to indicate that it was moved from
60    /// its containing queue, and this reason will be included in that record.
61    #[schema(example = "Scaling down")]
62    pub reason: String,
63
64    /// If present, queue_names takes precedence over `campaign`,
65    /// `tenant`, and `domain` and specifies the exact set of
66    /// scheduled queue names to which the xfer applies.
67    #[serde(default, skip_serializing_if = "Vec::is_empty")]
68    pub queue_names: Vec<String>,
69
70    #[serde(flatten)]
71    pub protocol: XferProtocol,
72}
73
74#[derive(Serialize, Deserialize, Debug, ToSchema, ToResponse)]
75pub struct XferV1Response {}
76
77#[derive(Serialize, Deserialize, Debug, ToSchema)]
78pub struct XferCancelV1Request {
79    /// The name of the xfer scheduled queue
80    pub queue_name: String,
81
82    /// Reason to log in the delivery log. Each matching message will log
83    /// with an AdminRebind record to indicate that it was moved from
84    /// its containing queue, and this reason will be included in that record.
85    #[schema(example = "Scaling down")]
86    pub reason: String,
87}
88
89#[derive(Serialize, Deserialize, Debug, ToSchema, ToResponse)]
90pub struct XferCancelV1Response {}