mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2024-11-24 06:19:46 +00:00
Support Azure blob storage in a similar fashion to S3. (#907)
This commit is contained in:
parent
9742149ce8
commit
9b4f5e8c75
16 changed files with 707 additions and 57 deletions
502
Cargo.lock
generated
502
Cargo.lock
generated
|
@ -2,6 +2,12 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "RustyXML"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b5ace29ee3216de37c0546865ad08edef58b0f9e76838ed8959a84a990e58c5"
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
|
@ -74,7 +80,7 @@ version = "0.7.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
@ -86,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"version_check",
|
||||
|
@ -304,6 +310,17 @@ dependencies = [
|
|||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener 2.5.3",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.15"
|
||||
|
@ -317,6 +334,17 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
|
||||
dependencies = [
|
||||
"event-listener 5.3.1",
|
||||
"event-listener-strategy",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
|
@ -461,6 +489,92 @@ dependencies = [
|
|||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure_core"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b552ad43a45a746461ec3d3a51dfb6466b4759209414b439c165eb6a6b7729e"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"dyn-clone",
|
||||
"futures",
|
||||
"getrandom 0.2.15",
|
||||
"hmac 0.12.1",
|
||||
"http-types",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"pin-project",
|
||||
"quick-xml 0.31.0",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.8",
|
||||
"rustc_version 0.4.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"time",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure_storage"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59f838159f4d29cb400a14d9d757578ba495ae64feb07a7516bf9e4415127126"
|
||||
dependencies = [
|
||||
"RustyXML",
|
||||
"async-lock",
|
||||
"async-trait",
|
||||
"azure_core",
|
||||
"bytes",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"time",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure_storage_blobs"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97e83c3636ae86d9a6a7962b2112e3b19eb3903915c50ce06ff54ff0a2e6a7e4"
|
||||
dependencies = [
|
||||
"RustyXML",
|
||||
"azure_core",
|
||||
"azure_storage",
|
||||
"azure_svc_blobstorage",
|
||||
"bytes",
|
||||
"futures",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"time",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure_svc_blobstorage"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e6c6f20c5611b885ba94c7bae5e02849a267381aecb8aee577e8c35ff4064c6"
|
||||
dependencies = [
|
||||
"azure_core",
|
||||
"bytes",
|
||||
"futures",
|
||||
"log",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
|
@ -1070,7 +1184,7 @@ dependencies = [
|
|||
"idna 1.0.2",
|
||||
"imagesize",
|
||||
"imap_proto",
|
||||
"infer",
|
||||
"infer 0.16.0",
|
||||
"jmap_proto",
|
||||
"libc",
|
||||
"mail-auth",
|
||||
|
@ -1118,6 +1232,15 @@ dependencies = [
|
|||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.8"
|
||||
|
@ -1152,7 +1275,7 @@ version = "0.1.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
@ -1299,7 +1422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
|
||||
dependencies = [
|
||||
"generic-array 0.14.7",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -1311,7 +1434,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array 0.14.7",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
|
@ -1512,7 +1635,7 @@ checksum = "1ab8a4ea925ce79678034870834602a2980f4b88c09e97feb266496dbb4493d2"
|
|||
dependencies = [
|
||||
"async-trait",
|
||||
"deadpool 0.12.1",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
"tracing",
|
||||
|
@ -1860,7 +1983,7 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
|
|||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"sha2 0.10.8",
|
||||
"subtle",
|
||||
|
@ -1908,7 +2031,7 @@ dependencies = [
|
|||
"hkdf",
|
||||
"pem-rfc7468",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"sec1",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
|
@ -1968,6 +2091,43 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
|
||||
dependencies = [
|
||||
"event-listener 5.3.1",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event_macro"
|
||||
version = "0.1.0"
|
||||
|
@ -2018,13 +2178,28 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
|
@ -2116,7 +2291,7 @@ dependencies = [
|
|||
"foundationdb-sys",
|
||||
"futures",
|
||||
"memchr",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"serde_json",
|
||||
|
@ -2265,6 +2440,21 @@ version = "0.3.31"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
|
||||
dependencies = [
|
||||
"fastrand 1.9.0",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.31"
|
||||
|
@ -2345,6 +2535,17 @@ dependencies = [
|
|||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
|
@ -2354,7 +2555,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
|
@ -2387,7 +2588,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
|
@ -2511,7 +2712,7 @@ dependencies = [
|
|||
"hickory-proto",
|
||||
"once_cell",
|
||||
"radix_trie",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.21.12",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
|
@ -2537,7 +2738,7 @@ dependencies = [
|
|||
"idna 0.4.0",
|
||||
"ipnet",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"ring 0.16.20",
|
||||
"rustls 0.21.12",
|
||||
"rustls-pemfile 1.0.4",
|
||||
|
@ -2562,7 +2763,7 @@ dependencies = [
|
|||
"lru-cache",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"resolv-conf",
|
||||
"rustls 0.21.12",
|
||||
"smallvec",
|
||||
|
@ -2687,6 +2888,26 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-types"
|
||||
version = "2.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
"base64 0.13.1",
|
||||
"futures-lite",
|
||||
"infer 0.2.3",
|
||||
"pin-project-lite",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_qs",
|
||||
"serde_urlencoded",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.9.5"
|
||||
|
@ -2795,6 +3016,22 @@ dependencies = [
|
|||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper 1.5.0",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.9"
|
||||
|
@ -3024,7 +3261,7 @@ dependencies = [
|
|||
"md5",
|
||||
"nlp",
|
||||
"parking_lot",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.23.14",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"store",
|
||||
|
@ -3080,6 +3317,12 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "infer"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
|
||||
|
||||
[[package]]
|
||||
name = "infer"
|
||||
version = "0.16.0"
|
||||
|
@ -3255,7 +3498,7 @@ dependencies = [
|
|||
"p256",
|
||||
"pkcs8",
|
||||
"quick-xml 0.36.2",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rasn",
|
||||
"rasn-cms",
|
||||
"rasn-pkix",
|
||||
|
@ -3521,6 +3764,12 @@ version = "0.5.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.3"
|
||||
|
@ -3607,7 +3856,7 @@ dependencies = [
|
|||
"mail-parser",
|
||||
"parking_lot",
|
||||
"quick-xml 0.36.2",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"ring 0.17.8",
|
||||
"rsa",
|
||||
"rustls-pemfile 2.2.0",
|
||||
|
@ -3823,7 +4072,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
|
@ -3866,7 +4115,7 @@ dependencies = [
|
|||
"pem",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.22.4",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"serde",
|
||||
|
@ -3905,7 +4154,7 @@ dependencies = [
|
|||
"mysql-common-derive",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"rust_decimal",
|
||||
"saturating",
|
||||
|
@ -3921,6 +4170,23 @@ dependencies = [
|
|||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
|
@ -4009,7 +4275,7 @@ dependencies = [
|
|||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -4228,7 +4494,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"opentelemetry",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
@ -4277,10 +4543,16 @@ dependencies = [
|
|||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"primeorder",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"sha2 0.10.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
|
@ -4311,7 +4583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
|
@ -4395,7 +4667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||
dependencies = [
|
||||
"phf_shared 0.11.2",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4538,7 +4810,7 @@ dependencies = [
|
|||
"hmac 0.12.1",
|
||||
"md-5 0.10.6",
|
||||
"memchr",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"sha2 0.10.8",
|
||||
"stringprep",
|
||||
]
|
||||
|
@ -4761,7 +5033,7 @@ dependencies = [
|
|||
"byteorder",
|
||||
"hmac 0.10.1",
|
||||
"md-5 0.9.1",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"sha-1",
|
||||
"sha2 0.9.9",
|
||||
]
|
||||
|
@ -4772,6 +5044,16 @@ version = "1.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.32.0"
|
||||
|
@ -4816,7 +5098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"ring 0.17.8",
|
||||
"rustc-hash 2.0.0",
|
||||
"rustls 0.23.14",
|
||||
|
@ -4875,6 +5157,19 @@ dependencies = [
|
|||
"nibble_vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"libc",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
|
@ -4882,8 +5177,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4893,7 +5198,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4902,7 +5216,16 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5024,7 +5347,7 @@ dependencies = [
|
|||
"num-bigint",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.23.14",
|
||||
"rustls-native-certs 0.7.3",
|
||||
"rustls-pemfile 2.2.0",
|
||||
|
@ -5054,7 +5377,7 @@ version = "0.4.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
|
@ -5158,12 +5481,14 @@ dependencies = [
|
|||
"http-body-util",
|
||||
"hyper 1.5.0",
|
||||
"hyper-rustls 0.27.3",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
|
@ -5176,6 +5501,7 @@ dependencies = [
|
|||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.0",
|
||||
"tokio-util",
|
||||
"tower-service",
|
||||
|
@ -5240,7 +5566,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
|||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"libc",
|
||||
"spin 0.9.8",
|
||||
"untrusted 0.9.0",
|
||||
|
@ -5329,7 +5655,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"signature",
|
||||
"spki",
|
||||
"subtle",
|
||||
|
@ -5434,7 +5760,7 @@ dependencies = [
|
|||
"borsh",
|
||||
"bytes",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rkyv",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -5485,6 +5811,19 @@ dependencies = [
|
|||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.12"
|
||||
|
@ -5783,7 +6122,7 @@ dependencies = [
|
|||
"ecdsa",
|
||||
"ed25519",
|
||||
"ed25519-dalek",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"idea",
|
||||
"idna 1.0.2",
|
||||
"lalrpop",
|
||||
|
@ -5797,8 +6136,8 @@ dependencies = [
|
|||
"p256",
|
||||
"p384",
|
||||
"p521",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"ripemd",
|
||||
|
@ -5854,6 +6193,17 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_qs"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -6015,7 +6365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6081,7 +6431,7 @@ dependencies = [
|
|||
"nlp",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
"regex",
|
||||
"reqwest 0.12.8",
|
||||
|
@ -6190,7 +6540,7 @@ dependencies = [
|
|||
"num_cpus",
|
||||
"prettytable-rs",
|
||||
"pwhash",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.8",
|
||||
"rpassword",
|
||||
"serde",
|
||||
|
@ -6211,6 +6561,9 @@ dependencies = [
|
|||
"ahash 0.8.11",
|
||||
"arc-swap",
|
||||
"async-trait",
|
||||
"azure_core",
|
||||
"azure_storage",
|
||||
"azure_storage_blobs",
|
||||
"bincode",
|
||||
"bitpacking",
|
||||
"blake3",
|
||||
|
@ -6229,10 +6582,11 @@ dependencies = [
|
|||
"num_cpus",
|
||||
"parking_lot",
|
||||
"r2d2",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
"redis",
|
||||
"regex",
|
||||
"reqwest 0.12.8",
|
||||
"ring 0.17.8",
|
||||
"roaring",
|
||||
"rocksdb",
|
||||
|
@ -6401,6 +6755,19 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand 2.2.0",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.7.0"
|
||||
|
@ -6502,6 +6869,7 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
|||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"js-sys",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
|
@ -6599,6 +6967,16 @@ dependencies = [
|
|||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-postgres"
|
||||
version = "0.7.12"
|
||||
|
@ -6618,7 +6996,7 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"postgres-protocol",
|
||||
"postgres-types",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
|
@ -6782,7 +7160,7 @@ dependencies = [
|
|||
"indexmap 1.9.3",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
|
@ -6896,7 +7274,7 @@ dependencies = [
|
|||
"http 1.1.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.22.4",
|
||||
"rustls-pki-types",
|
||||
"sha1",
|
||||
|
@ -6917,7 +7295,7 @@ dependencies = [
|
|||
"http 1.1.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"utf-8",
|
||||
|
@ -6939,7 +7317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
|
@ -7059,6 +7437,7 @@ dependencies = [
|
|||
"form_urlencoded",
|
||||
"idna 0.5.0",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -7109,7 +7488,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"pem",
|
||||
"privdrop",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rcgen 0.13.1",
|
||||
"regex",
|
||||
"reqwest 0.12.8",
|
||||
|
@ -7133,7 +7512,8 @@ version = "1.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -7154,6 +7534,12 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
|
@ -7173,6 +7559,12 @@ dependencies = [
|
|||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
@ -7602,7 +7994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
@ -7789,7 +8181,7 @@ dependencies = [
|
|||
"lzma-rs",
|
||||
"memchr",
|
||||
"pbkdf2",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"time",
|
||||
|
|
|
@ -34,7 +34,7 @@ tokio = { version = "1.23", features = ["full"] }
|
|||
jemallocator = "0.5.0"
|
||||
|
||||
[features]
|
||||
default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "enterprise"]
|
||||
default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "azure", "enterprise"]
|
||||
#default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "foundationdb", "enterprise"]
|
||||
sqlite = ["store/sqlite"]
|
||||
foundationdb = ["store/foundation", "common/foundation"]
|
||||
|
@ -44,4 +44,5 @@ rocks = ["store/rocks"]
|
|||
elastic = ["store/elastic"]
|
||||
s3 = ["store/s3"]
|
||||
redis = ["store/redis"]
|
||||
azure = ["store/azure"]
|
||||
enterprise = ["jmap/enterprise", "common/enterprise", "store/enterprise", "managesieve/enterprise", "directory/enterprise"]
|
||||
|
|
|
@ -12,6 +12,10 @@ rocksdb = { version = "0.22", optional = true, features = ["multi-threaded-cf"]
|
|||
foundationdb = { version = "0.9.0", features = ["embedded-fdb-include", "fdb-7_1"], optional = true }
|
||||
rusqlite = { version = "0.32", features = ["bundled"], optional = true }
|
||||
rust-s3 = { version = "=0.35.0-alpha.2", default-features = false, features = ["tokio-rustls-tls", "no-verify-ssl"], optional = true }
|
||||
azure_core = { version = "0.21.0", optional = true }
|
||||
azure_storage = { version = "0.21.0", optional = true }
|
||||
azure_storage_blobs = { version = "0.21.0", optional = true }
|
||||
reqwest = { version = "0.12.0", default-features = false, optional = true }
|
||||
tokio = { version = "1.23", features = ["sync", "fs", "io-util"] }
|
||||
r2d2 = { version = "0.8.10", optional = true }
|
||||
futures = { version = "0.3", optional = true }
|
||||
|
@ -56,6 +60,7 @@ postgres = ["tokio-postgres", "deadpool-postgres", "tokio-rustls", "rustls", "ri
|
|||
elastic = ["elasticsearch", "serde_json"]
|
||||
mysql = ["mysql_async", "futures"]
|
||||
s3 = ["rust-s3"]
|
||||
azure = ["azure_core", "azure_storage", "azure_storage_blobs", "reqwest"]
|
||||
foundation = ["foundationdb", "futures"]
|
||||
fdb-chunked-bm = []
|
||||
redis = ["dep:redis", "deadpool"]
|
||||
|
|
204
crates/store/src/backend/azure/mod.rs
Normal file
204
crates/store/src/backend/azure/mod.rs
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::{fmt::Display, io::Write, ops::Range, time::Duration};
|
||||
|
||||
use azure_core::error::ErrorKind;
|
||||
use azure_core::{ExponentialRetryOptions, RetryOptions, StatusCode, TransportOptions};
|
||||
use azure_storage::StorageCredentials;
|
||||
use azure_storage_blobs::prelude::{ClientBuilder, ContainerClient};
|
||||
use futures::stream::StreamExt;
|
||||
use std::sync::Arc;
|
||||
use utils::{
|
||||
codec::base32_custom::Base32Writer,
|
||||
config::{utils::AsKey, Config},
|
||||
};
|
||||
|
||||
pub struct AzureStore {
|
||||
client: ContainerClient,
|
||||
prefix: Option<String>,
|
||||
}
|
||||
|
||||
impl AzureStore {
|
||||
pub async fn open(config: &mut Config, prefix: impl AsKey) -> Option<Self> {
|
||||
let prefix = prefix.as_key();
|
||||
|
||||
let storage_account = config
|
||||
.value_require((&prefix, "storage-account"))?
|
||||
.to_string();
|
||||
let container = config.value_require((&prefix, "container"))?.to_string();
|
||||
|
||||
let credentials = match (
|
||||
config.value((&prefix, "access-key")),
|
||||
config.value((&prefix, "sas-token")),
|
||||
) {
|
||||
(Some(access_key), None) => {
|
||||
StorageCredentials::access_key(storage_account.clone(), access_key.to_string())
|
||||
}
|
||||
(None, Some(sas_token)) => match StorageCredentials::sas_token(sas_token) {
|
||||
Ok(cred) => cred,
|
||||
Err(err) => {
|
||||
config.new_build_error(
|
||||
prefix.as_str(),
|
||||
format!("Failed to create credentials: {err:?}"),
|
||||
);
|
||||
return None;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
config.new_build_error(
|
||||
prefix.as_str(),
|
||||
format!("Failed to create credentials: exactly one of 'access-key' and 'sas-token' must be specified"));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let timeout = config
|
||||
.property_or_default::<Duration>((&prefix, "timeout"), "30s")
|
||||
.unwrap_or_else(|| Duration::from_secs(30));
|
||||
let transport = match reqwest::Client::builder().timeout(timeout).build() {
|
||||
Ok(client) => Arc::new(client),
|
||||
Err(err) => {
|
||||
config.new_build_error(
|
||||
prefix.as_str(),
|
||||
format!("Failed to create HTTP client: {err:?}"),
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// Take the configured number of retries and multiply by 2. This is intended to match the
|
||||
// precedent set by the S3 back end, where we do the indicated number of retries,
|
||||
// ourselves, but internally the rust-s3 crate is also retrying each of our requests up to
|
||||
// one additional time, itself. So our retries, and the S3 backend's retries, are
|
||||
// comparable to each other.
|
||||
let max_retries: u32 = config
|
||||
.property_or_default((&prefix, "max-retries"), "3")
|
||||
.unwrap_or(3)
|
||||
* 2;
|
||||
|
||||
Some(AzureStore {
|
||||
client: ClientBuilder::new(storage_account, credentials)
|
||||
.transport(TransportOptions::new(transport))
|
||||
.retry(RetryOptions::exponential(
|
||||
ExponentialRetryOptions::default().max_retries(max_retries),
|
||||
))
|
||||
.container_client(container),
|
||||
prefix: config.value((&prefix, "key-prefix")).map(|s| s.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn get_blob(
|
||||
&self,
|
||||
key: &[u8],
|
||||
range: Range<usize>,
|
||||
) -> trc::Result<Option<Vec<u8>>> {
|
||||
let blob_client = self.client.blob_client(self.build_key(key));
|
||||
|
||||
let mut stream = blob_client.get();
|
||||
let mut buf = if range.end == usize::MAX {
|
||||
// Let's turn this into a proper RangeFrom.
|
||||
stream = stream.range(range.start..);
|
||||
// We don't know how big to expect the result to be.
|
||||
Vec::new()
|
||||
} else {
|
||||
stream = stream.range(range.clone());
|
||||
Vec::with_capacity(range.end - range.start)
|
||||
};
|
||||
let mut stream = stream.into_stream();
|
||||
|
||||
while let Some(response) = stream.next().await {
|
||||
let err = match response {
|
||||
Ok(chunks) => {
|
||||
let mut chunks = chunks.data;
|
||||
let mut err = None;
|
||||
while let Some(chunk) = chunks.next().await {
|
||||
match chunk {
|
||||
Ok(ref data) => {
|
||||
buf.extend(data);
|
||||
}
|
||||
Err(e) => {
|
||||
err = Some(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
Err(e) => Some(e),
|
||||
};
|
||||
|
||||
if let Some(e) = err {
|
||||
return if matches!(
|
||||
e.kind(),
|
||||
ErrorKind::HttpResponse {
|
||||
status: StatusCode::NotFound,
|
||||
..
|
||||
}
|
||||
) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(trc::StoreEvent::S3Error.reason(e))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(buf))
|
||||
}
|
||||
|
||||
pub(crate) async fn put_blob(&self, key: &[u8], data: &[u8]) -> trc::Result<()> {
|
||||
let blob_client = self.client.blob_client(self.build_key(key));
|
||||
|
||||
// We unfortunately have to make a copy of `data`. This is because the Azure SDK wants to
|
||||
// coerce the body into a value of type azure_core::Body, which doesn't have a lifetime
|
||||
// parameter and so cannot hold any non-static references (directly or indirectly).
|
||||
let data = data.to_vec();
|
||||
|
||||
blob_client
|
||||
.put_block_blob(data)
|
||||
.into_future()
|
||||
.await
|
||||
.map_err(into_error)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn delete_blob(&self, key: &[u8]) -> trc::Result<bool> {
|
||||
let blob_client = self.client.blob_client(self.build_key(key));
|
||||
|
||||
if let Err(e) = blob_client.delete().into_future().await {
|
||||
if matches!(
|
||||
e.kind(),
|
||||
ErrorKind::HttpResponse {
|
||||
status: StatusCode::NotFound,
|
||||
..
|
||||
}
|
||||
) {
|
||||
Ok(false)
|
||||
} else {
|
||||
Err(trc::StoreEvent::S3Error.reason(e))
|
||||
}
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_key(&self, key: &[u8]) -> String {
|
||||
if let Some(prefix) = &self.prefix {
|
||||
let mut writer =
|
||||
Base32Writer::with_raw_capacity(prefix.len() + ((key.len() + 3) / 4 * 5));
|
||||
writer.push_string(prefix);
|
||||
writer.write_all(key).unwrap();
|
||||
writer.finalize()
|
||||
} else {
|
||||
Base32Writer::from_bytes(key).finalize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_error(err: impl Display) -> trc::Error {
|
||||
trc::StoreEvent::S3Error.reason(err)
|
||||
}
|
|
@ -81,6 +81,8 @@ impl DistributedBlob {
|
|||
BlobBackend::Fs(store) => store.get_blob(key, read_range).await,
|
||||
#[cfg(feature = "s3")]
|
||||
BlobBackend::S3(store) => store.get_blob(key, read_range).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.get_blob(key, read_range).await,
|
||||
BlobBackend::Composite(_) => unimplemented!(),
|
||||
}
|
||||
})
|
||||
|
@ -111,6 +113,8 @@ impl DistributedBlob {
|
|||
BlobBackend::Fs(store) => store.put_blob(key, data).await,
|
||||
#[cfg(feature = "s3")]
|
||||
BlobBackend::S3(store) => store.put_blob(key, data).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.put_blob(key, data).await,
|
||||
BlobBackend::Composite(_) => unimplemented!(),
|
||||
}
|
||||
})
|
||||
|
@ -141,6 +145,8 @@ impl DistributedBlob {
|
|||
BlobBackend::Fs(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "s3")]
|
||||
BlobBackend::S3(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.delete_blob(key).await,
|
||||
BlobBackend::Composite(_) => unimplemented!(),
|
||||
}
|
||||
})
|
||||
|
|
|
@ -24,6 +24,8 @@ pub mod rocksdb;
|
|||
pub mod s3;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub mod sqlite;
|
||||
#[cfg(feature = "azure")]
|
||||
pub mod azure;
|
||||
|
||||
pub const MAX_TOKEN_LENGTH: usize = (u8::MAX >> 1) as usize;
|
||||
pub const MAX_TOKEN_MASK: usize = MAX_TOKEN_LENGTH - 1;
|
||||
|
|
|
@ -38,6 +38,9 @@ use crate::backend::elastic::ElasticSearchStore;
|
|||
#[cfg(feature = "redis")]
|
||||
use crate::backend::redis::RedisStore;
|
||||
|
||||
#[cfg(feature = "azure")]
|
||||
use crate::backend::azure::AzureStore;
|
||||
|
||||
impl Stores {
|
||||
pub async fn parse_all(config: &mut Config) -> Self {
|
||||
let mut stores = Self::parse(config).await;
|
||||
|
@ -216,6 +219,13 @@ impl Stores {
|
|||
"sql-read-replica" | "distributed-blob" => {
|
||||
composite_stores.push((store_id, protocol));
|
||||
}
|
||||
#[cfg(feature = "azure")]
|
||||
"azure" => {
|
||||
if let Some(db) = AzureStore::open(config, prefix).await.map(BlobStore::from) {
|
||||
self.blob_stores
|
||||
.insert(store_id, db.with_compression(compression_algo));
|
||||
}
|
||||
}
|
||||
unknown => {
|
||||
config.new_parse_warning(
|
||||
("store", id, "type"),
|
||||
|
|
|
@ -37,6 +37,8 @@ impl BlobStore {
|
|||
BlobBackend::Fs(store) => store.get_blob(key, read_range).await,
|
||||
#[cfg(feature = "s3")]
|
||||
BlobBackend::S3(store) => store.get_blob(key, read_range).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.get_blob(key, read_range).await,
|
||||
#[cfg(feature = "enterprise")]
|
||||
BlobBackend::Composite(store) => store.get_blob(key, read_range).await,
|
||||
};
|
||||
|
@ -117,6 +119,8 @@ impl BlobStore {
|
|||
BlobBackend::Fs(store) => store.put_blob(key, data.as_ref()).await,
|
||||
#[cfg(feature = "s3")]
|
||||
BlobBackend::S3(store) => store.put_blob(key, data.as_ref()).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.put_blob(key, data.as_ref()).await,
|
||||
#[cfg(feature = "enterprise")]
|
||||
BlobBackend::Composite(store) => store.put_blob(key, data.as_ref()).await,
|
||||
}
|
||||
|
@ -153,6 +157,8 @@ impl BlobStore {
|
|||
BlobBackend::Fs(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "s3")]
|
||||
BlobBackend::S3(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "enterprise")]
|
||||
BlobBackend::Composite(store) => store.delete_blob(key).await,
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ use backend::elastic::ElasticSearchStore;
|
|||
#[cfg(feature = "redis")]
|
||||
use backend::redis::RedisStore;
|
||||
|
||||
#[cfg(feature = "azure")]
|
||||
use backend::azure::AzureStore;
|
||||
|
||||
pub trait Deserialize: Sized + Sync + Send {
|
||||
fn deserialize(bytes: &[u8]) -> trc::Result<Self>;
|
||||
}
|
||||
|
@ -208,6 +211,8 @@ pub enum BlobBackend {
|
|||
Fs(Arc<FsStore>),
|
||||
#[cfg(feature = "s3")]
|
||||
S3(Arc<S3Store>),
|
||||
#[cfg(feature = "azure")]
|
||||
Azure(Arc<AzureStore>),
|
||||
#[cfg(feature = "enterprise")]
|
||||
Composite(Arc<backend::composite::distributed_blob::DistributedBlob>),
|
||||
}
|
||||
|
@ -288,6 +293,16 @@ impl From<S3Store> for BlobStore {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "azure")]
|
||||
impl From<AzureStore> for BlobStore {
|
||||
fn from(store: AzureStore) -> Self {
|
||||
BlobStore {
|
||||
backend: BlobBackend::Azure(Arc::new(store)),
|
||||
compression: CompressionAlgo::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "elastic")]
|
||||
impl From<ElasticSearchStore> for FtsStore {
|
||||
fn from(store: ElasticSearchStore) -> Self {
|
||||
|
|
|
@ -1540,6 +1540,7 @@ impl StoreEvent {
|
|||
StoreEvent::ElasticsearchError => "ElasticSearch error",
|
||||
StoreEvent::RedisError => "Redis error",
|
||||
StoreEvent::S3Error => "S3 error",
|
||||
StoreEvent::AzureError => "Azure error",
|
||||
StoreEvent::FilesystemError => "Filesystem error",
|
||||
StoreEvent::PoolError => "Connection pool error",
|
||||
StoreEvent::DataCorruption => "Data corruption detected",
|
||||
|
@ -1574,6 +1575,7 @@ impl StoreEvent {
|
|||
StoreEvent::ElasticsearchError => "An ElasticSearch error occurred",
|
||||
StoreEvent::RedisError => "A Redis error occurred",
|
||||
StoreEvent::S3Error => "An S3 error occurred",
|
||||
StoreEvent::AzureError => "An Azure error occurred",
|
||||
StoreEvent::FilesystemError => "A filesystem error occurred",
|
||||
StoreEvent::PoolError => "A connection pool error occurred",
|
||||
StoreEvent::DataCorruption => "Data corruption was detected",
|
||||
|
|
|
@ -31,6 +31,7 @@ impl EventType {
|
|||
| StoreEvent::ElasticsearchError
|
||||
| StoreEvent::RedisError
|
||||
| StoreEvent::S3Error
|
||||
| StoreEvent::AzureError
|
||||
| StoreEvent::FilesystemError
|
||||
| StoreEvent::PoolError
|
||||
| StoreEvent::DataCorruption
|
||||
|
|
|
@ -307,6 +307,7 @@ impl StoreEvent {
|
|||
Self::ElasticsearchError => "ElasticSearch error",
|
||||
Self::RedisError => "Redis error",
|
||||
Self::S3Error => "S3 error",
|
||||
Self::AzureError => "Azure error",
|
||||
Self::FilesystemError => "Filesystem error",
|
||||
Self::PoolError => "Connection pool error",
|
||||
Self::DataCorruption => "Data corruption",
|
||||
|
|
|
@ -440,6 +440,7 @@ impl EventType {
|
|||
| StoreEvent::ElasticsearchError
|
||||
| StoreEvent::RedisError
|
||||
| StoreEvent::S3Error
|
||||
| StoreEvent::AzureError
|
||||
| StoreEvent::FilesystemError
|
||||
| StoreEvent::PoolError
|
||||
| StoreEvent::DataCorruption
|
||||
|
|
|
@ -828,6 +828,7 @@ pub enum StoreEvent {
|
|||
ElasticsearchError,
|
||||
RedisError,
|
||||
S3Error,
|
||||
AzureError,
|
||||
FilesystemError,
|
||||
PoolError,
|
||||
DataCorruption,
|
||||
|
|
|
@ -864,6 +864,7 @@ impl EventType {
|
|||
EventType::Ai(AiEvent::LlmResponse) => 556,
|
||||
EventType::Ai(AiEvent::ApiError) => 557,
|
||||
EventType::Security(SecurityEvent::ScanBan) => 558,
|
||||
EventType::Store(StoreEvent::AzureError) => 559,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1468,6 +1469,7 @@ impl EventType {
|
|||
556 => Some(EventType::Ai(AiEvent::LlmResponse)),
|
||||
557 => Some(EventType::Ai(AiEvent::ApiError)),
|
||||
558 => Some(EventType::Security(SecurityEvent::ScanBan)),
|
||||
559 => Some(EventType::Store(StoreEvent::AzureError)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
resolver = "2"
|
||||
|
||||
[features]
|
||||
default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "foundationdb"]
|
||||
default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "azure", "foundationdb"]
|
||||
#default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "foundationdb"]
|
||||
sqlite = ["store/sqlite"]
|
||||
foundationdb = ["store/foundation", "common/foundation"]
|
||||
|
@ -15,6 +15,7 @@ rocks = ["store/rocks"]
|
|||
elastic = ["store/elastic"]
|
||||
s3 = ["store/s3"]
|
||||
redis = ["store/redis"]
|
||||
azure = ["store/azure"]
|
||||
|
||||
[dev-dependencies]
|
||||
store = { path = "../crates/store", features = ["test_mode", "enterprise"] }
|
||||
|
|
Loading…
Reference in a new issue