Last active
May 12, 2020 05:01
-
-
Save ggomagundan/c178f103ff76a3c3002735647fb6a6bb to your computer and use it in GitHub Desktop.
Finish Topic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "move_origin" | |
version = "0.1.0" | |
authors = ["Kai <ggogun@gmail.com>"] | |
edition = "2018" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
aws_lambda_events = "^0.3.0" | |
rusoto_core = "0.42.0" | |
rusoto_s3 = "0.42.0" | |
rusoto_credential = "0.42.0" | |
lambda_runtime = "^0.2.1" | |
serde = { version = "^1.0", features = ["derive"] } | |
serde_json = "^1.0" | |
serde_derive = "^1" | |
log = "^0.4" | |
simple_logger = "^1" | |
openssl = { version = "0.10", features = ["vendored"] } | |
dotenv = "0.14.1" | |
dotenv_codegen = "0.14.1" | |
chrono = { version = "0.4" , features = ["serde"] } | |
regex = "1" | |
reqwest = { version = "0.10", features = ["json", "blocking"] } | |
[[bin]] | |
name = "bootstrap" | |
path = "src/main.rs" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[macro_use] | |
extern crate dotenv_codegen; | |
use lambda_runtime::{error::HandlerError, lambda}; | |
use std::error::Error; | |
use serde::{Serialize, Deserialize}; | |
use rusoto_core::region::Region; | |
use rusoto_s3::{S3, S3Client, CopyObjectRequest}; | |
use regex::Regex; | |
use aws_lambda_events::event::sns::SnsEvent; | |
mod models; | |
use models::mediaconvert_response::*; | |
use models::video::*; | |
use models::video_sources::*; | |
// This is our function entry point. | |
// Note the use of the `lambda!` macro. It will hold our handler: | |
// pub type Handler<E, O> = fn(E, Context) -> Result<O, HandlerError> | |
fn main() -> Result<(), Box<dyn Error>> { | |
// lambda!(my_handler); | |
// Ok(()) | |
let j = "{\"version\":\"0\",\"id\":\"4914e037-36b4-27e9-1a0e-e2d377e74b13\",\"detail-type\":\"MediaConvert Job State Change\",\"source\":\"aws.mediaconvert\",\"account\":\"578297789655\",\"time\":\"2020-03-13T09:03:34Z\",\"region\":\"ap-northeast-2\",\"resources\":[\"arn:aws:mediaconvert:ap-northeast-2:578297789655:jobs/1584090167837-pl4uo5\"],\"detail\":{\"timestamp\":1584090214483,\"accountId\":\"578297789655\",\"queue\":\"arn:aws:mediaconvert:ap-northeast-2:578297789655:queues/Default\",\"jobId\":\"1584090167837-pl4uo5\",\"status\":\"COMPLETE\",\"userMetadata\":{\"text_content\": \"#샌드바 #카네오헤 #천국의바다 #테스트#강 #리붜 #rriivveerr 강은 영어로 뤼붜\",\"user_id\": \"204364\",\"original_name\": \"down-park-won.mp4\"},\"outputGroupDetails\":[{\"outputDetails\":[{\"outputFilePaths\":[\"s3://btoz-video-output/20200313/down-park-won/HLS_480p/down-park-won20200313T090252_output_480p.m3u8\"],\"durationInMs\":242400,\"videoDetails\":{\"widthInPx\":480,\"heightInPx\":640}}],\"playlistFilePaths\":[\"s3://btoz-video-output/20200313/down-park-won/HLS_480p/down-park-won.m3u8\"],\"type\":\"HLS_GROUP\"},{\"outputDetails\":[{\"outputFilePaths\":[\"s3://btoz-video-output/20200313/down-park-won/HLS_240p/down-park-won20200313T090252_output_240p.m3u8\"],\"durationInMs\":242400,\"videoDetails\":{\"widthInPx\":240,\"heightInPx\":352}}],\"playlistFilePaths\":[\"s3://btoz-video-output/20200313/down-park-won/HLS_240p/down-park-won.m3u8\"],\"type\":\"HLS_GROUP\"},{\"outputDetails\":[{\"outputFilePaths\":[\"s3://btoz-video-output/20200313/down-park-won/HLS_720p/down-park-won20200313T090252_output_720p.m3u8\"],\"durationInMs\":242400,\"videoDetails\":{\"widthInPx\":720,\"heightInPx\":1280}}],\"playlistFilePaths\":[\"s3://btoz-video-output/20200313/down-park-won/HLS_720p/down-park-won.m3u8\"],\"type\":\"HLS_GROUP\"},{\"outputDetails\":[{\"outputFilePaths\":[\"s3://btoz-video-output/20200313/down-park-won/thumbnails/down-park-won20200313T090251_output_thumbnail.0000005.jpg\"],\"durationInMs\":24000,\"videoDetails\":{\"widthInPx\":720,\"heightInPx\":1280}}],\"type\":\"FILE_GROUP\"}]}}"; | |
let u: MediaConvertResponse = serde_json::from_str(j).unwrap(); | |
println!("{:#?}", u); | |
match my_handler(u) { | |
Ok(_r) => Ok(()), | |
Err(e) => panic!("There was a problem opening the file: {:?}", e) | |
} | |
} | |
#[derive(Serialize, Deserialize)] | |
pub struct CustomOutput { | |
status_code: i64, | |
body: String | |
} | |
// Our handler will just check for a query string parameter called `firstName`. | |
// Note the different behavior depending on the value of the parameter. | |
// In case there's no query string parameter, we'll check the body of the request. | |
// The body comes as a string so we'll have to use `Serde` again to deserialize it. | |
// Finally, if we have no body, we'll return a default response. | |
fn my_handler(e: MediaConvertResponse) | |
// fn my_handler(e: SnsEvent, c: lambda_runtime::Context) | |
-> Result<CustomOutput, HandlerError> { | |
// $ cargo build --release --target x86_64-unknown-linux-musl | |
// $ zip -j rust.zip ./target/x86_64-unknown-linux-musl/release/bootstrap | |
let s3_client = S3Client::new(Region::ApNortheast2); | |
let from_bucket = dotenv!("UPLOAD_BUCKET_NAME").to_owned(); | |
let to_bucket = dotenv!("COPY_BUCKET_NAME").to_owned(); | |
let mut url_list: Vec<String> = Vec::new(); | |
// let media_convert_detail = e.records[0].sns.message.as_ref().unwrap(); | |
// println!("detail : {:?}", media_convert_detail); | |
// let detail_contents: MediaConvertResponse = serde_json::from_str(media_convert_detail).unwrap(); | |
let detail_contents = e.clone(); | |
println!("detail json: {:#?}", detail_contents); | |
// | |
let output_group_details = detail_contents.clone().detail.clone().unwrap().output_group_details.unwrap(); | |
let metadata = detail_contents.clone().detail.unwrap().user_metadata.unwrap(); | |
let mut video_sources: Vec<VideoSource> = Vec::new(); | |
let mut s3_thumbnail_paths: &str = ""; | |
let mut thumbnail_url: String = String::new() ; | |
for a in output_group_details.iter() | |
{ | |
let width = &a.output_details.as_ref().unwrap()[0].video_details.as_ref().unwrap().width_in_px; | |
match &a.playlist_file_paths { | |
Some(paths) => { | |
let detail = &paths[0]; | |
let re = Regex::new(r"s3://\w+.+.m3u8").unwrap(); | |
if re.is_match(&detail) { | |
let mat = re.find(&detail).unwrap(); | |
let url: String = mat.as_str().to_string().clone(); | |
let bucket_path: Vec<&str> = url.split(&to_bucket).collect(); | |
video_sources.push(VideoSource{ | |
format: "hls" , | |
s3_url: Some(url.clone()), | |
url: make_s3_public_url(bucket_path[1]), | |
width: *width | |
}) | |
} | |
} | |
None => { | |
s3_thumbnail_paths = &a.output_details.as_ref().unwrap()[0].output_file_paths.as_ref().unwrap()[0]; | |
let s3_thumbnail_path: Vec<&str> = s3_thumbnail_paths.split(&to_bucket).collect(); | |
thumbnail_url = make_s3_public_url(s3_thumbnail_path[1]); | |
} | |
} | |
}; | |
let uurl = video_sources[0].clone().s3_url.unwrap(); | |
let splited: Vec<&str> = uurl.split("btoz-video-output/").collect(); | |
let copy_to_paths: Vec<&str> = splited[1].split("/").collect(); | |
let copy_to_path: &str = copy_to_paths[0]; | |
println!("Move to Origin file"); | |
let source_file = metadata.get("original_name").unwrap(); | |
println!("from: {:?}, to {:}, sourcefile; {:}", from_bucket, to_bucket, source_file); | |
println!("source full : {:}", format!("{:}/{:}",from_bucket,source_file.clone())); | |
// let result = s3_client.copy_object(CopyObjectRequest { | |
// bucket: to_bucket , | |
// copy_source: format!("{:}/{:}", from_bucket, source_file.clone()), | |
// key: format!("{:}/{:}",copy_to_path,source_file.clone()), | |
// ..Default::default() | |
// }).sync(); | |
// println!("Result: {:?}", result); | |
let user_id: u64 = metadata.get("user_id").unwrap().parse().unwrap(); | |
let video: Video = Video { | |
name: source_file, | |
thumbnail: thumbnail_url.as_str().clone(), | |
text_content: metadata.get("text_content").unwrap(), | |
sources: video_sources, | |
user_id: user_id | |
}; | |
println!("request Body: {:?}", serde_json::to_string(&video).unwrap()); | |
// let client = reqwest::blocking::Client::new(); | |
// let request_url = dotenv!("REQUEST_URL"); | |
// let request_auth_key = dotenv!("REQUEST_AUTH_KEY"); | |
// let resp = client.post(request_url) | |
// .header("Content-Type","application/json") | |
// .header("Authorization",format!("Bearer {}", request_auth_key)) | |
// .body(serde_json::to_string(&video).unwrap()) | |
// .send(); | |
// println!("{:#?}", resp); | |
Ok(CustomOutput { | |
status_code: 200, | |
body: format!("Upload job ({:?}) finished ", "123")//c.aws_request_id) | |
}) | |
} | |
fn make_s3_public_url(detail_path: &str) -> String { | |
let bucket_name = dotenv!("COPY_BUCKET_NAME").to_owned(); | |
format!("https://{}.s3.{}.amazonaws.com{}", | |
&bucket_name, | |
&Region::ApNortheast2.name(), | |
detail_path) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use chrono::Utc; | |
use std::collections::HashMap; | |
// use chrono::prelude::*; | |
use serde::{Deserialize, Serialize}; | |
// #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
// pub struct SnsEvents { | |
// #[serde(rename = "Records")] | |
// pub records: Vec<SnsEvent>, | |
// } | |
// | |
// #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
// pub struct SnsEvent { | |
// #[serde(rename = "EventSource")] | |
// pub event_source: Option<String>, | |
// #[serde(rename = "EventVersion")] | |
// pub event_version: Option<String>, | |
// #[serde(rename = "EventSubscriptionArn")] | |
// pub event_subscription_arn: Option<String>, | |
// #[serde(rename = "Sns")] | |
// pub sns: Sns | |
// } | |
// | |
// #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
// pub struct Sns { | |
// pub Type: Option<String>, | |
// pub MessageId: Option<String>, | |
// pub TopicArn: Option<String>, | |
// pub Subject: Option<String>, | |
// #[serde(rename = "Message")] | |
// pub message: MediaConvertResponse, | |
// pub Timestamp: Option<String>, | |
// pub SignatureVersion: Option<String>, | |
// pub Signature: Option<String>, | |
// pub SigningCertUrl: Option<String>, | |
// pub UnsubscribeUrl: Option<String>, | |
// //MessageAttributes":{"key":{"Type":"String","Value":"value"}} | |
// } | |
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
pub struct MediaConvertResponse { | |
pub version: Option<String>, | |
pub id: Option<String>, | |
#[serde(rename = "detail-type")] | |
pub detail_type: Option<String>, | |
pub detail: Option<Detail>, | |
} | |
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
pub struct Detail { | |
// timestamp: Option<Utc>, | |
#[serde(rename = "accountId")] | |
pub account_id: Option<String>, | |
pub queue: Option<String>, | |
#[serde(rename = "jobId")] | |
pub job_id: Option<String>, | |
pub status: Option<String>, | |
#[serde(rename = "outputGroupDetails")] | |
pub output_group_details: Option<Vec<OutputGroupDetails>>, | |
#[serde(rename = "userMetadata")] | |
pub user_metadata: Option<HashMap<String, String>>, | |
} | |
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
pub struct OutputGroupDetails { | |
#[serde(rename = "outputDetails")] | |
pub output_details: Option<Vec<OutputDetails>>, | |
#[serde(rename = "playlistFilePaths")] | |
pub playlist_file_paths: Option<Vec<String>>, | |
pub r#type: Option<String>, | |
} | |
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
pub struct OutputDetails { | |
#[serde(rename = "outputFilePaths")] | |
pub output_file_paths: Option<Vec<String>>, | |
#[serde(rename = "durationInMs")] | |
pub duration_in_ms: Option<u64>, | |
#[serde(rename = "videoDetails")] | |
pub video_details: Option<VideoDetail>, | |
} | |
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
pub struct VideoDetail { | |
#[serde(rename = "widthInPx")] | |
pub width_in_px: u64, | |
#[serde(rename = "heightInPx")] | |
pub height_in_px: u64, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub mod video; | |
pub mod video_sources; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::models::video_sources::VideoSource; | |
use serde::{Deserialize, Serialize}; | |
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
pub struct Video<'a> { | |
pub name: &'a str, | |
pub thumbnail: &'a str, | |
pub text_content: &'a str , | |
pub sources: Vec<VideoSource<'a>>, | |
pub user_id: u64 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use serde::{Deserialize, Serialize}; | |
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] | |
pub struct VideoSource<'a> { | |
pub format: &'a str, | |
pub url: String, | |
pub s3_url: Option<String>, | |
pub width: u64 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment