1use chrono::Utc;
19use http::Request;
20use tokio::runtime::Handle;
21
22use crate::{
23 cdni::imd::spec::TypedHostMetadata,
24 dcdn::{
25 error::{ImdInterpretError, ProxyError, ProxyResult},
26 imdi::interpret_interconnection_metadata,
27 interpret::{
28 Error::{self, AssertionFailure},
29 ProcessedRequestResponse,
30 },
31 },
32 environment::scope::{Scope, Scopes},
33 hmds::{HmdsConfiguration, query_hmds},
34 logging::{LogLevel, LogMsg, LogMsgs},
35 mel::{
36 MEL_USER_SET_VARIABLE_STRUCT_NAME,
37 interpreter::values::{TypedValue, mel_var_value_from_type},
38 types::{Type, builtin_function_types, minimal_core_variable_types},
39 },
40 prr,
41 verifying::imdv::verify_interconnection_metadata,
42};
43
44pub fn safe_brooks_integration_handle(
45 request: &Request<Vec<u8>>,
46 mel: Scopes<TypedValue>,
47 hmds_key: &str,
48 hmds_config: &mut HmdsConfiguration,
49 runtime: &Handle,
50 mut log: LogMsgs,
51) -> ProxyResult {
52 log = debug!(
54 log,
55 &format!("Looking for {hmds_key} in the host metadata cache.")
56 );
57
58 let found = match hmds_config.hmds_cache.get(hmds_key) {
59 Some((timeout, found)) => {
60 log = debug!(
61 log,
62 &format!(
63 "Found {hmds_key} in the host metadata cache -- it is valid until {timeout}."
64 )
65 );
66 if Utc::now() > *timeout {
67 log = debug!(
68 log,
69 &format!("{hmds_key} in the host metadata cache timed out.")
70 );
71 hmds_config.hmds_cache.remove(hmds_key);
72 None
73 } else {
74 Some(found.clone())
75 }
76 }
77 None => None,
78 };
79
80 let (verified_md, updated_types_scopes) = if let Some(found) = found {
81 found
82 } else {
83 let res = match runtime.block_on(query_hmds(hmds_key, &hmds_config.hmds_server)) {
84 Ok(o) => o,
85 Err(e) => return Err((ProxyError::HmdsError(e.into()).into(), log)),
86 };
87 let (expiry, query_result) = match res {
88 Some((timeout, query_result)) => (timeout, query_result),
89 None => {
90 return Err((
91 ProxyError::HmdsError(
92 format!("Missing HMD configuration for {hmds_key}").into(),
93 )
94 .into(),
95 log,
96 ));
97 }
98 };
99
100 let metadata = match serde_json::from_value::<TypedHostMetadata<()>>(query_result) {
101 Ok(o) => o,
102 Err(e) => {
103 return Err((ProxyError::HmdsError(e.into()).into(), log));
104 }
105 };
106
107 let types_scope = Scopes::<Type> {
108 scopes: vec![&minimal_core_variable_types() + &builtin_function_types()],
109 };
110
111 let (verified_md, updated_types_scope) =
112 match verify_interconnection_metadata(&metadata.value, types_scope) {
113 Ok(o) => o,
114 Err(e) => {
115 return Err((ProxyError::HmdsError(e).into(), log));
116 }
117 };
118
119 log = debug!(
120 log,
121 &format!("Put {hmds_key} in the host metadata cache to expire at {expiry}.")
122 );
123 hmds_config.hmds_cache.insert(
124 hmds_key.to_string(),
125 (expiry, (verified_md.clone(), updated_types_scope.clone())),
126 );
127
128 (verified_md, updated_types_scope)
129 };
130
131 let processed_http_req = match TryInto::<ProcessedRequestResponse>::try_into(request) {
132 Ok(o) => o,
133 Err(e) => {
134 return Err((ProxyError::SetupError(e.into()).into(), log));
135 }
136 };
137
138 let processed_http_req = Box::new(processed_http_req);
139 let mel_scopes: Scopes<TypedValue> = mel.enter_scope(Into::<Scope<TypedValue>>::into(
140 &*processed_http_req as &dyn prr::Prr<Vec<u8>>,
141 ));
142
143 let var = match updated_types_scopes
146 .lookup(MEL_USER_SET_VARIABLE_STRUCT_NAME)
147 .ok_or(ProxyError::ImdiError(ImdInterpretError::RuntimeError(
148 Error::AssertionFailure(
149 format!(
150 "Missing {} struct type after analyzing HMD",
151 MEL_USER_SET_VARIABLE_STRUCT_NAME
152 )
153 .into(),
154 )
155 .into(),
156 ))) {
157 Ok(variable) => match variable {
158 Type::Struct(s) => s,
159 _ => {
160 return Err((
161 ProxyError::ImdiError(ImdInterpretError::MetadataProcessingError(
162 AssertionFailure(
163 format!(
164 "{} has wrong type after analyzing HMD",
165 MEL_USER_SET_VARIABLE_STRUCT_NAME
166 )
167 .into(),
168 )
169 .into(),
170 ))
171 .into(),
172 log,
173 ));
174 }
175 },
176 Err(e) => return Err((e.into(), log)),
177 };
178
179 log = debug!(
180 log,
181 &format!(
182 "Creating more-specific type for {} struct: {}",
183 MEL_USER_SET_VARIABLE_STRUCT_NAME, var
184 )
185 );
186 let mel_scopes = mel_scopes.insert(
187 MEL_USER_SET_VARIABLE_STRUCT_NAME,
188 mel_var_value_from_type(var),
189 );
190
191 interpret_interconnection_metadata(&verified_md, mel_scopes, processed_http_req, runtime, log)
192 .map_err(|(e, log)| (ProxyError::ImdiError(*e).into(), log))
193}