15 changed files with 137 additions and 147 deletions
@ -0,0 +1,13 @@
|
||||
use tracing_unwrap::ResultExt; |
||||
use crate::constants; |
||||
|
||||
pub fn get_aws_credential() -> (String, String, String) { |
||||
let access_key = crate::env::get(constants::ENV_AWS_ACCESS_KEY) |
||||
.expect_or_log("env not found: AWS_ACCESS_KEY"); |
||||
let secret_key = crate::env::get(constants::ENV_AWS_SECRET_KEY) |
||||
.expect_or_log("env not found: AWS_SECRET_KEY"); |
||||
let region = crate::env::get(constants::ENV_AWS_REGION) |
||||
.expect_or_log("env not found: AWS_REGION"); |
||||
|
||||
(access_key, secret_key, region) |
||||
} |
||||
@ -0,0 +1,4 @@
|
||||
pub mod s3; |
||||
pub mod kinesis; |
||||
pub mod parameter_store; |
||||
mod credential; |
||||
@ -0,0 +1,84 @@
|
||||
use std::sync::Arc; |
||||
use aws_config::meta::region::RegionProviderChain; |
||||
use aws_credential_types::Credentials; |
||||
use aws_types::region::Region; |
||||
use bytes::Bytes; |
||||
use tokio::sync::OnceCell; |
||||
use tracing::info; |
||||
use crate::model::error::DeviceError; |
||||
|
||||
static AWS_S3_CLIENT: OnceCell<Arc<aws_sdk_s3::Client>> = OnceCell::const_new(); |
||||
|
||||
async fn initialize_data() -> Arc<aws_sdk_s3::Client> { |
||||
let (access_key, secret_key, region) = crate::aws::credential::get_aws_credential(); |
||||
|
||||
let region_provider = RegionProviderChain::default_provider().or_else(Region::new(region)); |
||||
let region = region_provider.region().await.unwrap(); |
||||
|
||||
let credentials = Credentials::from_keys( |
||||
access_key, |
||||
secret_key, |
||||
None, |
||||
); |
||||
|
||||
let config = aws_config::defaults(aws_config::BehaviorVersion::latest()) |
||||
.region(region) |
||||
.credentials_provider(credentials) |
||||
.load() |
||||
.await; |
||||
|
||||
Arc::new(aws_sdk_s3::Client::new(&config)) |
||||
} |
||||
|
||||
async fn get_client() -> Arc<aws_sdk_s3::Client> { |
||||
AWS_S3_CLIENT.get_or_init(initialize_data) |
||||
.await |
||||
.clone() |
||||
} |
||||
|
||||
pub async fn read_file(bucket: &str, key: &str) -> Result<String, DeviceError> { |
||||
let client = get_client().await; |
||||
|
||||
let res = client |
||||
.get_object() |
||||
.bucket(bucket) |
||||
.key(key) |
||||
.send() |
||||
.await?; |
||||
|
||||
let data = res |
||||
.body |
||||
.collect() |
||||
.await?; |
||||
|
||||
let data: Bytes = data.into_bytes(); |
||||
|
||||
if data.is_empty() { |
||||
return Err(DeviceError::GeneralError("length".to_string())) |
||||
} |
||||
|
||||
Ok(String::from_utf8_lossy(&data).into_owned()) |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use super::*; |
||||
use serial_test::serial; |
||||
use crate::constants; |
||||
|
||||
fn setup() { |
||||
crate::env::set(constants::ENV_AWS_ACCESS_KEY, "AKIA32XY6L3KQA4QDIAP"); |
||||
crate::env::set(constants::ENV_AWS_SECRET_KEY, "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"); |
||||
crate::env::set(constants::ENV_AWS_REGION, "ap-northeast-2"); |
||||
} |
||||
|
||||
fn teardown() {} |
||||
|
||||
#[tokio::test] |
||||
#[serial] |
||||
async fn test_read_file() { |
||||
setup(); |
||||
assert!(read_file("apm-bigdata", "flower-device/test.csv").await.is_ok()); |
||||
teardown(); |
||||
} |
||||
} |
||||
@ -1,52 +0,0 @@
|
||||
use std::mem::size_of; |
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
#[repr(u8)] |
||||
#[derive(Debug, PartialEq)] |
||||
pub enum KinesisMessageType { |
||||
DeviceUpsert = 0x01 |
||||
} |
||||
|
||||
#[repr(C)] |
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)] |
||||
pub struct KinesisMessage { |
||||
pub action: u8, // data type
|
||||
pub size: i32, // data size
|
||||
pub data: Vec<u8> // data
|
||||
} |
||||
|
||||
impl KinesisMessage { |
||||
pub fn new(action: u8, size: i32, data: Vec<u8>) -> KinesisMessage { |
||||
KinesisMessage { |
||||
action, |
||||
size, |
||||
data, |
||||
} |
||||
} |
||||
|
||||
pub fn encode(&self) -> Vec<u8> { |
||||
let mut bin = Vec::new(); |
||||
bin.push(self.action); |
||||
bin.extend_from_slice(&self.size.to_ne_bytes()); |
||||
bin.extend_from_slice(&self.data); |
||||
bin |
||||
} |
||||
|
||||
pub fn decode(encoded: Vec<u8>) -> KinesisMessage { |
||||
let mut current_index = 0; |
||||
let action = encoded[current_index]; |
||||
current_index = current_index + size_of::<u8>(); |
||||
|
||||
let size_vec = encoded.get(current_index..current_index + size_of::<i32>()).unwrap().try_into().unwrap(); |
||||
let size = i32::from_ne_bytes(size_vec); |
||||
current_index = current_index + size_of::<i32>(); |
||||
|
||||
let data = encoded[current_index..current_index + size as usize].to_vec(); |
||||
|
||||
KinesisMessage { |
||||
action, |
||||
size, |
||||
data, |
||||
} |
||||
} |
||||
} |
||||
@ -1,41 +0,0 @@
|
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
pub trait KinesisMessageDetail<T> { |
||||
fn encode(&self) -> Vec<u8>; |
||||
fn decode(encoded: Vec<u8>) -> T; |
||||
} |
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)] |
||||
#[repr(C)] |
||||
pub struct UpsertKinesisMessageDetail { |
||||
pub finger_print: String, |
||||
pub so_id: String, |
||||
pub uuid: String, |
||||
pub use_personalized_ad: bool, |
||||
pub test: Option<bool>, |
||||
pub zip_code: Option<String>, |
||||
pub free_storage: i64, |
||||
pub used_storage: i64, |
||||
pub cached_storage: i64, |
||||
pub model_name: String, |
||||
pub firmware_build_date: Option<String>, |
||||
pub firmware_ver: Option<String>, |
||||
pub full_firmware_ver: Option<String>, |
||||
pub app_version: String, |
||||
pub platform_ad_id: Option<String>, |
||||
pub a_key: Option<String>, |
||||
pub is_exist: bool, |
||||
pub device_id: i64 |
||||
} |
||||
|
||||
impl<T> KinesisMessageDetail<T> for UpsertKinesisMessageDetail |
||||
where |
||||
T: Serialize + serde::de::DeserializeOwned,{ |
||||
fn encode(&self) -> Vec<u8> { |
||||
bincode::serialize(&self).unwrap() |
||||
} |
||||
|
||||
fn decode(encoded: Vec<u8>) -> T { |
||||
bincode::deserialize(&encoded).unwrap() |
||||
} |
||||
} |
||||
Loading…
Reference in new issue