1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! Data types used when interacting with the control interface of a wasmCloud lattice

use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use crate::ComponentId;

/// A control interface response that wraps a response payload, a success flag, and a message
/// with additional context if necessary.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CtlResponse<T> {
    /// Whether the request succeeded
    pub success: bool,
    /// A message with additional context about the response
    pub message: String,
    /// The response data, if any
    #[serde(skip_serializing_if = "Option::is_none")]
    pub response: Option<T>,
}

impl<T> CtlResponse<T> {
    pub fn ok(response: T) -> Self {
        CtlResponse {
            success: true,
            message: "".to_string(),
            response: Some(response),
        }
    }
}

impl CtlResponse<()> {
    /// Helper function to return a successful response without
    /// a message or a payload.
    pub fn success() -> Self {
        CtlResponse {
            success: true,
            message: "".to_string(),
            response: None,
        }
    }

    /// Helper function to return an unsuccessful response with
    /// a message but no payload. Note that this implicitly is
    /// typing the inner payload as `()` for efficiency.
    pub fn error(message: &str) -> Self {
        CtlResponse {
            success: false,
            message: message.to_string(),
            response: None,
        }
    }
}

#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ScaleComponentCommand {
    /// Image reference for the component.
    #[serde(default)]
    pub component_ref: String,
    /// Unique identifier of the component to scale.
    pub component_id: ComponentId,
    /// Optional set of annotations used to describe the nature of this component scale command. For
    /// example, autonomous agents may wish to "tag" scale requests as part of a given deployment
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub annotations: Option<HashMap<String, String>>,
    /// The maximum number of concurrent executing instances of this component. Setting this to `0` will
    /// stop the component.
    // NOTE: renaming to `count` lets us remain backwards compatible for a few minor versions
    #[serde(default, alias = "count", rename = "count")]
    pub max_instances: u32,
    /// Host ID on which to scale this component
    #[serde(default)]
    pub host_id: String,
    /// A list of named configs to use for this component. It is not required to specify a config.
    /// Configs are merged together before being given to the component, with values from the right-most
    /// config in the list taking precedence. For example, given ordered configs foo {a: 1, b: 2},
    /// bar {b: 3, c: 4}, and baz {c: 5, d: 6}, the resulting config will be: {a: 1, b: 3, c: 5, d:
    /// 6}
    #[serde(default)]
    pub config: Vec<String>,
}

/// A command sent to a host requesting a capability provider be started with the
/// given link name and optional configuration.
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct StartProviderCommand {
    /// Optional set of annotations used to describe the nature of this provider start command. For
    /// example, autonomous agents may wish to "tag" start requests as part of a given deployment
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub annotations: Option<HashMap<String, String>>,
    /// Unique identifier of the provider to start.
    pub provider_id: ComponentId,
    /// A list of named configs to use for this provider. It is not required to specify a config.
    /// Configs are merged together before being given to the provider, with values from the right-most
    /// config in the list taking precedence. For example, given ordered configs foo {a: 1, b: 2},
    /// bar {b: 3, c: 4}, and baz {c: 5, d: 6}, the resulting config will be: {a: 1, b: 3, c: 5, d:
    /// 6}
    #[serde(default)]
    pub config: Vec<String>,
    /// The host ID on which to start the provider
    #[serde(default)]
    pub host_id: String,
    /// The image reference of the provider to be started
    #[serde(default)]
    pub provider_ref: String,
}

/// A command sent to request that the given host purge and stop
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct StopHostCommand {
    /// The ID of the target host
    #[serde(default)]
    pub host_id: String,
    /// An optional timeout, in seconds
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub timeout: Option<u64>,
}

/// A request to stop the given provider on the indicated host
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct StopProviderCommand {
    /// Host ID on which to stop the provider
    #[serde(default)]
    pub host_id: String,
    /// Unique identifier for the provider to stop.
    #[serde(default, alias = "provider_ref")]
    pub provider_id: ComponentId,
}

/// A command instructing a specific host to perform a live update
/// on the indicated component by supplying a new image reference. Note that
/// live updates are only possible through image references
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct UpdateComponentCommand {
    /// The component's 56-character unique ID
    #[serde(default)]
    pub component_id: ComponentId,
    /// Optional set of annotations used to describe the nature of this
    /// update request. Only component instances that have matching annotations
    /// will be upgraded, allowing for instance isolation by
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub annotations: Option<HashMap<String, String>>,
    /// The host ID of the host to perform the live update
    #[serde(default)]
    pub host_id: String,
    /// The new image reference of the upgraded version of this component
    #[serde(default)]
    pub new_component_ref: String,
}