use crate::auth::auth_library_init;
use crate::common::allocator::Allocator;
use crate::common::error::Error;
use crate::io::channel_bootstrap::ClientBootstrap;
use crate::io::retry_strategy::RetryStrategy;
use crate::CrtError;
use mountpoint_s3_crt_sys::{
aws_byte_buf, aws_imds_client, aws_imds_client_get_instance_type, aws_imds_client_new, aws_imds_client_options,
aws_imds_client_release,
};
use std::ptr::NonNull;
#[derive(Debug)]
pub struct ImdsClient {
inner: NonNull<aws_imds_client>,
}
#[derive(Debug, Default)]
pub struct ImdsClientConfig {
inner: aws_imds_client_options,
client_bootstrap: Option<ClientBootstrap>,
retry_strategy: Option<RetryStrategy>,
}
impl ImdsClientConfig {
pub fn new() -> Self {
Default::default()
}
pub fn client_bootstrap(&mut self, client_bootstrap: ClientBootstrap) -> &mut Self {
self.inner.bootstrap = client_bootstrap.inner.as_ptr();
self.client_bootstrap = Some(client_bootstrap);
self
}
pub fn retry_strategy(&mut self, retry_strategy: RetryStrategy) -> &mut Self {
self.inner.retry_strategy = retry_strategy.inner.as_ptr();
self.retry_strategy = Some(retry_strategy);
self
}
}
impl ImdsClient {
pub fn new(allocator: &Allocator, config: ImdsClientConfig) -> Result<Self, Error> {
auth_library_init(allocator);
let inner = unsafe { aws_imds_client_new(allocator.inner.as_ptr(), &config.inner).ok_or_last_error()? };
Ok(Self { inner })
}
pub fn get_instance_type<F>(&self, callback: F) -> Result<(), Error>
where
F: FnOnce(Result<String, Error>) + 'static,
{
let callback_wrapper = Box::new(ImdsClientGetResourceCallback(Box::new(callback)));
let callback_raw_ptr = Box::into_raw(callback_wrapper) as *mut libc::c_void;
let get_resource_callback_fn_ptr: Option<unsafe extern "C" fn(*const aws_byte_buf, i32, *mut libc::c_void)> =
Some(imds_client_get_resource_callback);
unsafe {
aws_imds_client_get_instance_type(self.inner.as_ptr(), get_resource_callback_fn_ptr, callback_raw_ptr)
.ok_or_last_error()
}
}
}
impl Drop for ImdsClient {
fn drop(&mut self) {
unsafe { aws_imds_client_release(self.inner.as_ptr()) };
}
}
type OnGetResource = Box<dyn FnOnce(Result<String, Error>)>;
struct ImdsClientGetResourceCallback(OnGetResource);
unsafe extern "C" fn imds_client_get_resource_callback(
resource: *const aws_byte_buf,
error_code: i32,
user_data: *mut libc::c_void,
) {
let callback = Box::from_raw(user_data as *mut ImdsClientGetResourceCallback).0;
let result = if 0 != error_code {
Err(error_code.into())
} else {
let resource = std::slice::from_raw_parts((*resource).buffer, (*resource).len).to_vec();
Ok(String::from_utf8(resource).expect("resource response should be encoded with utf8."))
};
callback(result)
}