golem_api_grpc/
lib.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[cfg(test)]
16test_r::enable!();
17
18#[allow(clippy::large_enum_variant)]
19pub mod proto {
20    use crate::proto::golem::worker::UpdateMode;
21    use bincode::de::Decoder;
22    use bincode::enc::Encoder;
23    use bincode::error::{DecodeError, EncodeError};
24    use bincode::{Decode, Encode};
25    use golem_wasm_ast::analysis::{
26        AnalysedExport, AnalysedFunction, AnalysedFunctionParameter, AnalysedFunctionResult,
27        AnalysedInstance,
28    };
29    use uuid::Uuid;
30
31    tonic::include_proto!("mod");
32
33    pub const FILE_DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!("services");
34
35    impl From<Uuid> for golem::common::Uuid {
36        fn from(value: Uuid) -> Self {
37            let (high_bits, low_bits) = value.as_u64_pair();
38            golem::common::Uuid {
39                high_bits,
40                low_bits,
41            }
42        }
43    }
44
45    impl From<golem::common::Uuid> for Uuid {
46        fn from(value: golem::common::Uuid) -> Self {
47            let high_bits = value.high_bits;
48            let low_bits = value.low_bits;
49            Uuid::from_u64_pair(high_bits, low_bits)
50        }
51    }
52
53    impl TryFrom<crate::proto::golem::component::FunctionResult> for AnalysedFunctionResult {
54        type Error = String;
55
56        fn try_from(
57            value: crate::proto::golem::component::FunctionResult,
58        ) -> Result<Self, Self::Error> {
59            Ok(Self {
60                typ: (&value.typ.ok_or("Missing typ")?).try_into()?,
61            })
62        }
63    }
64
65    impl From<AnalysedFunctionResult> for crate::proto::golem::component::FunctionResult {
66        fn from(value: AnalysedFunctionResult) -> Self {
67            Self {
68                typ: Some((&value.typ).into()),
69            }
70        }
71    }
72
73    impl TryFrom<crate::proto::golem::component::ExportInstance> for AnalysedInstance {
74        type Error = String;
75
76        fn try_from(
77            value: crate::proto::golem::component::ExportInstance,
78        ) -> Result<Self, Self::Error> {
79            Ok(Self {
80                name: value.name,
81                functions: value
82                    .functions
83                    .into_iter()
84                    .map(|function| function.try_into())
85                    .collect::<Result<_, _>>()?,
86            })
87        }
88    }
89
90    impl From<AnalysedInstance> for crate::proto::golem::component::ExportInstance {
91        fn from(value: AnalysedInstance) -> Self {
92            Self {
93                name: value.name,
94                functions: value
95                    .functions
96                    .into_iter()
97                    .map(|function| function.into())
98                    .collect(),
99            }
100        }
101    }
102
103    impl TryFrom<crate::proto::golem::component::ExportFunction> for AnalysedFunction {
104        type Error = String;
105
106        fn try_from(
107            value: crate::proto::golem::component::ExportFunction,
108        ) -> Result<Self, Self::Error> {
109            Ok(Self {
110                name: value.name,
111                parameters: value
112                    .parameters
113                    .into_iter()
114                    .map(|parameter| parameter.try_into())
115                    .collect::<Result<_, _>>()?,
116                result: value.result.map(|result| result.try_into()).transpose()?,
117            })
118        }
119    }
120
121    impl From<AnalysedFunction> for crate::proto::golem::component::ExportFunction {
122        fn from(value: AnalysedFunction) -> Self {
123            Self {
124                name: value.name,
125                parameters: value
126                    .parameters
127                    .into_iter()
128                    .map(|parameter| parameter.into())
129                    .collect(),
130                result: value.result.map(|result| result.into()),
131            }
132        }
133    }
134
135    impl TryFrom<crate::proto::golem::component::Export> for AnalysedExport {
136        type Error = String;
137
138        fn try_from(value: crate::proto::golem::component::Export) -> Result<Self, Self::Error> {
139            match value.export {
140                None => Err("Missing export".to_string()),
141                Some(crate::proto::golem::component::export::Export::Instance(instance)) => {
142                    Ok(Self::Instance(instance.try_into()?))
143                }
144                Some(crate::proto::golem::component::export::Export::Function(function)) => {
145                    Ok(Self::Function(function.try_into()?))
146                }
147            }
148        }
149    }
150
151    impl From<AnalysedExport> for crate::proto::golem::component::Export {
152        fn from(value: AnalysedExport) -> Self {
153            match value {
154                AnalysedExport::Instance(instance) => Self {
155                    export: Some(crate::proto::golem::component::export::Export::Instance(
156                        instance.into(),
157                    )),
158                },
159                AnalysedExport::Function(function) => Self {
160                    export: Some(crate::proto::golem::component::export::Export::Function(
161                        function.into(),
162                    )),
163                },
164            }
165        }
166    }
167
168    impl TryFrom<golem::component::FunctionParameter> for AnalysedFunctionParameter {
169        type Error = String;
170
171        fn try_from(
172            value: crate::proto::golem::component::FunctionParameter,
173        ) -> Result<Self, Self::Error> {
174            Ok(Self {
175                name: value.name,
176                typ: (&value.typ.ok_or("Missing typ")?).try_into()?,
177            })
178        }
179    }
180
181    impl From<AnalysedFunctionParameter> for crate::proto::golem::component::FunctionParameter {
182        fn from(value: AnalysedFunctionParameter) -> Self {
183            Self {
184                name: value.name,
185                typ: Some((&value.typ).into()),
186            }
187        }
188    }
189
190    impl Encode for UpdateMode {
191        fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
192            match self {
193                UpdateMode::Automatic => 0u8.encode(encoder),
194                UpdateMode::Manual => 1u8.encode(encoder),
195            }
196        }
197    }
198
199    impl<Context> Decode<Context> for UpdateMode {
200        fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
201            match Decode::decode(decoder)? {
202                0u8 => Ok(UpdateMode::Automatic),
203                1u8 => Ok(UpdateMode::Manual),
204                _ => Err(DecodeError::Other("Invalid UpdateMode")),
205            }
206        }
207    }
208
209    #[cfg(test)]
210    mod tests {
211        use crate::proto::golem;
212        use prost::Message;
213        use test_r::test;
214
215        #[test]
216        fn target_worker_id_and_worker_id_are_bin_compatible() {
217            let component_id_uuid = uuid::Uuid::new_v4();
218            let component_id_uuid: golem::common::Uuid = component_id_uuid.into();
219            let component_id = golem::component::ComponentId {
220                value: Some(component_id_uuid),
221            };
222            let target_worker_id = golem::worker::TargetWorkerId {
223                component_id: Some(component_id),
224                name: Some("hello".to_string()),
225            };
226            let worker_id = golem::worker::WorkerId {
227                component_id: Some(component_id),
228                name: "hello".to_string(),
229            };
230
231            let target_worker_id_bytes = target_worker_id.encode_to_vec();
232            let worker_id_bytes = worker_id.encode_to_vec();
233
234            assert_eq!(target_worker_id_bytes, worker_id_bytes);
235        }
236    }
237}