diff --git a/Cargo.lock b/Cargo.lock index b5c9275..e8ec6f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -450,7 +450,7 @@ dependencies = [ "openssl", "pin-project-lite 0.2.9", "tokio-openssl", - "tokio-rustls", + "tokio-rustls 0.23.4", "tokio-util 0.7.3", "webpki-roots 0.22.4", ] @@ -569,7 +569,7 @@ dependencies = [ "futures-core", "futures-util", "generic-array 0.14.5", - "hmac 0.12.1", + "hmac", "http", "local-channel", "mime", @@ -1080,6 +1080,306 @@ dependencies = [ "webpki-roots 0.22.4", ] +[[package]] +name = "aws-config" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a8c971b0cb0484fc9436a291a44503b95141edc36ce7a6af6b6d7a06a02ab0" +dependencies = [ + "aws-http", + "aws-sdk-sso", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-json", + "aws-smithy-types", + "aws-types", + "bytes 1.2.0", + "hex", + "http", + "hyper 0.14.20", + "ring", + "tokio 1.20.0", + "tower", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-endpoint" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bc956f415dda77215372e5bc751a2463d1f9a1ec34edf3edc6c0ff67e5c8e43" +dependencies = [ + "aws-smithy-http", + "aws-types", + "http", + "regex", + "tracing", +] + +[[package]] +name = "aws-http" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a0d98a1d606aa24554e604f220878db4aa3b525b72f88798524497cc3867fc6" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "aws-types", + "bytes 1.2.0", + "http", + "http-body 0.4.5", + "lazy_static", + "percent-encoding", + "pin-project-lite 0.2.9", + "tracing", +] + +[[package]] +name = "aws-sdk-s3" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f6e22f5641db610235c0c5fb768b5925a6317b16b12e4ab5a625cfed176f8a2" +dependencies = [ + "aws-endpoint", + "aws-http", + "aws-sig-auth", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes 1.2.0", + "http", + "md-5", + "tokio-stream", + "tower", +] + +[[package]] +name = "aws-sdk-sso" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa0c66fab12976065403cf4cafacffe76afa91d0da335d195af379d4223d235" +dependencies = [ + "aws-endpoint", + "aws-http", + "aws-sig-auth", + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-json", + "aws-smithy-types", + "aws-types", + "bytes 1.2.0", + "http", + "tokio-stream", + "tower", +] + +[[package]] +name = "aws-sdk-sts" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048037cdfd7f42fb29b5f969c7f639b4b7eac00e8f911e4eac4f89fb7b3a0500" +dependencies = [ + "aws-endpoint", + "aws-http", + "aws-sig-auth", + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-query", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes 1.2.0", + "http", + "tower", +] + +[[package]] +name = "aws-sig-auth" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8386fc0d218dbf2011f65bd8300d21ba98603fd150b962f61239be8b02d1fc6" +dependencies = [ + "aws-sigv4", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-types", + "http", + "tracing", +] + +[[package]] +name = "aws-sigv4" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd866926c2c4978210bcb01d7d1b431c794f0c23ca9ee1e420204b018836b5fb" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-http", + "bytes 1.2.0", + "form_urlencoded", + "hex", + "http", + "once_cell", + "percent-encoding", + "regex", + "ring", + "time 0.3.11", + "tracing", +] + +[[package]] +name = "aws-smithy-async" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb59cfdd21143006c01b9ca4dc4a9190b8c50c2ef831f9eb36f54f69efa42f1" +dependencies = [ + "futures-util", + "pin-project-lite 0.2.9", + "tokio 1.20.0", + "tokio-stream", +] + +[[package]] +name = "aws-smithy-client" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44243329ba8618474c3b7f396de281f175ae172dd515b3d35648671a3cf51871" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-types", + "bytes 1.2.0", + "fastrand", + "http", + "http-body 0.4.5", + "hyper 0.14.20", + "hyper-rustls", + "lazy_static", + "pin-project-lite 0.2.9", + "tokio 1.20.0", + "tower", + "tracing", +] + +[[package]] +name = "aws-smithy-eventstream" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e69ee49b9ed0ef080a6e18c08644521d3026029eb65dfc8c694315e1ae3118bc" +dependencies = [ + "aws-smithy-types", + "bytes 1.2.0", + "crc32fast", +] + +[[package]] +name = "aws-smithy-http" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba78f69a5bbe7ac1826389304c67b789032d813574e78f9a2d450634277f833" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-types", + "bytes 1.2.0", + "bytes-utils", + "futures-core", + "http", + "http-body 0.4.5", + "hyper 0.14.20", + "once_cell", + "percent-encoding", + "pin-project-lite 0.2.9", + "tokio 1.20.0", + "tokio-util 0.7.3", + "tracing", +] + +[[package]] +name = "aws-smithy-http-tower" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8a512d68350561e901626baa08af9491cfbd54596201b84b4da846a59e4da3" +dependencies = [ + "aws-smithy-http", + "bytes 1.2.0", + "http", + "http-body 0.4.5", + "pin-project-lite 0.2.9", + "tower", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b7633698853aae80bd8b26866531420138eca91ea4620735d20b0537c93c2e" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-query" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a94b5a8cc94a85ccbff89eb7bc80dc135ede02847a73d68c04ac2a3e4cf6b7" +dependencies = [ + "aws-smithy-types", + "urlencoding", +] + +[[package]] +name = "aws-smithy-types" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d230d281653de22fb0e9c7c74d18d724a39d7148e2165b1e760060064c4967c0" +dependencies = [ + "itoa 1.0.2", + "num-integer", + "ryu", + "time 0.3.11", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aacaf6c0fa549ebe5d9daa96233b8635965721367ee7c69effc8d8078842df3" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb54f097516352475a0159c9355f8b4737c54044538a4d9aca4d376ef2361ccc" +dependencies = [ + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-http", + "aws-smithy-types", + "http", + "rustc_version 0.4.0", + "tracing", + "zeroize", +] + [[package]] name = "backoff" version = "0.2.1" @@ -1345,6 +1645,16 @@ dependencies = [ "serde", ] +[[package]] +name = "bytes-utils" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1934a3ef9cac8efde4966a92781e77713e1ba329f1d42e446c7d7eba340d8ef1" +dependencies = [ + "bytes 1.2.0", + "either", +] + [[package]] name = "bytestring" version = "1.1.0" @@ -1636,7 +1946,7 @@ dependencies = [ "aes-gcm", "base64", "hkdf", - "hmac 0.12.1", + "hmac", "percent-encoding", "rand 0.8.5", "sha2 0.10.2", @@ -1770,16 +2080,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array 0.14.5", - "subtle", -] - [[package]] name = "csv" version = "1.1.6" @@ -1802,6 +2102,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "ct-logs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" +dependencies = [ + "sct 0.6.1", +] + [[package]] name = "ctr" version = "0.8.0" @@ -1984,27 +2293,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", -] - [[package]] name = "discard" version = "1.0.4" @@ -2748,17 +3036,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "hmac 0.12.1", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", + "hmac", ] [[package]] @@ -2918,6 +3196,23 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +dependencies = [ + "ct-logs", + "futures-util", + "hyper 0.14.20", + "log", + "rustls 0.19.1", + "rustls-native-certs", + "tokio 1.20.0", + "tokio-rustls 0.22.0", + "webpki 0.21.4", +] + [[package]] name = "hyper-tls" version = "0.4.3" @@ -3455,17 +3750,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" -[[package]] -name = "md-5" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "md-5" version = "0.10.1" @@ -3622,9 +3906,9 @@ dependencies = [ "futures-executor", "futures-util", "hex", - "hmac 0.12.1", + "hmac", "lazy_static", - "md-5 0.10.1", + "md-5", "os_info", "pbkdf2", "percent-encoding", @@ -3643,7 +3927,7 @@ dependencies = [ "take_mut", "thiserror", "tokio 1.20.0", - "tokio-rustls", + "tokio-rustls 0.23.4", "tokio-util 0.7.3", "trust-dns-proto", "trust-dns-resolver", @@ -3682,17 +3966,18 @@ dependencies = [ ] [[package]] -name = "multipart-s3" +name = "multipart-s3-example" version = "1.0.0" dependencies = [ "actix-multipart", "actix-web", + "actix-web-lab", + "aws-config", + "aws-sdk-s3", "dotenv", "env_logger 0.9.0", "futures-util", "log", - "rusoto_core", - "rusoto_s3", "sanitize-filename", "serde", "serde_json", @@ -4307,8 +4592,8 @@ dependencies = [ "byteorder", "bytes 1.2.0", "fallible-iterator", - "hmac 0.12.1", - "md-5 0.10.1", + "hmac", + "md-5", "memchr", "rand 0.8.5", "sha2 0.10.2", @@ -4698,17 +4983,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom 0.2.7", - "redox_syscall", - "thiserror", -] - [[package]] name = "regex" version = "1.6.0" @@ -4902,88 +5176,6 @@ dependencies = [ "log", ] -[[package]] -name = "rusoto_core" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db30db44ea73551326269adcf7a2169428a054f14faf9e1768f2163494f2fa2" -dependencies = [ - "async-trait", - "base64", - "bytes 1.2.0", - "crc32fast", - "futures", - "http", - "hyper 0.14.20", - "hyper-tls 0.5.0", - "lazy_static", - "log", - "rusoto_credential", - "rusoto_signature", - "rustc_version 0.4.0", - "serde", - "serde_json", - "tokio 1.20.0", - "xml-rs", -] - -[[package]] -name = "rusoto_credential" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee0a6c13db5aad6047b6a44ef023dbbc21a056b6dab5be3b79ce4283d5c02d05" -dependencies = [ - "async-trait", - "chrono", - "dirs-next", - "futures", - "hyper 0.14.20", - "serde", - "serde_json", - "shlex", - "tokio 1.20.0", - "zeroize", -] - -[[package]] -name = "rusoto_s3" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aae4677183411f6b0b412d66194ef5403293917d66e70ab118f07cc24c5b14d" -dependencies = [ - "async-trait", - "bytes 1.2.0", - "futures", - "rusoto_core", - "xml-rs", -] - -[[package]] -name = "rusoto_signature" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ae95491c8b4847931e291b151127eccd6ff8ca13f33603eb3d0035ecb05272" -dependencies = [ - "base64", - "bytes 1.2.0", - "chrono", - "digest 0.9.0", - "futures", - "hex", - "hmac 0.11.0", - "http", - "hyper 0.14.20", - "log", - "md-5 0.9.1", - "percent-encoding", - "pin-project-lite 0.2.9", - "rusoto_credential", - "rustc_version 0.4.0", - "serde", - "sha2 0.9.9", - "tokio 1.20.0", -] - [[package]] name = "rusqlite" version = "0.27.0" @@ -5116,6 +5308,18 @@ dependencies = [ "rustls-pemfile 1.0.0", ] +[[package]] +name = "rustls-native-certs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" +dependencies = [ + "openssl-probe", + "rustls 0.19.1", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "0.3.0" @@ -5737,7 +5941,7 @@ checksum = "874e93a365a598dc3dadb197565952cb143ae4aa716f7bcc933a8d836f6bf89f" dependencies = [ "once_cell", "tokio 1.20.0", - "tokio-rustls", + "tokio-rustls 0.23.4", ] [[package]] @@ -6316,6 +6520,17 @@ dependencies = [ "tokio-util 0.7.3", ] +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls 0.19.1", + "tokio 1.20.0", + "webpki 0.21.4", +] + [[package]] name = "tokio-rustls" version = "0.23.4" @@ -6399,6 +6614,28 @@ dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite 0.2.9", + "tokio 1.20.0", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + [[package]] name = "tower-service" version = "0.3.2" @@ -6772,6 +7009,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821" + [[package]] name = "utf-8" version = "0.7.6" @@ -7307,10 +7550,10 @@ dependencies = [ ] [[package]] -name = "xml-rs" -version = "0.8.4" +name = "xmlparser" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" +checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8" [[package]] name = "yaml-rust" diff --git a/forms/multipart-s3/.env.example b/forms/multipart-s3/.env.example index 27afb67..8debcff 100644 --- a/forms/multipart-s3/.env.example +++ b/forms/multipart-s3/.env.example @@ -1,4 +1,4 @@ +AWS_REGION= AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_S3_BUCKET_NAME= -AWS_REGION= diff --git a/forms/multipart-s3/Cargo.toml b/forms/multipart-s3/Cargo.toml index b8855ca..9dcbe7d 100644 --- a/forms/multipart-s3/Cargo.toml +++ b/forms/multipart-s3/Cargo.toml @@ -1,18 +1,20 @@ [package] -name = "multipart-s3" +name = "multipart-s3-example" version = "1.0.0" edition = "2021" [dependencies] -actix-web = "4" actix-multipart = "0.4" +actix-web = "4" +actix-web-lab = "0.16" -dotenv = "0.15.0" +aws-config = "0.46" +aws-sdk-s3 = "0.16" + +dotenv = "0.15" env_logger = "0.9" futures-util = { version = "0.3.17", default-features = false, features = ["std"] } log = "0.4" -rusoto_core = "0.48" -rusoto_s3 = "0.48" sanitize-filename = "0.4" -serde = { version = "1.0.104", features = ["derive"] } -serde_json = "1.0" +serde = { version = "1", features = ["derive"] } +serde_json = "1" diff --git a/forms/multipart-s3/README.md b/forms/multipart-s3/README.md index 65dc81b..9a3c988 100644 --- a/forms/multipart-s3/README.md +++ b/forms/multipart-s3/README.md @@ -1,30 +1,21 @@ # Multipart + AWS S3 -Upload a file in multipart form to aws s3 (https://github.com/rusoto/rusoto). +Upload a file in multipart form to AWS S3 using [AWS S3 SDK](https://crates.io/crates/aws-sdk-s3). Receive multiple data in multipart form in JSON format and receive it as a struct. # Usage -``` +```sh cd forms/multipart-s3 ``` 1. copy .env.example .env -1. edit .env AWS_ACCESS_KEY_ID=you_key -1. edit .env AWS_SECRET_ACCESS_KEY=you_key -1. edit .env AWS_S3_BUCKET_NAME=you_key +1. edit .env AWS_ACCESS_KEY_ID=your_key +1. edit .env AWS_SECRET_ACCESS_KEY=your_key +1. edit .env AWS_S3_BUCKET_NAME=your_chosen_region -# Running Server - -``` -cd forms/multipart-s3 -cargo run (or ``cargo watch -x run``) +```sh +cargo run ``` -http://localhost:8080 - -# Using Other Regions - - - -- https://docs.rs/rusoto_core/0.42.0/rusoto_core/enum.Region.html + diff --git a/forms/multipart-s3/src/index.html b/forms/multipart-s3/src/index.html new file mode 100644 index 0000000..ad28b34 --- /dev/null +++ b/forms/multipart-s3/src/index.html @@ -0,0 +1,35 @@ + + Upload Test + +
+ + + +
+ + + + diff --git a/forms/multipart-s3/src/main.rs b/forms/multipart-s3/src/main.rs index 1522a27..b50ef9c 100644 --- a/forms/multipart-s3/src/main.rs +++ b/forms/multipart-s3/src/main.rs @@ -1,12 +1,18 @@ -use std::{borrow::BorrowMut, env}; +use std::fs; use actix_multipart::Multipart; -use actix_web::{middleware::Logger, web, App, Error, HttpResponse, HttpServer}; +use actix_web::{middleware::Logger, web, App, Error, HttpResponse, HttpServer, Responder}; +use actix_web_lab::respond::Html; +use aws_config::meta::region::RegionProviderChain; use dotenv::dotenv; use serde::{Deserialize, Serialize}; mod utils; -use self::utils::upload::{save_file as upload_save_file, split_payload, UploadFile}; + +use self::utils::{ + s3::Client, + upload::{save_file as upload_save_file, split_payload, UploadFile}, +}; #[derive(Deserialize, Serialize, Debug)] pub struct InpAdd { @@ -14,60 +20,31 @@ pub struct InpAdd { pub number: i32, } -async fn save_file(mut payload: Multipart) -> Result { - let pl = split_payload(payload.borrow_mut()).await; +async fn save_file( + s3_client: web::Data, + mut payload: Multipart, +) -> Result { + let pl = split_payload(&mut payload).await; println!("bytes={:#?}", pl.0); + let inp_info: InpAdd = serde_json::from_slice(&pl.0).unwrap(); println!("converter_struct={:#?}", inp_info); println!("tmpfiles={:#?}", pl.1); - //make key + + // make key let s3_upload_key = format!("projects/{}/", "posts_id"); - //create tmp file and upload s3 and remove tmp file - let upload_files: Vec = upload_save_file(pl.1, s3_upload_key).await.unwrap(); + + // create tmp file and upload s3 and remove tmp file + let upload_files: Vec = upload_save_file(&s3_client, pl.1, &s3_upload_key) + .await + .unwrap(); println!("upload_files={:#?}", upload_files); + Ok(HttpResponse::Ok().into()) } -async fn index() -> HttpResponse { - let html = r#" - Upload Test - -
- - - -
- - - - "#; - - HttpResponse::Ok() - .content_type("text/html; charset=utf-8") - .body(html) +async fn index() -> impl Responder { + Html(include_str!("./index.html").to_owned()) } #[actix_web::main] @@ -75,21 +52,20 @@ async fn main() -> std::io::Result<()> { dotenv().ok(); env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); - let aws_access_key_id = env::var("AWS_ACCESS_KEY_ID").expect("AWS_ACCESS_KEY_ID must be set"); - let aws_secret_access_key = - env::var("AWS_SECRET_ACCESS_KEY").expect("AWS_SECRET_ACCESS_KEY must be set"); - let aws_s3_bucket_name = - env::var("AWS_S3_BUCKET_NAME").expect("AWS_S3_BUCKET_NAME must be set"); + log::info!("creating temporary upload directory"); - log::info!("aws_access_key_id: {aws_access_key_id}"); - log::info!("aws_secret_access_key: {aws_secret_access_key}"); - log::info!("aws_s3_bucket_name: {aws_s3_bucket_name}"); + fs::create_dir_all("./tmp").unwrap(); - std::fs::create_dir_all("./tmp").unwrap(); + log::info!("configuring S3 client"); + let aws_region = RegionProviderChain::default_provider().or_else("us-east-1"); + let aws_config = aws_config::from_env().region(aws_region).load().await; + let s3_client = Client::new(&aws_config); + + log::info!("using AWS region: {}", aws_config.region().unwrap()); log::info!("starting HTTP server at http://localhost:8080"); - HttpServer::new(|| { + HttpServer::new(move || { App::new() .service( web::resource("/") @@ -97,7 +73,9 @@ async fn main() -> std::io::Result<()> { .route(web::post().to(save_file)), ) .wrap(Logger::default()) + .app_data(web::Data::new(s3_client.clone())) }) + .workers(2) .bind(("127.0.0.1", 8080))? .run() .await diff --git a/forms/multipart-s3/src/utils/s3.rs b/forms/multipart-s3/src/utils/s3.rs index dba73a3..e36bc17 100644 --- a/forms/multipart-s3/src/utils/s3.rs +++ b/forms/multipart-s3/src/utils/s3.rs @@ -1,64 +1,57 @@ -use std::io::Read as _; +use std::{env, fs, io::Read as _}; -use rusoto_core::Region; -use rusoto_s3::{DeleteObjectRequest, PutObjectRequest, S3Client, S3}; +use aws_config::SdkConfig as AwsConfig; +use aws_sdk_s3::{types::ByteStream, Client as S3Client}; +#[derive(Debug, Clone)] pub struct Client { - #[allow(dead_code)] - region: Region, s3: S3Client, bucket_name: String, } impl Client { // construct S3 testing client - pub fn new() -> Client { - let region = Region::default(); - + pub fn new(config: &AwsConfig) -> Client { Client { - region: region.to_owned(), - s3: S3Client::new(region), - bucket_name: std::env::var("AWS_S3_BUCKET_NAME").unwrap(), + s3: S3Client::new(config), + bucket_name: env::var("AWS_S3_BUCKET_NAME").unwrap(), } } pub fn url(&self, key: &str) -> String { format!( "https://{}.s3.{}.amazonaws.com/{key}", - std::env::var("AWS_S3_BUCKET_NAME").unwrap(), - std::env::var("AWS_REGION").unwrap(), + env::var("AWS_S3_BUCKET_NAME").unwrap(), + env::var("AWS_REGION").unwrap(), ) } - pub async fn put_object(&self, localfilepath: &str, key: &str) -> String { - let mut file = std::fs::File::open(localfilepath).unwrap(); - let mut contents: Vec = Vec::new(); - let _ = file.read_to_end(&mut contents); - let put_request = PutObjectRequest { - bucket: self.bucket_name.to_owned(), - key: key.to_owned(), - body: Some(contents.into()), - ..Default::default() - }; + pub async fn put_object(&self, local_path: &str, key: &str) -> String { + let mut file = fs::File::open(local_path).unwrap(); + + let mut contents = + Vec::with_capacity(file.metadata().map(|md| md.len()).unwrap_or(1024) as usize); + file.read_to_end(&mut contents).unwrap(); + let _res = self .s3 - .put_object(put_request) + .put_object() + .bucket(&self.bucket_name) + .key(key) + .body(ByteStream::from(contents)) + .send() .await .expect("Failed to put test object"); self.url(key) } - pub async fn delete_object(&self, key: String) { - let delete_object_req = DeleteObjectRequest { - bucket: self.bucket_name.to_owned(), - key: key.to_owned(), - ..Default::default() - }; - - let _res = self - .s3 - .delete_object(delete_object_req) + pub async fn delete_object(&self, key: &str) { + self.s3 + .delete_object() + .bucket(&self.bucket_name) + .key(key) + .send() .await .expect("Couldn't delete object"); } diff --git a/forms/multipart-s3/src/utils/upload.rs b/forms/multipart-s3/src/utils/upload.rs index 22f256b..df53a19 100644 --- a/forms/multipart-s3/src/utils/upload.rs +++ b/forms/multipart-s3/src/utils/upload.rs @@ -1,4 +1,4 @@ -use std::{convert::From, io::Write}; +use std::{convert::From, fs, io::Write}; use actix_multipart::{Field, Multipart}; use actix_web::{web, web::Bytes, Error}; @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::utils::s3::Client; -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct UploadFile { pub filename: String, pub key: String, @@ -36,6 +36,7 @@ pub struct Tmpfile { pub s3_key: String, pub s3_url: String, } + impl Tmpfile { fn new(filename: &str) -> Tmpfile { Tmpfile { @@ -46,25 +47,25 @@ impl Tmpfile { } } - async fn s3_upload_and_tmp_remove(&mut self, s3_upload_key: String) { - self.s3_upload(s3_upload_key).await; + async fn s3_upload_and_tmp_remove(&mut self, client: &Client, s3_upload_key: &str) { + self.s3_upload(client, s3_upload_key).await; self.tmp_remove(); } - async fn s3_upload(&mut self, s3_upload_key: String) { + async fn s3_upload(&mut self, client: &Client, s3_upload_key: &str) { let key = format!("{s3_upload_key}{}", &self.name); self.s3_key = key.clone(); - let url: String = Client::new().put_object(&self.tmp_path, &key.clone()).await; + let url = client.put_object(&self.tmp_path, &key.clone()).await; self.s3_url = url; } fn tmp_remove(&self) { - std::fs::remove_file(&self.tmp_path).unwrap(); + fs::remove_file(&self.tmp_path).unwrap(); } } pub async fn split_payload(payload: &mut Multipart) -> (Bytes, Vec) { - let mut tmp_files: Vec = Vec::new(); + let mut tmp_files = vec![]; let mut data = Bytes::new(); while let Some(item) = payload.next().await { @@ -80,7 +81,7 @@ pub async fn split_payload(payload: &mut Multipart) -> (Bytes, Vec) { Some(filename) => { let tmp_file = Tmpfile::new(&sanitize_filename::sanitize(&filename)); let tmp_path = tmp_file.tmp_path.clone(); - let mut f = web::block(move || std::fs::File::create(&tmp_path)) + let mut f = web::block(move || fs::File::create(&tmp_path)) .await .unwrap() .unwrap(); @@ -103,24 +104,27 @@ pub async fn split_payload(payload: &mut Multipart) -> (Bytes, Vec) { } pub async fn save_file( + client: &Client, tmp_files: Vec, - s3_upload_key: String, + s3_upload_key: &str, ) -> Result, Error> { let mut arr: Vec = Vec::with_capacity(tmp_files.len()); for item in tmp_files { let mut tmp_file: Tmpfile = item.clone(); + tmp_file - .s3_upload_and_tmp_remove(s3_upload_key.clone()) + .s3_upload_and_tmp_remove(client, s3_upload_key) .await; + arr.push(UploadFile::from(tmp_file)); } Ok(arr) } #[allow(unused)] -pub async fn delete_object(list: Vec) { - for key in list { - Client::new().delete_object(key).await; +pub async fn delete_object(client: &Client, keys: Vec<&str>) { + for key in keys { + client.delete_object(key).await; } }