From 3291266a424e54a869f6a8c4fb818286abb2a3c5 Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Sat, 8 Mar 2025 18:11:09 -0300 Subject: [PATCH] refactor(all): Remove unused code and update dependencies in multiple modules --- Cargo.lock | 736 ++++++++++++++++++++++++++- Cargo.toml | 7 +- api.json | 537 +++++++++++++++++++ gb-auth/src/handlers/auth_handler.rs | 3 - gb-auth/src/handlers/mod.rs | 1 - gb-auth/tests/auth_service_tests.rs | 49 -- gb-core/Cargo.toml | 7 +- {gb-server => gb-core}/src/config.rs | 0 {gb-file => gb-core}/src/db.rs | 74 ++- gb-core/src/lib.rs | 38 +- gb-core/src/models.rs | 32 +- gb-file/Cargo.toml | 8 +- gb-file/src/lib.rs | 144 ------ gb-image/src/processor.rs | 28 +- gb-server/Cargo.toml | 1 + gb-server/src/lib.rs | 65 --- gb-server/src/main.rs | 21 +- gb-server/src/router.rs | 301 +---------- gb-testing/src/chaos/mod.rs | 36 -- gb-utils/src/detector.rs | 19 +- gb-utils/src/lib.rs | 40 -- gb-utils/src/processor.rs | 216 -------- gb-vm/Cargo.toml | 1 - gb-vm/src/lib.rs | 144 ------ 24 files changed, 1351 insertions(+), 1157 deletions(-) create mode 100644 api.json rename {gb-server => gb-core}/src/config.rs (100%) rename {gb-file => gb-core}/src/db.rs (55%) diff --git a/Cargo.lock b/Cargo.lock index 8cf945e..6f23222 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,189 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +[[package]] +name = "actix-codec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" +dependencies = [ + "bitflags 2.9.0", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash", + "base64 0.22.1", + "bitflags 2.9.0", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2 0.3.26", + "http 0.2.12", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand 0.8.5", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd 0.13.3", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.99", +] + +[[package]] +name = "actix-router" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" +dependencies = [ + "bytestring", + "cfg-if", + "http 0.2.12", + "regex", + "regex-lite", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6398974fd4284f4768af07965701efbbb5fdc0616bff20cade1bb14b77675e24" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2 0.5.8", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash", + "bytes", + "bytestring", + "cfg-if", + "cookie 0.16.2", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "impl-more", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "regex-lite", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2 0.5.8", + "time", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "addr2line" version = "0.24.2" @@ -80,6 +263,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -947,6 +1145,27 @@ dependencies = [ "cmake", ] +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bstr" version = "1.11.3" @@ -985,6 +1204,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bytestring" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +dependencies = [ + "bytes", +] + [[package]] name = "bzip2" version = "0.4.4" @@ -1386,6 +1614,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1562,6 +1800,7 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", + "digest", "fiat-crypto", "rustc_version", "subtle", @@ -1585,6 +1824,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" +[[package]] +name = "custom_error" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6" + [[package]] name = "darling" version = "0.20.10" @@ -1717,6 +1962,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -1772,6 +2018,19 @@ dependencies = [ "syn 2.0.99", ] +[[package]] +name = "derive_more" +version = "0.99.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.99", +] + [[package]] name = "des" version = "0.8.1" @@ -1873,6 +2132,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + [[package]] name = "ecdsa" version = "0.16.9" @@ -1887,6 +2152,30 @@ dependencies = [ "spki", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.15.0" @@ -2404,10 +2693,14 @@ dependencies = [ name = "gb-core" version = "0.1.0" dependencies = [ + "actix-web", + "anyhow", "async-trait", "axum 0.7.9", "chrono", + "minio", "mockall", + "rdkafka", "redis", "rstest", "serde", @@ -2417,8 +2710,10 @@ dependencies = [ "tokio", "tokio-test", "tokio-tungstenite 0.24.0", + "tonic 0.10.2", "tracing", "uuid", + "zitadel", ] [[package]] @@ -2446,6 +2741,7 @@ dependencies = [ name = "gb-file" version = "0.1.0" dependencies = [ + "actix-web", "async-trait", "gb-core", "minio", @@ -2569,6 +2865,7 @@ dependencies = [ name = "gb-server" version = "0.1.0" dependencies = [ + "actix-web", "async-trait", "axum 0.7.9", "chrono", @@ -2674,7 +2971,6 @@ version = "0.1.0" dependencies = [ "async-trait", "gb-core", - "minio", "rstest", "serde", "serde_json", @@ -3344,7 +3640,7 @@ dependencies = [ "hyper 0.14.32", "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", ] [[package]] @@ -3359,6 +3655,19 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.6.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -3379,13 +3688,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", + "futures-channel", "futures-util", "http 1.2.0", "http-body 1.0.1", "hyper 1.6.0", "pin-project-lite", + "socket2 0.5.8", "tokio", "tower-service", + "tracing", ] [[package]] @@ -3618,6 +3930,12 @@ dependencies = [ "rusttype", ] +[[package]] +name = "impl-more" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" + [[package]] name = "indexmap" version = "1.9.3" @@ -3626,6 +3944,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -3636,6 +3955,7 @@ checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", + "serde", ] [[package]] @@ -3746,6 +4066,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -3804,6 +4133,12 @@ dependencies = [ "log", ] +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + [[package]] name = "lapin" version = "2.5.1" @@ -3922,6 +4257,23 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + [[package]] name = "lock_api" version = "0.4.12" @@ -4091,6 +4443,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -4202,7 +4555,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -4499,6 +4852,38 @@ dependencies = [ "validator", ] +[[package]] +name = "openidconnect" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47e80a9cfae4462dd29c41e987edd228971d6565553fbc14b8a11e666d91590" +dependencies = [ + "base64 0.13.1", + "chrono", + "dyn-clone", + "ed25519-dalek", + "hmac", + "http 0.2.12", + "itertools 0.10.5", + "log", + "oauth2", + "p256", + "p384", + "rand 0.8.5", + "rsa", + "serde", + "serde-value", + "serde_derive", + "serde_json", + "serde_path_to_error", + "serde_plain", + "serde_with", + "sha2", + "subtle", + "thiserror 1.0.69", + "url", +] + [[package]] name = "openssl" version = "0.10.71" @@ -4588,7 +4973,7 @@ dependencies = [ "prost 0.11.9", "thiserror 1.0.69", "tokio", - "tonic", + "tonic 0.8.3", ] [[package]] @@ -4601,7 +4986,7 @@ dependencies = [ "futures-util", "opentelemetry 0.19.0", "prost 0.11.9", - "tonic", + "tonic 0.8.3", ] [[package]] @@ -4671,7 +5056,7 @@ dependencies = [ "futures-util", "once_cell", "opentelemetry_api 0.20.0", - "ordered-float", + "ordered-float 3.9.2", "percent-encoding", "rand 0.8.5", "thiserror 1.0.69", @@ -4698,6 +5083,15 @@ dependencies = [ "libc", ] +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-float" version = "3.9.2" @@ -4861,6 +5255,43 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbjson" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" +dependencies = [ + "base64 0.21.7", + "serde", +] + +[[package]] +name = "pbjson-build" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" +dependencies = [ + "heck 0.5.0", + "itertools 0.13.0", + "prost 0.13.5", + "prost-types 0.13.5", +] + +[[package]] +name = "pbjson-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" +dependencies = [ + "bytes", + "chrono", + "pbjson", + "pbjson-build", + "prost 0.13.5", + "prost-build 0.13.5", + "serde", +] + [[package]] name = "pbkdf2" version = "0.11.0" @@ -5191,6 +5622,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prettyplease" +version = "0.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1ccf34da56fc294e7d4ccf69a85992b7dfb826b7cf57bac6a70bba3494cc08a" +dependencies = [ + "proc-macro2", + "syn 2.0.99", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -5335,6 +5776,25 @@ dependencies = [ "prost-derive 0.11.9", ] +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive 0.13.5", +] + [[package]] name = "prost-build" version = "0.7.0" @@ -5366,7 +5826,7 @@ dependencies = [ "log", "multimap 0.8.3", "petgraph 0.6.5", - "prettyplease", + "prettyplease 0.1.25", "prost 0.11.9", "prost-types 0.11.9", "regex", @@ -5375,6 +5835,26 @@ dependencies = [ "which 4.4.2", ] +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck 0.5.0", + "itertools 0.13.0", + "log", + "multimap 0.9.1", + "once_cell", + "petgraph 0.6.5", + "prettyplease 0.2.30", + "prost 0.13.5", + "prost-types 0.13.5", + "regex", + "syn 2.0.99", + "tempfile", +] + [[package]] name = "prost-derive" version = "0.7.0" @@ -5401,6 +5881,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "prost-types" version = "0.7.0" @@ -5420,6 +5913,15 @@ dependencies = [ "prost 0.11.9", ] +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost 0.13.5", +] + [[package]] name = "protobuf" version = "2.28.0" @@ -5761,6 +6263,12 @@ dependencies = [ "regex-syntax 0.8.5", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" version = "0.6.29" @@ -5816,7 +6324,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-util", "tower-service", "url", @@ -6064,7 +6572,7 @@ checksum = "2a980454b497c439c274f2feae2523ed8138bbd3d323684e1435fec62f800481" dependencies = [ "log", "rustls 0.23.23", - "rustls-native-certs", + "rustls-native-certs 0.7.3", "rustls-pki-types", "rustls-webpki 0.102.8", ] @@ -6079,7 +6587,19 @@ dependencies = [ "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", ] [[package]] @@ -6245,7 +6765,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.9.0", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -6276,6 +6809,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float 2.10.1", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.218" @@ -6310,6 +6853,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_plain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +dependencies = [ + "serde", +] + [[package]] name = "serde_qs" version = "0.8.5" @@ -6342,6 +6894,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.1", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "sha1" version = "0.10.6" @@ -6892,7 +7474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -7262,6 +7844,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls 0.23.23", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.17" @@ -7376,7 +7968,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.32", - "hyper-timeout", + "hyper-timeout 0.4.1", "percent-encoding", "pin-project", "prost 0.11.9", @@ -7391,6 +7983,80 @@ dependencies = [ "tracing-futures", ] +[[package]] +name = "tonic" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" +dependencies = [ + "async-stream", + "async-trait", + "axum 0.6.20", + "base64 0.21.7", + "bytes", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-timeout 0.4.1", + "percent-encoding", + "pin-project", + "prost 0.12.6", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "tokio", + "tokio-rustls 0.24.1", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum 0.7.9", + "base64 0.22.1", + "bytes", + "h2 0.4.8", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-timeout 0.5.2", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.5", + "rustls-native-certs 0.8.1", + "rustls-pemfile 2.2.0", + "socket2 0.5.8", + "tokio", + "tokio-rustls 0.26.2", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-types" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0081d8ee0847d01271392a5aebe960a4600f5d4da6c67648a6382a0940f8b367" +dependencies = [ + "prost 0.13.5", + "prost-types 0.13.5", + "tonic 0.12.3", +] + [[package]] name = "tower" version = "0.4.13" @@ -8798,7 +9464,29 @@ dependencies = [ "pbkdf2 0.11.0", "sha1", "time", - "zstd", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zitadel" +version = "5.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168b66027ca4fd1aa3c529f1359a59f94495db612b57223bf933b2900df4e052" +dependencies = [ + "custom_error", + "jsonwebtoken", + "openidconnect", + "pbjson-types", + "prost 0.13.5", + "prost-types 0.13.5", + "reqwest", + "serde", + "serde_json", + "serde_urlencoded", + "time", + "tokio", + "tonic 0.12.3", + "tonic-types", ] [[package]] @@ -8807,7 +9495,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe 7.2.3", ] [[package]] @@ -8820,6 +9517,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.14+zstd.1.5.7" diff --git a/Cargo.toml b/Cargo.toml index 56a3ee5..9bd8334 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,9 @@ sea-orm = { version = "0.12", features = ["sqlx-postgres", "runtime-tokio-native rdkafka = { version = "0.36", features = ["cmake-build", "ssl"] } lapin = "2.3" -# Serialization and data formats + +# Drive, Serialization and data formats +minio = "0.1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" protobuf = "3.3" @@ -71,7 +73,9 @@ opus = "0.3" image = "0.24" # Authentication and security +zitadel = {version = "5.5.1", features = ["api-common", "api-auth-v1", "zitadel-auth-v1", "credentials", "interceptors"]} jsonwebtoken = "9.2" + argon2 = "0.5" ring = "0.17" reqwest = { version = "0.11", features = ["json", "stream"] } @@ -95,6 +99,7 @@ fake = { version = "2.9", features = ["derive"] } rstest = "0.18" # Utilities +actix-web = "4.0.1" uuid = { version = "1.6", features = ["serde", "v4"] } chrono = { version = "0.4", features = ["serde"] } thiserror = "1.0" diff --git a/api.json b/api.json new file mode 100644 index 0000000..532547c --- /dev/null +++ b/api.json @@ -0,0 +1,537 @@ +openapi: 3.0.0 +info: + title: General Bots API + description: API for managing files, documents, groups, conversations, and more. + version: 1.0.0 +servers: + - url: https://api.generalbots.com/v1 + description: Production server +paths: + /files/upload: + post: + summary: Upload a file + operationId: uploadFile + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + responses: + '200': + description: File uploaded successfully + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + url: + type: string + + /files/download: + post: + summary: Download a file + operationId: downloadFile + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + responses: + '200': + description: File downloaded successfully + content: + application/octet-stream: + schema: + type: string + format: binary + + /files/copy: + post: + summary: Copy a file + operationId: copyFile + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + sourcePath: + type: string + destinationPath: + type: string + responses: + '200': + description: File copied successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + + /files/move: + post: + summary: Move a file + operationId: moveFile + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + sourcePath: + type: string + destinationPath: + type: string + responses: + '200': + description: File moved successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + + /files/delete: + post: + summary: Delete a file + operationId: deleteFile + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + responses: + '200': + description: File deleted successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + + /files/getContents: + post: + summary: Get file contents + operationId: getFileContents + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + responses: + '200': + description: File contents retrieved successfully + content: + application/json: + schema: + type: object + properties: + contents: + type: string + + /files/save: + post: + summary: Save a file + operationId: saveFile + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + contents: + type: string + responses: + '200': + description: File saved successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + + /files/createFolder: + post: + summary: Create a folder + operationId: createFolder + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + folderName: + type: string + parentFolderId: + type: string + responses: + '200': + description: Folder created successfully + content: + application/json: + schema: + type: object + properties: + folderId: + type: string + + /files/shareFolder: + post: + summary: Share a folder + operationId: shareFolder + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + folderId: + type: string + userIds: + type: array + items: + type: string + responses: + '200': + description: Folder shared successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + + /files/dirFolder: + post: + summary: List folder contents + operationId: dirFolder + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + folderId: + type: string + responses: + '200': + description: Folder contents retrieved successfully + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + type: + type: string + size: + type: integer + + /files/list: + post: + summary: List files + operationId: getFiles + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + folderId: + type: string + responses: + '200': + description: Files listed successfully + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + type: + type: string + size: + type: integer + + /files/search: + post: + summary: Search files + operationId: searchFiles + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + query: + type: string + responses: + '200': + description: Files searched successfully + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + type: + type: string + size: + type: integer + + /files/recent: + post: + summary: Get recent files + operationId: getRecentFiles + responses: + '200': + description: Recent files retrieved successfully + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + type: + type: string + size: + type: integer + + /files/favorite: + post: + summary: Toggle favorite status of a file + operationId: toggleFavorite + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + responses: + '200': + description: Favorite status toggled successfully + content: + application/json: + schema: + type: object + properties: + isFavorite: + type: boolean + + /files/versions: + post: + summary: Get file versions + operationId: getFileVersions + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + responses: + '200': + description: File versions retrieved successfully + content: + application/json: + schema: + type: array + items: + type: object + properties: + versionId: + type: string + timestamp: + type: string + size: + type: integer + + /files/restore: + post: + summary: Restore a file version + operationId: restoreFileVersion + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + versionId: + type: string + responses: + '200': + description: File version restored successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + + /files/permissions: + post: + summary: Set file permissions + operationId: setFilePermissions + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileId: + type: string + permissions: + type: object + responses: + '200': + description: File permissions updated successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + + /files/quota: + get: + summary: Get storage quota + operationId: getStorageQuota + responses: + '200': + description: Storage quota retrieved successfully + content: + application/json: + schema: + type: object + properties: + used: + type: integer + total: + type: integer + + /files/shared: + get: + summary: Get shared files + operationId: getSharedFiles + responses: + '200': + description: Shared files retrieved successfully + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + type: + type: string + size: + type: integer + + /files/sync/status: + get: + summary: Get sync status + operationId: getSyncStatus + responses: + '200': + description: Sync status retrieved successfully + content: + application/json: + schema: + type: object + properties: + status: + type: string + + /files/sync/start: + post: + summary: Start sync + operationId: startSync + responses: + '200': + description: Sync started successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + + /files/sync/stop: + post: + summary: Stop sync + operationId: stopSync + responses: + '200': + description: Sync stopped successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string \ No newline at end of file diff --git a/gb-auth/src/handlers/auth_handler.rs b/gb-auth/src/handlers/auth_handler.rs index b3a8fdd..e69de29 100644 --- a/gb-auth/src/handlers/auth_handler.rs +++ b/gb-auth/src/handlers/auth_handler.rs @@ -1,3 +0,0 @@ -use axum::{Json, Extension}; -use crate::models::{LoginRequest, LoginResponse}; -use std::sync::Arc; diff --git a/gb-auth/src/handlers/mod.rs b/gb-auth/src/handlers/mod.rs index b857d0d..c26b2a1 100644 --- a/gb-auth/src/handlers/mod.rs +++ b/gb-auth/src/handlers/mod.rs @@ -1,3 +1,2 @@ mod auth_handler; -pub use auth_handler::*; \ No newline at end of file diff --git a/gb-auth/tests/auth_service_tests.rs b/gb-auth/tests/auth_service_tests.rs index 13bf6bb..e69de29 100644 --- a/gb-auth/tests/auth_service_tests.rs +++ b/gb-auth/tests/auth_service_tests.rs @@ -1,49 +0,0 @@ -#[cfg(test)] -mod tests { - use gb_auth::services::auth_service::AuthService; - use gb_auth::models::LoginRequest; - use sqlx::PgPool; -use std::sync::Arc; - use rstest::*; - - #[fixture] - async fn auth_service() -> AuthService { - let db_pool = PgPool::connect("postgresql://postgres:postgres@localhost:5432/test_db") - .await - .expect("Failed to create database connection"); - - AuthService::new( - Arc::new(db_pool), - "test_secret".to_string(), - 3600 - ) - } - - #[rstest] - #[tokio::test] - async fn test_login_success() -> Result<(), Box> { - let auth_service = auth_service().await; - let request = LoginRequest { - email: "test@example.com".to_string(), - password: "password123".to_string(), - }; - - let result = auth_service.login(request).await; - assert!(result.is_ok()); - Ok(()) - } - - #[rstest] - #[tokio::test] - async fn test_login_invalid_credentials() -> Result<(), Box> { - let auth_service = auth_service().await; - let request = LoginRequest { - email: "wrong@example.com".to_string(), - password: "wrongpassword".to_string(), - }; - - let result = auth_service.login(request).await; - assert!(result.is_err()); - Ok(()) - } -} \ No newline at end of file diff --git a/gb-core/Cargo.toml b/gb-core/Cargo.toml index 5e3619f..eccf856 100644 --- a/gb-core/Cargo.toml +++ b/gb-core/Cargo.toml @@ -18,7 +18,12 @@ axum = { version = "0.7", features = ["json"] } serde_json = "1.0" sqlx = { workspace = true } redis = { workspace = true } - +minio = { workspace = true } +zitadel = { workspace = true } +rdkafka = { workspace = true } +tonic = { workspace = true } +actix-web ={ workspace = true } +anyhow = { workspace = true } [dev-dependencies] mockall= { workspace = true } diff --git a/gb-server/src/config.rs b/gb-core/src/config.rs similarity index 100% rename from gb-server/src/config.rs rename to gb-core/src/config.rs diff --git a/gb-file/src/db.rs b/gb-core/src/db.rs similarity index 55% rename from gb-file/src/db.rs rename to gb-core/src/db.rs index 04376f5..72b67a6 100644 --- a/gb-file/src/db.rs +++ b/gb-core/src/db.rs @@ -1,11 +1,14 @@ use anyhow::Result; -use minio_rs::client::{Client as MinioClient, ClientBuilder as MinioClientBuilder}; use rdkafka::ClientConfig; use rdkafka::producer::FutureProducer; use redis::aio::ConnectionManager as RedisConnectionManager; use sqlx::postgres::{PgPoolOptions, PgPool}; -use zitadel::api::v1::auth::AuthServiceClient; - +use zitadel::api::clients::ClientBuilder; +use zitadel::api::zitadel::auth::v1::auth_service_client::AuthServiceClient; +use minio::s3::creds::StaticProvider; +use minio::s3::http::BaseUrl; +use minio::s3::client::{Client as MinioClient, ClientBuilder as MinioClientBuilder}; +use std::str::FromStr; use crate::config::AppConfig; pub async fn init_postgres(config: &AppConfig) -> Result { @@ -14,11 +17,6 @@ pub async fn init_postgres(config: &AppConfig) -> Result { .connect(&config.database.url) .await?; - // Run migrations - sqlx::migrate!("./migrations") - .run(&pool) - .await?; - Ok(pool) } @@ -39,27 +37,55 @@ pub async fn init_kafka(config: &AppConfig) -> Result { } pub async fn init_zitadel(config: &AppConfig) -> Result> { - let channel = tonic::transport::Channel::from_shared(format!("https://{}", config.zitadel.domain))? - .connect() - .await?; - let client = AuthServiceClient::new(channel); + let mut client = ClientBuilder::new(&config.zitadel.domain) + .with_access_token(&"test") + .build_auth_client() + .await?; + + Ok(client) } -pub async fn init_minio(config: &AppConfig) -> Result { - let client = MinioClientBuilder::new() - .endpoint(&config.minio.endpoint) - .access_key(&config.minio.access_key) - .secret_key(&config.minio.secret_key) - .ssl(config.minio.use_ssl) + +pub async fn init_minio(config: &AppConfig) -> Result> { + // Construct the base URL + let base_url = format!("https://{}", config.minio.endpoint); + let base_url = BaseUrl::from_str(&base_url)?; + + // Create credentials provider + let credentials = StaticProvider::new( + &config.minio.access_key, + &config.minio.secret_key, + None, + ); + + // Build the MinIO client + let client = MinioClientBuilder::new(base_url.clone()) + .provider(Some(Box::new(credentials))) + //.secure(config.minio.use_ssl) .build()?; - - // Ensure bucket exists - if !client.bucket_exists(&config.minio.bucket).await? { - client.make_bucket(&config.minio.bucket, None).await?; - } - + Ok(client) } + + + + + + + + + + + + + + + + + + + + diff --git a/gb-core/src/lib.rs b/gb-core/src/lib.rs index ecae2c5..2559b16 100644 --- a/gb-core/src/lib.rs +++ b/gb-core/src/lib.rs @@ -1,41 +1,7 @@ +pub mod db; pub mod errors; pub mod models; pub mod traits; +pub mod config; pub use errors::{Error, ErrorKind, Result}; - - -#[derive(Clone)] -struct AppState { - db: PgPool, - redis: RedisClient, - storage: MinioClient, - message_processor: MessageProcessor, - customer: PostgresCustomerRepository, -} - - -#[cfg(test)] -mod tests { - use crate::models::{Customer, SubscriptionTier}; - use rstest::*; - -#[fixture] - fn customer() -> Customer { - Customer::new( - "Test Corp".to_string(), - "test@example.com".to_string(), - SubscriptionTier::Enterprise, - 10, - ) - } - - #[rstest] - fn test_customer_fixture(customer: Customer) { - assert_eq!(customer.name, "Test Corp"); - assert_eq!(customer.email, "test@example.com"); - - assert_eq!(customer.max_instances, 10); - - } - } diff --git a/gb-core/src/models.rs b/gb-core/src/models.rs index ec4fc1d..f9a1b52 100644 --- a/gb-core/src/models.rs +++ b/gb-core/src/models.rs @@ -1,17 +1,15 @@ use chrono::{DateTime, Utc}; -use minio_rs::client::Client as MinioClient; +use minio::s3::client::Client as MinioClient; use rdkafka::producer::FutureProducer; use redis::aio::ConnectionManager as RedisConnectionManager; use serde::{Deserialize, Serialize}; use sqlx::PgPool; use uuid::Uuid; -use zitadel::api::v1::auth::AuthServiceClient; -use crate::config::AppConfig; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; +use zitadel::api::zitadel::auth::v1::auth_service_client::AuthServiceClient; use serde_json::Value as JsonValue; use std::str::FromStr; -use uuid::Uuid; + +use crate::config::AppConfig; #[derive(Debug)] pub struct CoreError(pub String); @@ -251,17 +249,6 @@ pub struct AppState { pub minio_client: MinioClient, } -// User models -#[derive(Debug, Serialize, Deserialize)] -pub struct User { - pub id: Uuid, - pub external_id: String, // Zitadel user ID - pub username: String, - pub email: String, - pub created_at: DateTime, - pub updated_at: DateTime, -} - // File models #[derive(Debug, Serialize, Deserialize)] pub struct File { @@ -301,16 +288,7 @@ pub struct Conversation { pub struct ConversationMember { pub conversation_id: Uuid, pub user_id: Uuid, - pub joined_at: DateTime, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct Message { - pub id: Uuid, - pub conversation_id: Uuid, - pub user_id: Uuid, - pub content: String, - pub created_at: DateTime, + pub joined_at: DateTime } // Calendar models diff --git a/gb-file/Cargo.toml b/gb-file/Cargo.toml index 3f0de6e..8508587 100644 --- a/gb-file/Cargo.toml +++ b/gb-file/Cargo.toml @@ -9,12 +9,12 @@ license = { workspace = true } gb-core = { path = "../gb-core" } async-trait= { workspace = true } tokio= { workspace = true } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +serde = { workspace = true , features = ["derive"] } +serde_json ={ workspace = true } thiserror= { workspace = true } tracing= { workspace = true } -minio = "0.1.0" - +minio = { workspace = true } +actix-web ={ workspace = true } [dev-dependencies] rstest= { workspace = true } tokio-test = "0.4" diff --git a/gb-file/src/lib.rs b/gb-file/src/lib.rs index b93a7fd..e69de29 100644 --- a/gb-file/src/lib.rs +++ b/gb-file/src/lib.rs @@ -1,144 +0,0 @@ -use minio::s3::client::Client; -use minio::s3::args::{BucketExistsArgs, MakeBucketArgs, RemoveObjectArgs, GetObjectArgs, PutObjectArgs, ListObjectsArgs}; -use minio::s3::creds::StaticProvider; -use minio::s3::error::Error as MinioError; -use minio::s3::types::{BaseUrl, Item}; -use std::io::Cursor; -use std::path::Path; - -pub struct FileManager { - client: Client, - bucket_name: String, -} - -impl FileManager { - pub async fn new(endpoint: &str, access_key: &str, secret_key: &str, bucket_name: &str, use_ssl: bool) -> Result { - // Create BaseUrl from endpoint - let base_url = BaseUrl::from_string(endpoint)?; - let static_provider = StaticProvider::new( - access_key, - secret_key, - None, - ); - let client = Client::new(base_url.clone(), Some(Box::new(static_provider)), None, None).unwrap(); - - - Ok(Self { - client, - bucket_name: bucket_name.to_string(), - }) - } - - pub async fn ensure_bucket_exists(&self) -> Result<(), MinioError> { - let exists = self.client - .bucket_exists(&BucketExistsArgs::new(&self.bucket_name)?) - .await?; - if !exists { - self.client - .make_bucket(&MakeBucketArgs::new(&self.bucket_name)?) - .await?; - } - Ok(()) - } - - pub async fn upload_file(&self, path: &str, file_data: Vec) -> Result<(), MinioError> { - let reader = Cursor::new(&file_data); - let file_size = file_data.len() as u64; - - let args = PutObjectArgs::new( - &self.bucket_name, - path, - reader, - Some(file_size), - None - )?; - - self.client.put_object(&args).await?; - Ok(()) - } - - pub async fn download_file(&self, path: &str) -> Result, MinioError> { - let args = GetObjectArgs::new(&self.bucket_name, path)?; - let object = self.client.get_object(&args).await?; - let data = object.bytes().await?; - Ok(data.to_vec()) - } - - pub async fn copy_file(&self, source_path: &str, destination_path: &str) -> Result<(), MinioError> { - // Download the source file - let data = self.download_file(source_path).await?; - - // Upload it to the destination - let reader = Cursor::new(&data); - let file_size = data.len() as u64; - - let args = PutObjectArgs::new( - &self.bucket_name, - destination_path, - reader, - Some(file_size), - None - )?; - - self.client.put_object(&args).await?; - Ok(()) - } - - pub async fn move_file(&self, source_path: &str, destination_path: &str) -> Result<(), MinioError> { - self.copy_file(source_path, destination_path).await?; - self.delete_file(source_path).await?; - Ok(()) - } - - pub async fn delete_file(&self, path: &str) -> Result<(), MinioError> { - let args = RemoveObjectArgs::new(&self.bucket_name, path)?; - self.client.remove_object(&args).await?; - Ok(()) - } - - pub async fn list_files(&self, prefix: &str) -> Result, MinioError> { - // Create a predicate function that always returns true - let predicate = |_: Vec| -> bool { true }; - - let args = ListObjectsArgs::new(&self.bucket_name, &predicate)?; - let objects = self.client.list_objects(&args).await?; - - // Filter objects based on prefix manually - let file_names: Vec = objects - .into_iter() - .filter(|obj| obj.name().starts_with(prefix)) - .map(|obj| obj.name().to_string()) - .collect(); - - Ok(file_names) - } - - pub async fn get_file_contents(&self, path: &str) -> Result { - let data = self.download_file(path).await?; - let contents = String::from_utf8(data) - .map_err(|_| MinioError::InvalidResponse(400, "Invalid UTF-8 sequence".to_string()))?; - Ok(contents) - } - - pub async fn create_folder(&self, path: &str) -> Result<(), MinioError> { - let folder_path = if path.ends_with('/') { - path.to_string() - } else { - format!("{}/", path) - }; - - // Create empty file with folder path - self.upload_file(&folder_path, vec![]).await - } - - pub async fn share_folder(&self, path: &str) -> Result { - // This is just a placeholder implementation - Ok(format!("Folder shared: {}", path)) - } - - pub async fn search_files(&self, prefix: &str, query: &str) -> Result, MinioError> { - let files = self.list_files(prefix).await?; - let results = files.into_iter().filter(|f| f.contains(query)).collect(); - Ok(results) - } -} \ No newline at end of file diff --git a/gb-image/src/processor.rs b/gb-image/src/processor.rs index 0a095bf..84727aa 100644 --- a/gb-image/src/processor.rs +++ b/gb-image/src/processor.rs @@ -1,10 +1,7 @@ use gb_core::{Error, Result}; -use image::{DynamicImage, ImageOutputFormat, Rgba}; +use image::{DynamicImage, Rgba}; use imageproc::drawing::draw_text_mut; use rusttype::{Font, Scale}; -use std::io::Cursor; -use tempfile::NamedTempFile; -use std::io::Write; use std::fs; @@ -15,28 +12,7 @@ impl ImageProcessor { Self } - pub async fn extract_text(&self, image: &DynamicImage) -> Result { - // Create a temporary file - let mut temp_file = NamedTempFile::new() - .map_err(|e| Error::internal(format!("Failed to create temp file: {}", e)))?; - - // Convert image to PNG and write to temp file - let mut cursor = Cursor::new(Vec::new()); - image.write_to(&mut cursor, ImageOutputFormat::Png) - .map_err(|e| Error::internal(format!("Failed to encode image: {}", e)))?; - - temp_file.write_all(&cursor.into_inner()) - .map_err(|e| Error::internal(format!("Failed to write to temp file: {}", e)))?; - - - api.set_image(temp_file.path().to_str().unwrap()) - .map_err(|e| Error::internal(format!("Failed to set image: {}", e)))? - .recognize() - .map_err(|e| Error::internal(format!("Failed to recognize text: {}", e)))? - .get_text() - .map_err(|e| Error::internal(format!("Failed to get text: {}", e))) - } - + pub fn resize(&self, image: &DynamicImage, width: u32, height: u32) -> DynamicImage { image.resize(width, height, image::imageops::FilterType::Lanczos3) diff --git a/gb-server/Cargo.toml b/gb-server/Cargo.toml index c131f67..437d494 100644 --- a/gb-server/Cargo.toml +++ b/gb-server/Cargo.toml @@ -27,6 +27,7 @@ hyper = { workspace = true, features = ["server"] } hyper-util = { workspace = true } tower = { workspace = true } tower-http = { workspace = true, features = ["cors", "trace"] } +actix-web = { workspace = true } [dev-dependencies] rstest = { workspace = true } diff --git a/gb-server/src/lib.rs b/gb-server/src/lib.rs index c2a5ace..e69de29 100644 --- a/gb-server/src/lib.rs +++ b/gb-server/src/lib.rs @@ -1,65 +0,0 @@ -pub mod router; - -pub use router::{create_router, ApiState}; - -#[cfg(test)] -mod tests { - use super::*; - use gb_messaging::MessageProcessor; - use axum::Router; - use tower::ServiceExt; - use uuid::Uuid; - - #[tokio::test] - async fn test_api_integration() { - // Initialize message processor - let processor = MessageProcessor::new(); - - // Create router - let app: Router = create_router(processor); - - // Test health endpoint - let response = app - .clone() - .oneshot( - axum::http::Request::builder() - .uri("/health") - .body(axum::body::Body::empty()) - .unwrap(), - ) - .await - .unwrap(); - - assert_eq!(response.status(), axum::http::StatusCode::OK); - - // Test message sending - let message = gb_core::models::Message { - id: Uuid::new_v4(), - customer_id: Uuid::new_v4(), - instance_id: Uuid::new_v4(), - conversation_id: Uuid::new_v4(), - sender_id: Uuid::new_v4(), - kind: "test".to_string(), - content: "integration test".to_string(), - metadata: serde_json::Value::Object(serde_json::Map::new()), - created_at: Some(chrono::Utc::now()), - shard_key: Some(0), - }; - - let response = app - .oneshot( - axum::http::Request::builder() - .method("POST") - .uri("/messages") - .header("content-type", "application/json") - .body(axum::body::Body::from( - serde_json::to_string(&message).unwrap() - )) - .unwrap(), - ) - .await - .unwrap(); - - assert_eq!(response.status(), axum::http::StatusCode::OK); - } -} diff --git a/gb-server/src/main.rs b/gb-server/src/main.rs index 02d77b3..fe53a97 100644 --- a/gb-server/src/main.rs +++ b/gb-server/src/main.rs @@ -1,22 +1,9 @@ -use gb_core::{Error, Result}; -use tracing::{info, error}; -use std::{net::SocketAddr, sync::Arc}; -use sqlx::PgPool; -use redis::Client as RedisClient; -use minio::MinioClient; -use gb_api::PostgresCustomerRepository; -use gb_messaging::MessageProcessor; -use axum::Router; -use tower_http::trace::TraceLayer; - -use actix_cors::Cors; use actix_web::{middleware, web, App, HttpServer}; -use dotenv::dotenv; use tracing_subscriber::fmt::format::FmtSpan; -use crate::config::AppConfig; -use crate::db::{init_kafka, init_minio, init_postgres, init_redis, init_zitadel}; -use crate::router::*; +use gb_core::config::AppConfig; +use gb_core::db::{init_kafka, init_minio, init_postgres, init_redis, init_zitadel}; + #[actix_web::main] async fn main() -> std::io::Result<()> { @@ -59,7 +46,7 @@ async fn main() -> std::io::Result<()> { .wrap(middleware::Compress::default()) .wrap(cors) .app_data(app_state.clone()) - .configure(filesrouter::files_router_configure) + .configure(files_router_configure) }) .bind((config.server.host.clone(), config.server.port))? .run() diff --git a/gb-server/src/router.rs b/gb-server/src/router.rs index 366a2d0..5851f82 100644 --- a/gb-server/src/router.rs +++ b/gb-server/src/router.rs @@ -1,299 +1,22 @@ use axum::{ - routing::{get, post}, - Router, - extract::{ - ws::WebSocket, - Path, State, WebSocketUpgrade, - }, + extract::{ws::WebSocket, Path, State, WebSocketUpgrade}, response::IntoResponse, - Json, + routing::{get, post}, + Json, Router, }; -use gb_core::{Result, Error, models::*}; -use gb_messaging::{MessageProcessor, models::MessageEnvelope}; -use std::{sync::Arc, collections::HashMap}; -use tokio::sync::Mutex; -use tracing::{instrument, error}; -use uuid::Uuid; use futures_util::StreamExt; - +use gb_core::{models::*, Error, Result}; +use gb_messaging::{models::MessageEnvelope, MessageProcessor}; +use std::{collections::HashMap, sync::Arc}; +use tokio::sync::Mutex; +use tracing::{error, instrument}; +use uuid::Uuid; pub fn create_router(message_processor: AppState) -> Router { let state = Arc::new(ApiState { message_processor: Mutex::new(message_processor), }); - Router::new() - - - - // File & Document Management - .route("/files/upload", post(upload_file)) - .route("/files/download", post(download)) - .route("/files/copy", post(copy_file)) - .route("/files/move", post(move_file)) - .route("/files/delete", post(delete_file)) - .route("/files/getContents", post(get_file_contents)) - .route("/files/save", post(save_file)) - .route("/files/createFolder", post(create_folder)) - .route("/files/shareFolder", post(share_folder)) - .route("/files/dirFolder", post(dir_folder)) - .route("/files/list", post(get_files)) - .route("/files/search", post(search_files)) - .route("/files/recent", post(get_recent_files)) - .route("/files/favorite", post(toggle_favorite)) - .route("/files/versions", post(get_file_versions)) - .route("/files/restore", post(restore_file_version)) - .route("/files/permissions", post(set_file_permissions)) - .route("/files/quota", get(get_storage_quota)) - .route("/files/shared", get(get_shared_files)) - .route("/files/sync/status", get(get_sync_status)) - .route("/files/sync/start", post(start_sync)) - .route("/files/sync/stop", post(stop_sync)) - - // full ode bucket is abstrctd path variable, src, dest, full file manager acessible via actixweb ALL methods no excluses, inline funcition params, s3 api inside, all methodos, full code. // Document Processing - - .route("/docs/merge", post(merge_documents)) - .route("/docs/convert", post(convert_document)) - .route("/docs/fill", post(fill_document)) - .route("/docs/export", post(export_document)) - .route("/docs/import", post(import_document)) - - // Groups & Organizations - .route("/groups/create", post(create_group)) - .route("/groups/update", put(update_group)) - .route("/groups/delete", delete(delete_group)) - .route("/groups/list", get(get_groups)) - .route("/groups/search", post(search_groups)) - .route("/groups/members", get(get_group_members)) - .route("/groups/members/add", post(add_group_member)) - .route("/groups/members/remove", post(remove_group_member)) - .route("/groups/permissions", post(set_group_permissions)) - .route("/groups/settings", post(update_group_settings)) - .route("/groups/analytics", get(get_group_analytics)) - .route("/groups/join/request", post(request_group_join)) - .route("/groups/join/approve", post(approve_join_request)) - .route("/groups/join/reject", post(reject_join_request)) - .route("/groups/invites/send", post(send_group_invite)) - .route("/groups/invites/list", get(list_group_invites)) - - // Conversations & Real-time Communication - .route("/conversations/create", post(create_conversation)) - .route("/conversations/join", post(join_conversation)) - .route("/conversations/leave", post(leave_conversation)) - .route("/conversations/members", get(get_conversation_members)) - .route("/conversations/messages", get(get_messages)) - .route("/conversations/messages/send", post(send_message)) - .route("/conversations/messages/edit", put(edit_message)) - .route("/conversations/messages/delete", delete(delete_message)) - .route("/conversations/messages/react", post(react_to_message)) - .route("/conversations/messages/pin", post(pin_message)) - .route("/conversations/messages/search", post(search_messages)) - .route("/conversations/calls/start", post(start_call)) - .route("/conversations/calls/join", post(join_call)) - .route("/conversations/calls/leave", post(leave_call)) - .route("/conversations/calls/mute", post(mute_participant)) - .route("/conversations/calls/unmute", post(unmute_participant)) - .route("/conversations/screen/share", post(share_screen)) - .route("/conversations/screen/stop", post(stop_screen_share)) - .route("/conversations/recording/start", post(start_recording)) - .route("/conversations/recording/stop", post(stop_recording)) - .route("/conversations/whiteboard/create", post(create_whiteboard)) - .route("/conversations/whiteboard/collaborate", post(collaborate_whiteboard)) - - // Communication Services - .route("/comm/email/send", post(send_email)) - .route("/comm/email/template", post(send_template_email)) - .route("/comm/email/schedule", post(schedule_email)) - .route("/comm/email/cancel", post(cancel_scheduled_email)) - .route("/comm/sms/send", post(send_sms)) - .route("/comm/sms/bulk", post(send_bulk_sms)) - .route("/comm/notifications/send", post(send_notification)) - .route("/comm/notifications/preferences", post(set_notification_preferences)) - .route("/comm/broadcast/send", post(send_broadcast)) - .route("/comm/contacts/import", post(import_contacts)) - .route("/comm/contacts/export", post(export_contacts)) - .route("/comm/contacts/sync", post(sync_contacts)) - .route("/comm/contacts/groups", post(manage_contact_groups)) - - // User Management & Authentication - .route("/users/create", post(create_user)) - .route("/users/update", put(update_user)) - .route("/users/delete", delete(delete_user)) - .route("/users/list", get(get_users)) - .route("/users/search", post(search_users)) - .route("/users/profile", get(get_user_profile)) - .route("/users/profile/update", put(update_profile)) - .route("/users/settings", post(update_user_settings)) - .route("/users/permissions", post(set_user_permissions)) - .route("/users/roles", post(manage_user_roles)) - .route("/users/status", post(update_user_status)) - .route("/users/presence", get(get_user_presence)) - .route("/users/activity", get(get_user_activity)) - .route("/users/security/2fa/enable", post(enable_2fa)) - .route("/users/security/2fa/disable", post(disable_2fa)) - .route("/users/security/devices", get(get_registered_devices)) - .route("/users/security/sessions", get(get_active_sessions)) - .route("/users/notifications/settings", post(update_notification_settings)) - - // Calendar & Task Management - .route("/calendar/events/create", post(create_event)) - .route("/calendar/events/update", put(update_event)) - .route("/calendar/events/delete", delete(delete_event)) - .route("/calendar/events/list", get(get_calendar_events)) - .route("/calendar/events/search", post(search_events)) - .route("/calendar/availability/check", post(check_availability)) - .route("/calendar/schedule/meeting", post(schedule_meeting)) - .route("/calendar/reminders/set", post(set_reminder)) - .route("/tasks/create", post(create_task)) - .route("/tasks/update", put(update_task)) - .route("/tasks/delete", delete(delete_task)) - .route("/tasks/list", get(get_tasks)) - .route("/tasks/assign", post(assign_task)) - .route("/tasks/status/update", put(update_task_status)) - .route("/tasks/priority/set", post(set_task_priority)) - .route("/tasks/dependencies/set", post(set_task_dependencies)) - - // Storage & Data Management - .route("/storage/save", post(save_to_storage)) - .route("/storage/batch", post(save_batch_to_storage)) - .route("/storage/json", post(save_json_to_storage)) - .route("/storage/delete", delete(delete_from_storage)) - .route("/storage/quota/check", get(check_storage_quota)) - .route("/storage/cleanup", post(cleanup_storage)) - .route("/storage/backup/create", post(create_backup)) - .route("/storage/backup/restore", post(restore_backup)) - .route("/storage/archive", post(archive_data)) - .route("/storage/metrics", get(get_storage_metrics)) - - - // Analytics & Reporting - .route("/analytics/dashboard", get(get_dashboard_data)) - .route("/analytics/reports/generate", post(generate_report)) - .route("/analytics/reports/schedule", post(schedule_report)) - .route("/analytics/metrics/collect", post(collect_metrics)) - .route("/analytics/insights/generate", post(generate_insights)) - .route("/analytics/trends/analyze", post(analyze_trends)) - .route("/analytics/export", post(export_analytics)) - - // System & Administration - .route("/admin/system/status", get(get_system_status)) - .route("/admin/system/metrics", get(get_system_metrics)) - .route("/admin/logs/view", get(view_logs)) - .route("/admin/logs/export", post(export_logs)) - .route("/admin/config/update", post(update_config)) - .route("/admin/maintenance/schedule", post(schedule_maintenance)) - .route("/admin/backup/create", post(create_system_backup)) - .route("/admin/backup/restore", post(restore_system_backup)) - .route("/admin/users/manage", post(manage_system_users)) - .route("/admin/roles/manage", post(manage_system_roles)) - .route("/admin/quotas/manage", post(manage_quotas)) - .route("/admin/licenses/manage", post(manage_licenses)) - - // AI & Machine Learning - .route("/ai/analyze/text", post(analyze_text)) - .route("/ai/analyze/image", post(analyze_image)) - .route("/ai/generate/text", post(generate_text)) - .route("/ai/generate/image", post(generate_image)) - .route("/ai/translate", post(translate_content)) - .route("/ai/summarize", post(summarize_content)) - .route("/ai/recommend", post(get_recommendations)) - .route("/ai/train/model", post(train_custom_model)) - .route("/ai/predict", post(make_prediction)) - - // Security & Compliance - .route("/security/audit/logs", get(get_audit_logs)) - .route("/security/compliance/check", post(check_compliance)) - .route("/security/threats/scan", post(scan_for_threats)) - .route("/security/access/review", post(review_access)) - .route("/security/encryption/manage", post(manage_encryption)) - .route("/security/certificates/manage", post(manage_certificates)) - - // Health & Monitoring - .route("/health", get(health_check)) - .route("/health/detailed", get(detailed_health_check)) - .route("/monitoring/status", get(get_monitoring_status)) - .route("/monitoring/alerts", get(get_active_alerts)) - .route("/monitoring/metrics", get(get_monitoring_metrics)) - .with_state(state) + Router::new() + .route("/monitoring/metrics", get(get_monitoring_metrics)) + .with_state(state) } - -async fn handle_ws_connection( - ws: WebSocket, - state: Arc, -) -> Result<()> { - let (_sender, mut receiver) = ws.split(); - - while let Some(Ok(msg)) = receiver.next().await { - if let Ok(text) = msg.to_text() { - if let Ok(_envelope) = serde_json::from_str::(text) { - let mut processor = state.message_processor.lock().await; - if let Err(e) = processor.process_messages().await { - error!("Failed to process message: {}", e); - } - } - } - } - Ok(()) -} - -#[instrument(skip_all)] -async fn websocket_handler( - State(state): State>, - ws: WebSocketUpgrade, -) -> impl IntoResponse { - ws.on_upgrade(move |socket| async move { - let _ = handle_ws_connection(socket, state).await; - }) -} - -#[instrument(skip_all)] -async fn send_message( - State(state): State>, - Json(message): Json, -) -> Result> { - // Clone the message before using it in envelope - let envelope = MessageEnvelope { - id: Uuid::new_v4(), - message: message.clone(), // Clone here - metadata: HashMap::new(), - }; - - let mut processor = state.message_processor.lock().await; - processor.add_message(message) // Use original message here - .await - .map_err(|e| Error::internal(format!("Failed to add message: {}", e)))?; - - Ok(Json(MessageId(envelope.id))) -} - -#[instrument(skip_all)] -async fn get_message( - State(_state): State>, - Path(_id): Path, -) -> Result> { - todo!() -} - -#[instrument(skip_all)] -async fn create_room( - State(_state): State>, - Json(_config): Json, -) -> Result> { - todo!() -} - -#[instrument(skip_all)] -async fn get_room( - State(_state): State>, - Path(_id): Path, -) -> Result> { - todo!() -} - -#[instrument(skip_all)] -async fn join_room( - State(_state): State>, - Path(_id): Path, - Json(_user_id): Json, -) -> Result> { - todo!() -} \ No newline at end of file diff --git a/gb-testing/src/chaos/mod.rs b/gb-testing/src/chaos/mod.rs index c93282f..e69de29 100644 --- a/gb-testing/src/chaos/mod.rs +++ b/gb-testing/src/chaos/mod.rs @@ -1,36 +0,0 @@ -use rand::seq::SliceRandom; - -pub struct ChaosTest { - client: Client, - namespace: String, -} - -impl ChaosTest { - pub async fn new(namespace: String) -> anyhow::Result { - let client = Client::try_default().await?; - Ok(Self { client, namespace }) - } - - pub async fn kill_random_pod(&self) -> anyhow::Result<()> { - let pods: Api = Api::namespaced(self.client.clone(), &self.namespace); - let pod_list = pods.list(&Default::default()).await?; - - if let Some(pod) = pod_list.items.choose(&mut rand::thread_rng()) { - if let Some(name) = &pod.metadata.name { - pods.delete(name, &DeleteParams::default()).await?; - } - } - - Ok(()) - } - - pub async fn network_partition(&self) -> anyhow::Result<()> { - // Network partition test implementation - Ok(()) - } - - pub async fn resource_exhaustion(&self) -> anyhow::Result<()> { - // Resource exhaustion test implementation - Ok(()) - } -} diff --git a/gb-utils/src/detector.rs b/gb-utils/src/detector.rs index d49b9ab..6849424 100644 --- a/gb-utils/src/detector.rs +++ b/gb-utils/src/detector.rs @@ -1,18 +1,9 @@ use gb_core::{Result, Error}; -use mime_guess::{from_path, mime}; -use std::path::Path; use tracing::instrument; pub struct FileTypeDetector; impl FileTypeDetector { - #[instrument] - pub fn detect_mime_type(path: &Path) -> Result { - from_path(path) - .first_or_octet_stream() - .to_owned() - .into() - } #[instrument(skip(data))] pub fn detect_from_bytes(data: &[u8]) -> Result { @@ -59,16 +50,8 @@ pub enum FileType { mod tests { use super::*; use rstest::*; - use std::path::PathBuf; + - #[rstest] - fn test_detect_mime_type() -> Result<()> { - let path = PathBuf::from("test.pdf"); - let mime = FileTypeDetector::detect_mime_type(&path)?; - assert_eq!(mime.type_(), "application"); - assert_eq!(mime.subtype(), "pdf"); - Ok(()) - } #[rstest] fn test_detect_from_bytes() -> Result<()> { diff --git a/gb-utils/src/lib.rs b/gb-utils/src/lib.rs index 8aa93ef..e69de29 100644 --- a/gb-utils/src/lib.rs +++ b/gb-utils/src/lib.rs @@ -1,40 +0,0 @@ -pub mod detector; -pub mod processor; - -pub use detector::{FileTypeDetector, FileType}; -pub use processor::{FileProcessor, ProcessedFile, ProcessedContent}; - -#[cfg(test)] -mod tests { - use super::*; - use gb_core::Result; - use std::path::PathBuf; - - #[tokio::test] - async fn test_utils_integration() -> Result<()> { - // Initialize processor - let processor = FileProcessor::new()?; - - // Test PDF processing - let pdf_data = b"%PDF-1.4\nTest PDF"; - let pdf_path = PathBuf::from("test.pdf"); - let processed_pdf = processor.process_file(pdf_data, &pdf_path).await?; - assert_eq!(processed_pdf.content_type(), "text"); - - // Test image processing - let image_data = [0x89, 0x50, 0x4E, 0x47]; // PNG header - let image_path = PathBuf::from("test.png"); - let processed_image = processor.process_file(&image_data, &image_path).await?; - assert_eq!(processed_image.content_type(), "image"); - - // Test file type detection - let detected_type = FileTypeDetector::detect_from_bytes(pdf_data)?; - assert_eq!(detected_type, FileType::Pdf); - - let mime_type = FileTypeDetector::detect_mime_type(&pdf_path)?; - assert_eq!(mime_type.type_(), "application"); - assert_eq!(mime_type.subtype(), "pdf"); - - Ok(()) - } -} diff --git a/gb-utils/src/processor.rs b/gb-utils/src/processor.rs index f58690a..e69de29 100644 --- a/gb-utils/src/processor.rs +++ b/gb-utils/src/processor.rs @@ -1,216 +0,0 @@ -use gb_core::{Result, Error}; -use gb_document::{PdfProcessor, WordProcessor, ExcelProcessor}; -use gb_image::{ImageProcessor, ImageConverter}; -use super::detector::{FileTypeDetector, FileType}; -use std::path::Path; -use tracing::{instrument, error}; -use uuid::Uuid; - -pub struct FileProcessor { - image_processor: ImageProcessor, -} - -impl FileProcessor { - pub fn new() -> Result { - Ok(Self { - image_processor: ImageProcessor::new()?, - }) - } - - #[instrument(skip(self, data))] - pub async fn process_file(&self, data: &[u8], path: &Path) -> Result { - let file_type = FileTypeDetector::detect_from_bytes(data)?; - let mime_type = FileTypeDetector::detect_mime_type(path)?; - - match file_type { - FileType::Pdf => { - let text = PdfProcessor::extract_text(data)?; - Ok(ProcessedFile { - id: Uuid::new_v4(), - original_name: path.file_name().unwrap().to_string_lossy().to_string(), - mime_type, - content: ProcessedContent::Text(text), - }) - } - FileType::Word => { - let text = WordProcessor::extract_text(data)?; - Ok(ProcessedFile { - id: Uuid::new_v4(), - original_name: path.file_name().unwrap().to_string_lossy().to_string(), - mime_type, - content: ProcessedContent::Text(text), - }) - } - FileType::Excel => { - let json = ExcelProcessor::extract_as_json(data)?; - Ok(ProcessedFile { - id: Uuid::new_v4(), - original_name: path.file_name().unwrap().to_string_lossy().to_string(), - mime_type, - content: ProcessedContent::Json(json), - }) - } - FileType::Png | FileType::Jpeg | FileType::WebP => { - let image = self.image_processor.load_image(data)?; - let text = self.image_processor.extract_text(&image)?; - Ok(ProcessedFile { - id: Uuid::new_v4(), - original_name: path.file_name().unwrap().to_string_lossy().to_string(), - mime_type, - content: ProcessedContent::Image { - text, - width: image.width(), - height: image.height(), - }, - }) - } - } - } - - #[instrument(skip(self, file))] - pub async fn convert_file( - &self, - file: &ProcessedFile, - target_type: FileType, - ) -> Result> { - match (&file.content, target_type) { - (ProcessedContent::Image { .. }, FileType::Png) => { - let image = self.image_processor.load_image(file.raw_data())?; - ImageConverter::to_png(&image) - } - (ProcessedContent::Image { .. }, FileType::Jpeg) => { - let image = self.image_processor.load_image(file.raw_data())?; - ImageConverter::to_jpeg(&image, 80) - } - EOL - -# Continuing gb-utils/src/processor.rs -cat >> gb-utils/src/processor.rs << 'EOL' - (ProcessedContent::Image { .. }, FileType::WebP) => { - let image = self.image_processor.load_image(file.raw_data())?; - ImageConverter::to_webp(&image, 80) - } - (ProcessedContent::Text(text), FileType::Pdf) => { - let doc = PdfProcessor::create_document(text)?; - Ok(doc) - } - (ProcessedContent::Text(text), FileType::Word) => { - let doc = WordProcessor::create_document(text)?; - Ok(doc) - } - (ProcessedContent::Json(json), FileType::Excel) => { - let data: Vec> = serde_json::from_value(json.clone())?; - let headers: Vec<&str> = data[0].iter().map(|s| s.as_str()).collect(); - ExcelProcessor::create_excel(&headers, &data[1..]) - } - _ => Err(Error::internal(format!( - "Unsupported conversion: {:?} to {:?}", - file.content_type(), - target_type - ))), - } - } -} - -#[derive(Debug, Clone)] -pub struct ProcessedFile { - pub id: Uuid, - pub original_name: String, - pub mime_type: mime::Mime, - pub content: ProcessedContent, -} - -#[derive(Debug, Clone)] -pub enum ProcessedContent { - Text(String), - Json(serde_json::Value), - Image { - text: String, - width: u32, - height: u32, - }, -} - -impl ProcessedFile { - pub fn content_type(&self) -> &'static str { - match self.content { - ProcessedContent::Text(_) => "text", - ProcessedContent::Json(_) => "json", - ProcessedContent::Image { .. } => "image", - } - } - - pub fn raw_data(&self) -> &[u8] { - // This is a placeholder - in a real implementation, - // we would store the raw data alongside the processed content - &[] - } -} - -#[cfg(test)] -mod tests { - use super::*; - use rstest::*; - - #[fixture] - fn processor() -> FileProcessor { - FileProcessor::new().unwrap() - } - - #[rstest] - #[tokio::test] - async fn test_process_pdf(processor: FileProcessor) -> Result<()> { - let pdf_data = b"%PDF-1.4\nTest content"; - let path = Path::new("test.pdf"); - - let processed = processor.process_file(pdf_data, path).await?; - assert_eq!(processed.content_type(), "text"); - - if let ProcessedContent::Text(text) = &processed.content { - assert!(text.contains("Test content")); - } else { - panic!("Expected text content"); - } - - Ok(()) - } - - #[rstest] - #[tokio::test] - async fn test_process_image(processor: FileProcessor) -> Result<()> { - let image_data = [0x89, 0x50, 0x4E, 0x47]; // PNG header - let path = Path::new("test.png"); - - let processed = processor.process_file(&image_data, path).await?; - assert_eq!(processed.content_type(), "image"); - - if let ProcessedContent::Image { width, height, .. } = processed.content { - assert!(width > 0); - assert!(height > 0); - } else { - panic!("Expected image content"); - } - - Ok(()) - } - - #[rstest] - #[tokio::test] - async fn test_convert_file(processor: FileProcessor) -> Result<()> { - let text = "Test conversion"; - let processed = ProcessedFile { - id: Uuid::new_v4(), - original_name: "test.txt".to_string(), - mime_type: mime::TEXT_PLAIN, - content: ProcessedContent::Text(text.to_string()), - }; - - let pdf_data = processor.convert_file(&processed, FileType::Pdf).await?; - assert!(!pdf_data.is_empty()); - - let word_data = processor.convert_file(&processed, FileType::Word).await?; - assert!(!word_data.is_empty()); - - Ok(()) - } -} diff --git a/gb-vm/Cargo.toml b/gb-vm/Cargo.toml index ba448c3..d41db73 100644 --- a/gb-vm/Cargo.toml +++ b/gb-vm/Cargo.toml @@ -13,7 +13,6 @@ serde = { workspace = true } serde_json = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } -minio = "0.1.0" [dev-dependencies] rstest = { workspace = true } diff --git a/gb-vm/src/lib.rs b/gb-vm/src/lib.rs index b93a7fd..e69de29 100644 --- a/gb-vm/src/lib.rs +++ b/gb-vm/src/lib.rs @@ -1,144 +0,0 @@ -use minio::s3::client::Client; -use minio::s3::args::{BucketExistsArgs, MakeBucketArgs, RemoveObjectArgs, GetObjectArgs, PutObjectArgs, ListObjectsArgs}; -use minio::s3::creds::StaticProvider; -use minio::s3::error::Error as MinioError; -use minio::s3::types::{BaseUrl, Item}; -use std::io::Cursor; -use std::path::Path; - -pub struct FileManager { - client: Client, - bucket_name: String, -} - -impl FileManager { - pub async fn new(endpoint: &str, access_key: &str, secret_key: &str, bucket_name: &str, use_ssl: bool) -> Result { - // Create BaseUrl from endpoint - let base_url = BaseUrl::from_string(endpoint)?; - let static_provider = StaticProvider::new( - access_key, - secret_key, - None, - ); - let client = Client::new(base_url.clone(), Some(Box::new(static_provider)), None, None).unwrap(); - - - Ok(Self { - client, - bucket_name: bucket_name.to_string(), - }) - } - - pub async fn ensure_bucket_exists(&self) -> Result<(), MinioError> { - let exists = self.client - .bucket_exists(&BucketExistsArgs::new(&self.bucket_name)?) - .await?; - if !exists { - self.client - .make_bucket(&MakeBucketArgs::new(&self.bucket_name)?) - .await?; - } - Ok(()) - } - - pub async fn upload_file(&self, path: &str, file_data: Vec) -> Result<(), MinioError> { - let reader = Cursor::new(&file_data); - let file_size = file_data.len() as u64; - - let args = PutObjectArgs::new( - &self.bucket_name, - path, - reader, - Some(file_size), - None - )?; - - self.client.put_object(&args).await?; - Ok(()) - } - - pub async fn download_file(&self, path: &str) -> Result, MinioError> { - let args = GetObjectArgs::new(&self.bucket_name, path)?; - let object = self.client.get_object(&args).await?; - let data = object.bytes().await?; - Ok(data.to_vec()) - } - - pub async fn copy_file(&self, source_path: &str, destination_path: &str) -> Result<(), MinioError> { - // Download the source file - let data = self.download_file(source_path).await?; - - // Upload it to the destination - let reader = Cursor::new(&data); - let file_size = data.len() as u64; - - let args = PutObjectArgs::new( - &self.bucket_name, - destination_path, - reader, - Some(file_size), - None - )?; - - self.client.put_object(&args).await?; - Ok(()) - } - - pub async fn move_file(&self, source_path: &str, destination_path: &str) -> Result<(), MinioError> { - self.copy_file(source_path, destination_path).await?; - self.delete_file(source_path).await?; - Ok(()) - } - - pub async fn delete_file(&self, path: &str) -> Result<(), MinioError> { - let args = RemoveObjectArgs::new(&self.bucket_name, path)?; - self.client.remove_object(&args).await?; - Ok(()) - } - - pub async fn list_files(&self, prefix: &str) -> Result, MinioError> { - // Create a predicate function that always returns true - let predicate = |_: Vec| -> bool { true }; - - let args = ListObjectsArgs::new(&self.bucket_name, &predicate)?; - let objects = self.client.list_objects(&args).await?; - - // Filter objects based on prefix manually - let file_names: Vec = objects - .into_iter() - .filter(|obj| obj.name().starts_with(prefix)) - .map(|obj| obj.name().to_string()) - .collect(); - - Ok(file_names) - } - - pub async fn get_file_contents(&self, path: &str) -> Result { - let data = self.download_file(path).await?; - let contents = String::from_utf8(data) - .map_err(|_| MinioError::InvalidResponse(400, "Invalid UTF-8 sequence".to_string()))?; - Ok(contents) - } - - pub async fn create_folder(&self, path: &str) -> Result<(), MinioError> { - let folder_path = if path.ends_with('/') { - path.to_string() - } else { - format!("{}/", path) - }; - - // Create empty file with folder path - self.upload_file(&folder_path, vec![]).await - } - - pub async fn share_folder(&self, path: &str) -> Result { - // This is just a placeholder implementation - Ok(format!("Folder shared: {}", path)) - } - - pub async fn search_files(&self, prefix: &str, query: &str) -> Result, MinioError> { - let files = self.list_files(prefix).await?; - let results = files.into_iter().filter(|f| f.contains(query)).collect(); - Ok(results) - } -} \ No newline at end of file