From 1d775e3e1a223c0d834f72e79ca1443b2e2cf837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Wo=C5=BAniak?= Date: Thu, 1 Dec 2022 17:39:06 +0100 Subject: [PATCH] Start payments --- .gitignore | 1 + Cargo.lock | 773 +++++++++++++++++- Cargo.toml | 3 +- crates/channels/Cargo.toml | 3 +- crates/channels/src/lib.rs | 2 + crates/channels/src/orders.rs | 21 +- crates/channels/src/payments.rs | 95 +++ crates/config/src/lib.rs | 194 +++-- crates/model/Cargo.toml | 11 +- .../migrations/202204131841_init.sql | 2 +- crates/order_manager/src/actions/order.rs | 17 +- crates/order_manager/src/db/order.rs | 1 + crates/order_manager/src/db/order_address.rs | 156 ++++ crates/order_manager/src/db/order_item.rs | 1 + crates/order_manager/src/main.rs | 1 + crates/payment_adapter/Cargo.toml | 10 + crates/payment_adapter/src/lib.rs | 48 ++ crates/payment_manager/Cargo.toml | 29 +- crates/payment_manager/src/actions/mod.rs | 2 + .../src/{lib.rs => actions/pay_u_adapter.rs} | 193 ++--- .../src/actions/t_pay_adapter.rs | 0 crates/payment_manager/src/context.rs | 0 crates/payment_manager/src/db.rs | 0 crates/payment_manager/src/main.rs | 53 ++ crates/payment_manager/src/mqtt.rs | 0 .../payment_manager/src/pay_u_adapter/mod.rs | 44 +- crates/payment_manager/src/rpc.rs | 0 27 files changed, 1409 insertions(+), 251 deletions(-) create mode 100644 crates/channels/src/payments.rs create mode 100644 crates/payment_adapter/Cargo.toml create mode 100644 crates/payment_adapter/src/lib.rs create mode 100644 crates/payment_manager/src/actions/mod.rs rename crates/payment_manager/src/{lib.rs => actions/pay_u_adapter.rs} (55%) create mode 100644 crates/payment_manager/src/actions/t_pay_adapter.rs create mode 100644 crates/payment_manager/src/context.rs create mode 100644 crates/payment_manager/src/db.rs create mode 100644 crates/payment_manager/src/main.rs create mode 100644 crates/payment_manager/src/mqtt.rs create mode 100644 crates/payment_manager/src/rpc.rs diff --git a/.gitignore b/.gitignore index 2e0a6fd..fe78e04 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ bazzar.toml node_modules web/dist web/tmp +adapters diff --git a/Cargo.lock b/Cargo.lock index 51c4ed8..2987682 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,6 +246,15 @@ dependencies = [ "syn", ] +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -287,6 +296,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "ambient-authority" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8ad6edb4840b78c5c3d88de606b22252d552b55f3a4699fbb10fc070ec3049" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -361,7 +376,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi 0.3.9", ] @@ -576,6 +591,71 @@ dependencies = [ "bytes", ] +[[package]] +name = "cap-fs-ext" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0e103ce36d217d568903ad27b14ec2238ecb5d65bad2e756a8f3c0d651506e" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes", + "windows-sys 0.36.1", +] + +[[package]] +name = "cap-primitives" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3f336aa91cce16033ed3c94ac91d98956c49b420e6d6cd0dd7d0e386a57085" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix", + "winapi-util", + "windows-sys 0.36.1", + "winx", +] + +[[package]] +name = "cap-rand" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d14b9606aa9550d34651bc481443203bc014237bdb992d201d2afa62d2ec6dea" +dependencies = [ + "ambient-authority", + "rand 0.8.5", +] + +[[package]] +name = "cap-std" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d6e70b626eceac9d6fc790fe2d72cc3f2f7bc3c35f467690c54a526b0f56db" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "ipnet", + "rustix", +] + +[[package]] +name = "cap-time-ext" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a0524f7c4cff2ea547ae2b652bf7a348fd3e48f76556dc928d8b45ab2f1d50" +dependencies = [ + "cap-primitives", + "once_cell", + "rustix", + "winx", +] + [[package]] name = "cart_manager" version = "0.1.0" @@ -756,6 +836,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "cpufeatures" version = "0.2.5" @@ -765,6 +854,119 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-bforest" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c200df7d943cd2b8cb3a67f6a56781c63849f122d74deff24d1767c3918b0bdc" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f365623f4c3d576f47f11868568d0c90e18ac169497a9ed73c433fe2d3f9f2fb" +dependencies = [ + "arrayvec", + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-egraph", + "cranelift-entity", + "cranelift-isle", + "gimli", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbaf79f8ae63bd86dc40a04417a7cc1691a217f6db204438026c164679b4694" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "587db55845c943d8211e9c7198a977fa6686b44f18df15f31cec9a12fcf5dda8" + +[[package]] +name = "cranelift-egraph" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6dccc0b16b7b8c1278162e436beebb35f3d321743b639d2b578138d630f43e" +dependencies = [ + "cranelift-entity", + "fxhash", + "hashbrown 0.12.3", + "indexmap", + "log", + "smallvec", +] + +[[package]] +name = "cranelift-entity" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b062935d2c6dba87387d2ac163eb9c54967ed6143c3136fffaba8acb5eaa9e" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476ea81fe736b858d2d2c53b9d9fd28082589f57ebe4e1654a68af7359800a0c" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c50a465703c15d3d913f6b0db8320c4e92c940f0f0cad874c7fcf5aecc066c0" + +[[package]] +name = "cranelift-native" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d9e0d1382584b8d454ec12c86fd562b64ccd454c1199846c1b7d158db9ed38" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f54959195c47437544a1a4d2602381949a12918e0179bcc82d909cc34cf08dd" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + [[package]] name = "crc" version = "3.0.0" @@ -1153,6 +1355,27 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -1191,6 +1414,12 @@ dependencies = [ "uuid 0.8.2", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fastrand" version = "1.8.0" @@ -1340,6 +1569,17 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-set-times" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a267b6a9304912e018610d53fe07115d8b530b160e85db4d2d3a59f3ddde1aec" +dependencies = [ + "io-lifetimes", + "rustix", + "windows-sys 0.36.1", +] + [[package]] name = "fs_manager" version = "0.1.0" @@ -1489,6 +1729,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.6" @@ -1512,6 +1761,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + [[package]] name = "git2" version = "0.14.4" @@ -1671,6 +1931,15 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -1890,6 +2159,26 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "io-extras" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5d8c2ab5becd8720e30fd25f8fa5500d8dc3fceadd8378f05859bd7b46fc49" +dependencies = [ + "io-lifetimes", + "windows-sys 0.36.1", +] + +[[package]] +name = "io-lifetimes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" +dependencies = [ + "libc", + "windows-sys 0.42.0", +] + [[package]] name = "iovec" version = "0.1.4" @@ -1911,6 +2200,18 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f84f1612606f3753f205a4e9a2efd6fe5b4c573a6269b2cc6c3003d44a0d127" +[[package]] +name = "is-terminal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d508111813f9af3afd2f92758f77e4ed2cc9371b642112c6a48d22eb73105c5" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes", + "rustix", + "windows-sys 0.36.1", +] + [[package]] name = "itertools" version = "0.10.5" @@ -2003,6 +2304,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" version = "0.2.137" @@ -2057,6 +2364,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" + [[package]] name = "local-channel" version = "0.1.3" @@ -2104,6 +2417,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "matchers" version = "0.1.0" @@ -2119,6 +2441,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + [[package]] name = "md-5" version = "0.10.5" @@ -2365,10 +2693,22 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", ] +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "crc32fast", + "hashbrown 0.12.3", + "indexmap", + "memchr", +] + [[package]] name = "once_cell" version = "1.16.0" @@ -2639,6 +2979,44 @@ dependencies = [ "thiserror", ] +[[package]] +name = "payment_adapter" +version = "0.1.0" +dependencies = [ + "config", + "model", + "wasmtime-api", + "wasmtime-wasi", +] + +[[package]] +name = "payment_manager" +version = "0.1.0" +dependencies = [ + "channels", + "chrono", + "config", + "db-utils", + "fake", + "gumdrop", + "model", + "opentelemetry 0.17.0", + "opentelemetry-jaeger", + "rumqttc", + "serde", + "sqlx", + "sqlx-core", + "tarpc", + "testx", + "thiserror", + "tokio", + "tracing", + "tracing-opentelemetry", + "tracing-subscriber", + "uuid 1.2.2", + "wasmtime", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -2792,6 +3170,15 @@ dependencies = [ "trackable 0.2.24", ] +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + [[package]] name = "ptr_meta" version = "0.1.4" @@ -3038,6 +3425,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regalloc2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + [[package]] name = "regex" version = "1.7.0" @@ -3206,6 +3605,12 @@ dependencies = [ "rust_decimal", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -3230,6 +3635,22 @@ dependencies = [ "semver 1.0.14", ] +[[package]] +name = "rustix" +version = "0.35.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "itoa", + "libc", + "linux-raw-sys", + "once_cell", + "windows-sys 0.42.0", +] + [[package]] name = "rustls" version = "0.20.7" @@ -3546,6 +3967,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shellexpand" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" +dependencies = [ + "dirs", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -3579,6 +4009,12 @@ dependencies = [ "autocfg 1.1.0", ] +[[package]] +name = "slice-group-by" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" + [[package]] name = "slog" version = "2.7.0" @@ -3748,6 +4184,12 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -3840,6 +4282,28 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-interface" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92adbaf536f5aff6986e1e62ba36cee72b1718c5153eee08b9e728ddde3f6029" +dependencies = [ + "atty", + "bitflags", + "cap-fs-ext", + "cap-std", + "io-lifetimes", + "rustix", + "windows-sys 0.36.1", + "winx", +] + +[[package]] +name = "target-lexicon" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" + [[package]] name = "tarpc" version = "0.31.0" @@ -4416,9 +4880,9 @@ dependencies = [ [[package]] name = "validator" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f07b0a1390e01c0fc35ebb26b28ced33c9a3808f7f9fbe94d3cc01e233bfeed5" +checksum = "32ad5bf234c7d3ad1042e5252b7eddb2c4669ee23f32c7dd0e9b7705f07ef591" dependencies = [ "idna 0.2.3", "lazy_static", @@ -4475,6 +4939,49 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi-cap-std-sync" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe15d7e9ee5bb76cb64b9c29ff00c62642e8552e7f2a8b4758897b0a89a582d" +dependencies = [ + "anyhow", + "async-trait", + "cap-fs-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "io-extras", + "io-lifetimes", + "is-terminal", + "once_cell", + "rustix", + "system-interface", + "tracing", + "wasi-common", + "windows-sys 0.36.1", +] + +[[package]] +name = "wasi-common" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e0ef82a2154554def1a220afd48f95cb0f22be343b16930e8957113bd3d967" +dependencies = [ + "anyhow", + "bitflags", + "cap-rand", + "cap-std", + "io-extras", + "rustix", + "thiserror", + "tracing", + "wasmtime", + "wiggle", + "windows-sys 0.36.1", +] + [[package]] name = "wasm-bindgen" version = "0.2.83" @@ -4543,6 +5050,199 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +[[package]] +name = "wasmparser" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a4460aa3e271fa180b6a5d003e728f3963fb30e3ba0fa7c9634caa06049328" +dependencies = [ + "indexmap", +] + +[[package]] +name = "wasmtime" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad9bd12d0823195f6c833f340d8d1df39e2bbf40f5767416560ca7476b97e47" +dependencies = [ + "anyhow", + "bincode", + "cfg-if 1.0.0", + "indexmap", + "libc", + "log", + "object", + "once_cell", + "paste", + "psm", + "rayon", + "serde", + "target-lexicon", + "wasmparser", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", + "windows-sys 0.36.1", +] + +[[package]] +name = "wasmtime-api" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6db9127057c8be35bf5e4dd3d124b99ffe65db4b5631e701a115e3fb4d92590" + +[[package]] +name = "wasmtime-asm-macros" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6694b753be856b36d47744cdf2bd525bac53d0de5981132d5430bb62c496e4" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "wasmtime-cranelift" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c55d30708ebc24b6fa2a247807821642967487388845c7fc5320fef1010abe8" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01be016d65ec9200a2d4efbc2ca983bbb7264332e49c11179aaf7587e57d854d" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap", + "log", + "object", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d36042d7962fa1b2a6bfb96d3b33e2283138e7396bc29b2c6970f2a1e80a0ed" +dependencies = [ + "addr2line", + "anyhow", + "bincode", + "cfg-if 1.0.0", + "cpp_demangle", + "gimli", + "log", + "object", + "rustc-demangle", + "serde", + "target-lexicon", + "thiserror", + "wasmtime-environ", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.36.1", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4511b8abbdbaf3e9aaa4044ead8bd31b70e2da5e43e2cb91605f871ca23d56" +dependencies = [ + "once_cell", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb7b3e58024d8d395dfc4efbe2a58360a1998565b118b0342b3cf62a4084bde" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "windows-sys 0.36.1", +] + +[[package]] +name = "wasmtime-runtime" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4034f371135e9e2e81430dda14f6f5a49a222c6557ec4f65301edc093b216d38" +dependencies = [ + "anyhow", + "cc", + "cfg-if 1.0.0", + "indexmap", + "libc", + "log", + "mach", + "memoffset 0.6.5", + "paste", + "rand 0.8.5", + "rustix", + "thiserror", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-jit-debug", + "windows-sys 0.36.1", +] + +[[package]] +name = "wasmtime-types" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a770de14a3b5676dfd8a3c06bcab829d9cb58b113911634f3ec3b6960b1d79e3" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wasmtime-wasi" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648d6b4360af358bf2a0688ef7e35d4b413f7185257bf8de6a58f09fb4d7eca1" +dependencies = [ + "anyhow", + "wasi-cap-std-sync", + "wasi-common", + "wasmtime", + "wiggle", +] + +[[package]] +name = "wast" +version = "35.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" +dependencies = [ + "leb128", +] + [[package]] name = "web" version = "0.1.0" @@ -4613,6 +5313,48 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wiggle" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff29f3353b12c949adc6ad6d89edd87f3fa227b1ee1a26f437ae5e9dfe42ba5f" +dependencies = [ + "anyhow", + "async-trait", + "bitflags", + "thiserror", + "tracing", + "wasmtime", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03743b2f04849564d6a2cd6ba32861d93f2d46baddad449473ec399d58b78e3" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "shellexpand", + "syn", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "544319bbf95f2e0fc2c410b2098aff28a885e6cf59d02a67f5647eec1679d4ec" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wiggle-generate", +] + [[package]] name = "winapi" version = "0.2.8" @@ -4765,6 +5507,29 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "winx" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b01e010390eb263a4518c8cebf86cb67469d1511c00b749a47b64c39e8054d" +dependencies = [ + "bitflags", + "io-lifetimes", + "windows-sys 0.36.1", +] + +[[package]] +name = "witx" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" +dependencies = [ + "anyhow", + "log", + "thiserror", + "wast", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 1a269b8..8702355 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,12 +12,13 @@ members = [ # "crates/database_manager", "crates/email_manager", "crates/order_manager", -# "crates/payment_manager", + "crates/payment_manager", "crates/search_manager", "crates/stock_manager", "crates/token_manager", "crates/fs_manager", "crates/lang_provider", + "crates/payment_adapter", # artifacts # "crates/db-seed", # "crates/api", diff --git a/crates/channels/Cargo.toml b/crates/channels/Cargo.toml index 7ab045e..be7c2ef 100644 --- a/crates/channels/Cargo.toml +++ b/crates/channels/Cargo.toml @@ -10,7 +10,8 @@ emails = [] search = [] stocks = [] orders = [] -default = ['accounts', 'carts', 'emails', 'search', 'stocks', 'orders'] +payments = [] +default = ['accounts', 'carts', 'emails', 'search', 'stocks', 'orders', 'payments'] [dependencies] bincode = { version = "*" } diff --git a/crates/channels/src/lib.rs b/crates/channels/src/lib.rs index 3b31e3b..458327a 100644 --- a/crates/channels/src/lib.rs +++ b/crates/channels/src/lib.rs @@ -11,6 +11,8 @@ pub mod emails; pub mod mqtt; #[cfg(feature = "orders")] pub mod orders; +#[cfg(feature = "payments")] +pub mod payments; pub mod rpc; #[cfg(feature = "search")] pub mod search; diff --git a/crates/channels/src/orders.rs b/crates/channels/src/orders.rs index 6b877c6..9108081 100644 --- a/crates/channels/src/orders.rs +++ b/crates/channels/src/orders.rs @@ -13,6 +13,8 @@ pub enum Error { CreateOrder, #[error("Failed to create order item")] CreateOrderItem, + #[error("Failed to create order address")] + CreateOrderAddress, } #[derive(Debug, Copy, Clone)] @@ -55,8 +57,8 @@ impl AsyncClient { pub mod create_order { use model::{ - AccountId, Order, OrderAddressId, OrderItem, ProductId, Quantity, QuantityUnit, - ShoppingCartId, + AccountId, City, Country, Email, Name, Order, OrderItem, Phone, ProductId, Quantity, + QuantityUnit, ShoppingCartId, Street, Zip, }; pub use super::Error; @@ -68,13 +70,24 @@ pub mod create_order { pub quantity_unit: QuantityUnit, } + #[derive(Debug, serde::Serialize, serde::Deserialize)] + pub struct AddressInput { + pub name: Name, + pub email: Email, + pub street: Street, + pub city: City, + pub country: Country, + pub zip: Zip, + pub phone: Phone, + } + #[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct Input { pub buyer_id: AccountId, pub items: Vec, pub shopping_cart_id: Option, pub checkout_notes: Option, - pub delivery_address_id: OrderAddressId, + pub address: AddressInput, } #[derive(Debug, serde::Serialize, serde::Deserialize)] @@ -119,7 +132,7 @@ pub mod mqtt { use config::SharedAppConfig; use rumqttc::EventLoop; - use crate::orders::CLIENT_NAME; + use super::CLIENT_NAME; use crate::AsyncClient; pub fn create_client(config: SharedAppConfig) -> (AsyncClient, EventLoop) { diff --git a/crates/channels/src/payments.rs b/crates/channels/src/payments.rs new file mode 100644 index 0000000..32a8e79 --- /dev/null +++ b/crates/channels/src/payments.rs @@ -0,0 +1,95 @@ +// use rumqttc::QoS; + +// use crate::AsyncClient; + +pub static CLIENT_NAME: &str = "payments"; + +#[derive(Debug, thiserror::Error, serde::Serialize, serde::Deserialize)] +pub enum Error { + #[error("Something went wrong")] + InternalServerError, +} + +#[derive(Debug, Copy, Clone)] +pub enum Topic { + Succeed, +} + +impl Topic { + pub fn to_str(self) -> &'static str { + match self { + Topic::Succeed => "payments/succeed", + } + } +} + +impl Into for Topic { + fn into(self) -> String { + self.to_str().into() + } +} + +impl<'s> PartialEq<&'s str> for Topic { + fn eq(&self, other: &&'s str) -> bool { + self.to_str() == *other + } +} + +impl PartialEq for Topic { + fn eq(&self, other: &String) -> bool { + self.to_str() == other.as_str() + } +} + +pub mod start_payment { + use super::Error; + + #[derive(Debug, serde::Serialize, serde::Deserialize)] + pub struct Input {} + + #[derive(Debug, serde::Serialize, serde::Deserialize)] + pub struct Details {} + + pub type Output = Result; +} + +pub mod rpc { + use config::SharedAppConfig; + + use crate::payments::start_payment; + + #[tarpc::service] + pub trait Payments { + async fn start_payment(input: start_payment::Input) -> start_payment::Output; + } + + pub async fn create_client(config: SharedAppConfig) -> PaymentsClient { + use tarpc::client; + use tarpc::tokio_serde::formats::Bincode; + + let l = config.lock(); + let addr = l.orders_manager().rpc_addr(); + + let transport = tarpc::serde_transport::tcp::connect(addr, Bincode::default); + + let client = PaymentsClient::new( + client::Config::default(), + transport.await.expect("Failed to connect to server"), + ) + .spawn(); + + client + } +} + +pub mod mqtt { + use config::SharedAppConfig; + use rumqttc::EventLoop; + + use super::CLIENT_NAME; + use crate::AsyncClient; + + pub fn create_client(config: SharedAppConfig) -> (AsyncClient, EventLoop) { + crate::mqtt::create_client(CLIENT_NAME, config.lock().stocks_manager().mqtt_addr()) + } +} diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 56e54b4..2ef50e4 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; +use std::path::{Path, PathBuf}; use std::sync::Arc; use parking_lot::Mutex; @@ -42,83 +44,6 @@ impl std::ops::DerefMut for SharedAppConfig { } } -#[derive(Serialize, Deserialize, Default)] -pub struct PaymentConfig { - payu_client_id: Option, - payu_client_secret: Option, - /// Create payu account and copy here merchant id - payu_client_merchant_id: Option, - currency: Option, - /// Allow customers to pay on site - #[serde(default)] - optional_payment: bool, -} - -impl Example for PaymentConfig { - fn example() -> Self { - Self { - payu_client_id: Some(pay_u::ClientId::new( - "Create payu account and copy here client_id", - )), - payu_client_secret: Some(pay_u::ClientSecret::new( - "Create payu account and copy here client_secret", - )), - /// Create payu account and copy here merchant id - payu_client_merchant_id: Some(pay_u::MerchantPosId::from(0)), - /// Allow customers to pay on site - currency: None, - optional_payment: true, - } - } -} - -impl PaymentConfig { - pub fn optional_payment(&self) -> bool { - self.optional_payment - } - - pub fn payu_client_id(&self) -> pay_u::ClientId { - self.payu_client_id - .as_ref() - .cloned() - .or_else(|| std::env::var("PAYU_CLIENT_ID").ok().map(pay_u::ClientId)) - .expect("payment config payu_client_id nor PAYU_CLIENT_ID env was given") - } - - pub fn payu_client_secret(&self) -> pay_u::ClientSecret { - self.payu_client_secret - .as_ref() - .cloned() - .or_else(|| { - std::env::var("PAYU_CLIENT_SECRET") - .ok() - .map(pay_u::ClientSecret) - }) - .expect("payment config payu_client_secret nor PAYU_CLIENT_SECRET env was given") - } - - pub fn payu_client_merchant_id(&self) -> pay_u::MerchantPosId { - self.payu_client_merchant_id - .or_else(|| { - std::env::var("PAYU_CLIENT_MERCHANT_ID") - .ok() - .and_then(|s| s.parse::().ok()) - .map(pay_u::MerchantPosId) - }) - .expect( - "payment config payu_client_merchant_id nor PAYU_CLIENT_MERCHANT_ID env was given", - ) - } - - pub fn currency(&self) -> String { - self.currency - .as_ref() - .cloned() - .or_else(|| std::env::var("CURRENCY").ok()) - .unwrap_or_else(|| "PLN".into()) - } -} - #[derive(Serialize, Deserialize, Default)] pub struct WebConfig { /// Host name @@ -584,6 +509,121 @@ impl OrderConfig { } } +#[derive(Serialize, Deserialize, Default)] +pub struct PaymentProviderConfig { + pub client_id: Option, + pub client_secret: Option, + pub merchant_id: Option, + #[serde(flatten)] + pub custom: HashMap, +} + +#[derive(Serialize, Deserialize, Default)] +pub struct PaymentConfig { + pub rpc_port: u16, + pub rpc_bind: String, + pub mqtt_port: u16, + pub mqtt_bind: String, + pub adapters_path: Option, + currency: Option, + /// Allow customers to pay on site + #[serde(default)] + optional_payment: bool, + #[serde(flatten)] + providers: HashMap, +} + +impl Example for PaymentConfig { + fn example() -> Self { + Self { + rpc_port: 19335, + rpc_bind: "0.0.0.0".into(), + mqtt_port: 1888, + mqtt_bind: "0.0.0.0".into(), + adapters_path: Some(Path::new("./adapters").to_path_buf()), + currency: None, + /// Allow customers to pay on site + optional_payment: true, + providers: { + let mut h = HashMap::with_capacity(2); + h.insert( + "pay_u".into(), + PaymentProviderConfig { + client_id: Some("Create payu account and copy here client_id".into()), + client_secret: Some( + "Create payu account and copy here client_secret".into(), + ), + merchant_id: Some("Create payu account and copy here merchant id".into()), + custom: { + let mut h = HashMap::with_capacity(2); + h.insert("example1".into(), "custom value1".into()); + h.insert("example2".into(), "custom value2".into()); + h + }, + }, + ); + h + }, + } + } +} + +impl PaymentConfig { + pub fn rpc_addr(&self) -> (&str, u16) { + (&self.rpc_bind, self.rpc_port) + } + + pub fn mqtt_addr(&self) -> (&str, u16) { + (&self.mqtt_bind, self.mqtt_port) + } + + pub fn optional_payment(&self) -> bool { + self.optional_payment + } + // + // pub fn payu_client_id(&self) -> pay_u::ClientId { + // self.payu_client_id + // .as_ref() + // .cloned() + // .or_else(|| + // std::env::var("PAYU_CLIENT_ID").ok().map(pay_u::ClientId)) + // .expect("payment config payu_client_id nor PAYU_CLIENT_ID env was + // given") } + // + // pub fn payu_client_secret(&self) -> pay_u::ClientSecret { + // self.payu_client_secret + // .as_ref() + // .cloned() + // .or_else(|| { + // std::env::var("PAYU_CLIENT_SECRET") + // .ok() + // .map(pay_u::ClientSecret) + // }) + // .expect("payment config payu_client_secret nor PAYU_CLIENT_SECRET env + // was given") } + // + // pub fn payu_client_merchant_id(&self) -> pay_u::MerchantPosId { + // self.payu_client_merchant_id + // .or_else(|| { + // std::env::var("PAYU_CLIENT_MERCHANT_ID") + // .ok() + // .and_then(|s| s.parse::().ok()) + // .map(pay_u::MerchantPosId) + // }) + // .expect( + // "payment config payu_client_merchant_id nor + // PAYU_CLIENT_MERCHANT_ID env was given", ) + // } + + pub fn currency(&self) -> String { + self.currency + .as_ref() + .cloned() + .or_else(|| std::env::var("CURRENCY").ok()) + .unwrap_or_else(|| "PLN".into()) + } +} + #[derive(Serialize, Deserialize)] pub struct AppConfig { #[serde(default)] diff --git a/crates/model/Cargo.toml b/crates/model/Cargo.toml index 94d5c0f..7987189 100644 --- a/crates/model/Cargo.toml +++ b/crates/model/Cargo.toml @@ -7,6 +7,15 @@ edition = "2021" db = ["sqlx", "sqlx-core"] dummy = ["fake", "rand"] +accounts = [] +carts = [] +emails = [] +search = [] +stocks = [] +orders = [] +payments = [] +default = ['accounts', 'carts', 'emails', 'search', 'stocks', 'orders', 'payments'] + [dependencies] argon2 = { version = "0.4", features = ["parallel", "password-hash"] } chrono = { version = "0.4", features = ["serde"] } @@ -21,4 +30,4 @@ sqlx-core = { version = "0.6.2", features = [], optional = true } thiserror = { version = "1.0.31" } tracing = { version = "0.1.34" } uuid = { version = "1.2.1", features = ["serde"] } -validator = { version = "0.15.0" } +validator = { version = "0.16.0" } diff --git a/crates/order_manager/migrations/202204131841_init.sql b/crates/order_manager/migrations/202204131841_init.sql index d267b59..7082cb1 100644 --- a/crates/order_manager/migrations/202204131841_init.sql +++ b/crates/order_manager/migrations/202204131841_init.sql @@ -35,7 +35,7 @@ CREATE TABLE orders CREATE TABLE order_addresses ( id serial NOT NULL PRIMARY KEY, - name text NOT NULL, + "name" text NOT NULL, email text NOT NULL, street text NOT NULL, city text NOT NULL, diff --git a/crates/order_manager/src/actions/order.rs b/crates/order_manager/src/actions/order.rs index 2afbdba..da9eef5 100644 --- a/crates/order_manager/src/actions/order.rs +++ b/crates/order_manager/src/actions/order.rs @@ -4,7 +4,7 @@ use config::SharedAppConfig; use db_utils::{begin_t, dbm_run, PgT}; use model::OrderStatus; -use crate::db::{CreateOrder, CreateOrderItem, Database}; +use crate::db::{CreateAddress, CreateOrder, CreateOrderItem, Database}; pub async fn create_order( input: create_order::Input, @@ -36,11 +36,22 @@ pub async fn inner_create_order( input: create_order::Input, t: &mut PgT<'_>, ) -> create_order::Output { + let dbm = CreateAddress { + name: input.address.name, + email: input.address.email, + street: input.address.street, + city: input.address.city, + country: input.address.country, + zip: input.address.zip, + phone: input.address.phone, + }; + let address = dbm_run!(dbm, &mut *t, Error::CreateOrderAddress); + let dbm = CreateOrder { buyer_id: input.buyer_id, shopping_cart_id: input.shopping_cart_id, checkout_notes: input.checkout_notes, - delivery_address_id: input.delivery_address_id, + delivery_address_id: address.id, }; let order = dbm_run!(dbm, &mut *t, Error::CreateOrder); @@ -61,7 +72,7 @@ pub async fn inner_create_order( Ok(create_order::Details { order, order_items }) } -pub fn change(current: OrderStatus, next: OrderStatus) -> Option { +pub fn _change(current: OrderStatus, next: OrderStatus) -> Option { match (current, next) { // paying (OrderStatus::Confirmed, OrderStatus::Payed) => Some(OrderStatus::Payed), diff --git a/crates/order_manager/src/db/order.rs b/crates/order_manager/src/db/order.rs index da66582..e12dd60 100644 --- a/crates/order_manager/src/db/order.rs +++ b/crates/order_manager/src/db/order.rs @@ -17,6 +17,7 @@ pub struct CreateOrder { } impl CreateOrder { + #[tracing::instrument] pub async fn run(self, t: &mut sqlx::Transaction<'_, sqlx::Postgres>) -> Result { sqlx::query_as( r#" diff --git a/crates/order_manager/src/db/order_address.rs b/crates/order_manager/src/db/order_address.rs index e69de29..2ee5c21 100644 --- a/crates/order_manager/src/db/order_address.rs +++ b/crates/order_manager/src/db/order_address.rs @@ -0,0 +1,156 @@ +use db_utils::PgT; +use model::{ + City, Country, Email, Name, OrderAddress, OrderAddressId, OrderId, Phone, Street, Zip, +}; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Failed to load address for order {0:?}")] + AddressForOrder(OrderId), + #[error("Failed to create address for order")] + Create, + #[error("Failed to update address {address_id:?} for order {order_id:?}")] + Update { + order_id: OrderId, + address_id: OrderAddressId, + }, +} + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub struct AddressForOrder { + pub order_id: OrderId, +} + +impl AddressForOrder { + #[tracing::instrument] + pub async fn run(self, t: &mut PgT<'_>) -> Result { + sqlx::query_as( + r#" +SELECT a.id, + a.name, + a.email, + a.street, + a.city, + a.country, + a.zip, + a.phone +FROM order_addresses a +IINER JOIN orders o ON orders.address_id = id +WHERE o.id = $1 +LIMIT 1 + "#, + ) + .bind(self.order_id) + .fetch_one(t) + .await + .map_err(|e| { + tracing::error!("{}", e); + Error::AddressForOrder(self.order_id) + }) + } +} + +#[derive(Debug)] +pub struct CreateAddress { + pub name: Name, + pub email: Email, + pub street: Street, + pub city: City, + pub country: Country, + pub zip: Zip, + pub phone: Phone, +} + +impl CreateAddress { + #[tracing::instrument] + pub async fn run(self, t: &mut PgT<'_>) -> Result { + sqlx::query_as( + r#" +INSERT INTO order_addresses ( + name, + email, + street, + city, + country, + zip, + phone +) +VALUES ($1, $2, $3, $4, $5, $6, $7) +RETURNING id, + name, + email, + street, + city, + country, + zip, + phone + "#, + ) + .bind(self.name) + .bind(self.email) + .bind(self.street) + .bind(self.city) + .bind(self.country) + .bind(self.zip) + .bind(self.phone) + .fetch_one(t) + .await + .map_err(|e| { + tracing::error!("{}", e); + Error::Create + }) + } +} + +#[derive(Debug)] +pub struct UpdateAddress { + pub order_id: OrderId, + pub address_id: OrderAddressId, + pub name: Name, + pub email: Email, + pub street: Street, + pub city: City, + pub country: Country, + pub zip: Zip, + pub phone: Phone, +} + +impl UpdateAddress { + #[tracing::instrument] + pub async fn run(self, t: &mut PgT<'_>) -> Result { + sqlx::query_as( + r#" +UPDATE order_addresses +SET name = $2, email = $3, street = $4, city = $5, country = $6, zip = $7, phone = $8 +WHERE id = $1 +RETURNING id, + name, + email, + street, + city, + country, + zip, + phone + "#, + ) + .bind(self.address_id) + .bind(self.name) + .bind(self.email) + .bind(self.street) + .bind(self.city) + .bind(self.country) + .bind(self.zip) + .bind(self.phone) + .fetch_one(t) + .await + .map_err(|e| { + tracing::error!("{}", e); + Error::Update { + order_id: self.order_id, + address_id: self.address_id, + } + }) + } +} diff --git a/crates/order_manager/src/db/order_item.rs b/crates/order_manager/src/db/order_item.rs index e887683..42b0d14 100644 --- a/crates/order_manager/src/db/order_item.rs +++ b/crates/order_manager/src/db/order_item.rs @@ -17,6 +17,7 @@ pub struct CreateOrderItem { } impl CreateOrderItem { + #[tracing::instrument] pub async fn run(self, t: &mut sqlx::Transaction<'_, sqlx::Postgres>) -> Result { sqlx::query_as( r#" diff --git a/crates/order_manager/src/main.rs b/crates/order_manager/src/main.rs index 31801c4..0213972 100644 --- a/crates/order_manager/src/main.rs +++ b/crates/order_manager/src/main.rs @@ -4,6 +4,7 @@ mod actions; mod db; mod mqtt; mod rpc; +mod context; pub struct Opts {} diff --git a/crates/payment_adapter/Cargo.toml b/crates/payment_adapter/Cargo.toml new file mode 100644 index 0000000..2925e1e --- /dev/null +++ b/crates/payment_adapter/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "payment_adapter" +version = "0.1.0" +edition = "2021" + +[dependencies] +wasmtime-wasi = { version = "3.0.0" } +wasmtime-api = { version = "0.4.0" } +config = { path = "../config" } +model = { path = "../model" } diff --git a/crates/payment_adapter/src/lib.rs b/crates/payment_adapter/src/lib.rs new file mode 100644 index 0000000..2ceb842 --- /dev/null +++ b/crates/payment_adapter/src/lib.rs @@ -0,0 +1,48 @@ +use std::collections::HashMap; + +pub use config::PaymentProviderConfig; +use model::{Price, ProductId, Quantity, QuantityUnit}; + +#[derive(Debug)] +pub struct Buyer { + /// Required customer e-mail + pub email: String, + /// Required customer phone number + pub phone: String, + /// Required customer first name + pub first_name: String, + /// Required customer last name + pub last_name: String, + /// Required customer language + pub language: String, +} + +#[derive(Debug)] +pub struct Product { + pub id: ProductId, + pub name: String, + pub unit_price: Price, + pub quantity_unit: QuantityUnit, + pub quantity: Quantity, +} + +pub struct CreatePayment { + // pub client: PayUClient, + pub buyer: Buyer, + pub customer_ip: String, + pub currency: String, + pub description: String, + pub cart_products: Vec, + pub items: HashMap, + pub order_ext_id: String, + pub notify_uri: String, + pub continue_uri: String, +} + +pub trait PaymentAdapter { + fn name() -> &'static str; + + fn init(&mut self, config: &PaymentProviderConfig); + + fn create_payment(&self, msg: CreatePayment); +} diff --git a/crates/payment_manager/Cargo.toml b/crates/payment_manager/Cargo.toml index 5429ca0..7fdd445 100644 --- a/crates/payment_manager/Cargo.toml +++ b/crates/payment_manager/Cargo.toml @@ -3,22 +3,31 @@ name = "payment_manager" version = "0.1.0" edition = "2021" +[[bin]] +name = "payment-manager" +path = "./src/main.rs" + [dependencies] -actix = { version = "0.13", features = [] } -actix-rt = { version = "2.7", features = [] } +channels = { path = "../channels" } chrono = { version = "0.4", features = ["serde"] } config = { path = "../config" } -database_manager = { path = "../database_manager" } -derive_more = { version = "0.99", features = [] } +db-utils = { path = "../db-utils" } model = { path = "../model", features = ["db"] } -parking_lot = { version = "0.12", features = [] } -pay_u = { version = '0.1', features = ["single-client"] } -pretty_env_logger = { version = "0.4", features = [] } +opentelemetry = { version = "0.17.0" } +opentelemetry-jaeger = { version = "0.17.0" } rumqttc = { version = "*" } -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0.137", features = ["derive"] } +sqlx = { version = "0.6.2", features = ["migrate", "runtime-actix-rustls", "all-types", "postgres"] } +sqlx-core = { version = "0.6.2", features = [] } +tarpc = { version = "0.31.0", features = ["tokio1", "serde-transport-bincode", "serde-transport", "serde", "serde-transport-json", "tcp"] } thiserror = { version = "1.0.31" } -tracing = { version = "0.1.34" } -uuid = { version = "0.8", features = ["serde"] } +tokio = { version = "1.21.2", features = ['full'] } +tracing = { version = "0.1.6" } +tracing-opentelemetry = { version = "0.17.4" } +tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +uuid = { version = "1.2.1", features = ["serde"] } +wasmtime = { version = "3.0.0", default-features = false, features = ['cranelift', 'parallel-compilation', 'pooling-allocator'] } +gumdrop = { version = "0.8.1", features = [] } [dev-dependencies] fake = { version = "2.5.0" } diff --git a/crates/payment_manager/src/actions/mod.rs b/crates/payment_manager/src/actions/mod.rs new file mode 100644 index 0000000..99c2127 --- /dev/null +++ b/crates/payment_manager/src/actions/mod.rs @@ -0,0 +1,2 @@ +mod pay_u_adapter; +mod t_pay_adapter; diff --git a/crates/payment_manager/src/lib.rs b/crates/payment_manager/src/actions/pay_u_adapter.rs similarity index 55% rename from crates/payment_manager/src/lib.rs rename to crates/payment_manager/src/actions/pay_u_adapter.rs index 1ebd438..24e2f99 100644 --- a/crates/payment_manager/src/lib.rs +++ b/crates/payment_manager/src/actions/pay_u_adapter.rs @@ -1,68 +1,10 @@ -mod pay_u_adapter; -mod t_pay_adapter; - use std::collections::HashMap; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; -use actix::Addr; use config::SharedAppConfig; -use database_manager::{query_db, Database}; use model::{ AccountId, OrderId, OrderStatus, PaymentMethod, Price, ProductId, Quantity, QuantityUnit, }; -use parking_lot::Mutex; - -#[macro_export] -macro_rules! pay_async_handler { - ($msg: ty, $async: ident, $res: ty) => { - impl actix::Handler<$msg> for PaymentManager { - type Result = actix::ResponseActFuture>; - - fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result { - use actix::WrapFuture; - let client = self.client.clone(); - let db = self.db.clone(); - let config = self.config.clone(); - Box::pin(async { $async(msg, client, db, config).await }.into_actor(self)) - } - } - }; -} - -#[macro_export] -macro_rules! query_pay { - ($manager: expr, $msg: expr, default $fail: expr) => { - match $manager.send($msg).await { - Ok(Ok(r)) => r, - Ok(Err(e)) => { - tracing::error!("Payment {e}"); - $fail - } - Err(e) => { - tracing::error!("Payment {e:?}"); - $fail - } - } - }; - - ($manager: expr, $msg: expr, $fail: expr) => { - $crate::query_pay!($manager, $msg, $fail, $fail) - }; - - ($manager: expr, $msg: expr, $db_fail: expr, $act_fail: expr) => { - match $manager.send($msg).await { - Ok(Ok(r)) => r, - Ok(Err(e)) => { - tracing::error!("Payment {e}"); - return Err($db_fail); - } - Err(e) => { - tracing::error!("Payment {e:?}"); - return Err($act_fail); - } - } - }; -} pub type PayUClient = Arc>; @@ -84,101 +26,62 @@ pub type Result = std::result::Result; #[derive(Clone)] pub struct PaymentManager { client: PayUClient, - db: Addr, config: SharedAppConfig, } -impl PaymentManager { - pub async fn build(config: SharedAppConfig, db: Addr) -> Self { - let mut client = { - let l = config.lock(); - let p = l.payment(); - pay_u::Client::new( - p.payu_client_id(), - p.payu_client_secret(), - p.payu_client_merchant_id(), - ) - }; - client.authorize().await.unwrap_or_else(|e| { - tracing::error!("{e}"); - dbg!(e); - std::process::exit(1); - }); - Self { - client: Arc::new(Mutex::new(client)), - db, - config, - } - } -} - -impl actix::Actor for PaymentManager { - type Context = actix::Context; -} +// impl PaymentManager { +// pub async fn build(config: SharedAppConfig, db: Addr) -> Self { +// let mut client = { +// let l = config.lock(); +// let p = l.payment(); +// pay_u::Client::new( +// p.payu_client_id(), +// p.payu_client_secret(), +// p.payu_client_merchant_id(), +// ) +// }; +// client.authorize().await.unwrap_or_else(|e| { +// tracing::error!("{e}"); +// dbg!(e); +// std::process::exit(1); +// }); +// Self { +// client: Arc::new(Mutex::new(client)), +// db, +// config, +// } +// } +// } +// +// impl actix::Actor for PaymentManager { +// type Context = actix::Context; +// } pub struct PaymentResult { pub redirect_uri: String, pub payu_order_id: String, } -#[derive(Debug)] -pub struct Buyer { - /// Required customer e-mail - pub email: String, - /// Required customer phone number - pub phone: String, - /// Required customer first name - pub first_name: String, - /// Required customer last name - pub last_name: String, - /// Required customer language - pub language: String, -} - -impl From for pay_u::Buyer { - fn from(b: Buyer) -> Self { - pay_u::Buyer::new(b.email, b.phone, b.first_name, b.last_name, b.language) - } -} - -#[derive(Debug)] -pub struct Product { - pub id: ProductId, - pub name: String, - pub unit_price: Price, - pub quantity_unit: QuantityUnit, - pub quantity: Quantity, -} - -impl From for pay_u::Product { - fn from(p: Product) -> Self { - pay_u::Product::new(p.name, **p.unit_price, **p.quantity as u32) - } -} - pub struct CreatePaymentResult { pub order: model::Order, pub items: Vec, pub redirect_uri: String, } -#[derive(Debug, actix::Message)] -#[rtype(result = "Result")] +#[derive(Debug)] pub struct RequestPayment { pub currency: String, - pub buyer: Buyer, + pub buyer: model::Buyer, pub customer_ip: String, pub buyer_id: AccountId, pub payment_method: PaymentMethod, pub db_order_id: OrderId, } -pay_async_handler!(RequestPayment, request_payment, CreatePaymentResult); - -pub(crate) async fn request_payment( +pub async fn request_payment( msg: RequestPayment, client: PayUClient, - db: Addr, + // db: Addr, config: SharedAppConfig, ) -> Result { let db_order: model::Order = query_db!( @@ -236,7 +139,7 @@ pub(crate) async fn request_payment( let redirect_uri = match msg.payment_method { PaymentMethod::PayU => { - let (redirect_uri, ext_order_id) = pay_u_adapter::CreatePayment { + let (redirect_uri, ext_order_id) = crate::pay_u_adapter::CreatePayment { client, buyer: msg.buyer, customer_ip: msg.customer_ip, @@ -283,18 +186,14 @@ pub(crate) async fn request_payment( #[serde(transparent)] pub struct PaymentNotification(pay_u::notify::StatusUpdate); -#[derive(Debug, actix::Message)] -#[rtype(result = "Result<()>")] pub struct UpdatePayment { pub notification: PaymentNotification, } -pay_async_handler!(UpdatePayment, update_payment, ()); - -pub(crate) async fn update_payment( +pub async fn payment_notification( msg: UpdatePayment, _client: PayUClient, - db: Addr, + // db: Addr, _config: SharedAppConfig, ) -> Result<()> { let status = msg.notification.0.status(); @@ -308,12 +207,12 @@ pub(crate) async fn update_payment( pay_u::PaymentStatus::Completed => OrderStatus::Payed, pay_u::PaymentStatus::Canceled => OrderStatus::Cancelled, }; - let _ = db - .send(database_manager::UpdateOrderByExt { - status, - order_ext_id, - }) - .await; + // let _ = db + // .send(database_manager::UpdateOrderByExt { + // status, + // order_ext_id, + // }) + // .await; Ok(()) } @@ -327,11 +226,11 @@ mod tests { impl config::UpdateConfig for NoOpts {} - #[actix::test] + #[tokio::test] async fn create() { - testx::db!(config, db); - let db = db.start(); - - let _manager = PaymentManager::build(config, db).await; + // testx::db!(config, db); + // let db = db.start(); + // + // let _manager = PaymentManager::build(config, db).await; } } diff --git a/crates/payment_manager/src/actions/t_pay_adapter.rs b/crates/payment_manager/src/actions/t_pay_adapter.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/payment_manager/src/context.rs b/crates/payment_manager/src/context.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/payment_manager/src/db.rs b/crates/payment_manager/src/db.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/payment_manager/src/main.rs b/crates/payment_manager/src/main.rs new file mode 100644 index 0000000..5b8ba80 --- /dev/null +++ b/crates/payment_manager/src/main.rs @@ -0,0 +1,53 @@ +use std::fs::read_dir; +use std::path::PathBuf; + +use config::{AppConfig, UpdateConfig}; + +// mod actions; +// mod context; +// mod db; +// mod mqtt; +// pub mod pay_u_adapter; +// mod rpc; +// pub mod t_pay_adapter; + +#[derive(gumdrop::Options)] +pub struct Opts { + pub adapters_path: Option, +} + +impl UpdateConfig for Opts { + fn update_config(&self, config: &mut AppConfig) { + if let Some(path) = self.adapters_path.clone() { + config.payment_mut().adapters_path = Some(path); + } + } +} + +#[tokio::main] +async fn main() { + let opts: Opts = gumdrop::parse_args_default_or_exit(); + + let config = config::default_load(&opts); + + let engine = wasmtime::Engine::default(); + + { + let adapters_path = config.lock().payment().adapters_path.clone(); + let adapters = adapters_path.unwrap_or_else(|| panic!("No payment adapters path provided")); + let dir = read_dir(&adapters).unwrap_or_else(|e| { + panic!( + "Failed to load payment adapters at path {:?}. {}", + adapters, e + ) + }); + for file in dir.filter_map(|r| r.map(|r| r.path()).ok()) { + wasmtime::Module::from_file(&engine, file).unwrap(); + } + } + + // let db = db::Database::build(config.clone()).await; + + // let mqtt_client = mqtt::start(config.clone(), db.clone()).await; + // rpc::start(config, db, mqtt_client).await; +} diff --git a/crates/payment_manager/src/mqtt.rs b/crates/payment_manager/src/mqtt.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/payment_manager/src/pay_u_adapter/mod.rs b/crates/payment_manager/src/pay_u_adapter/mod.rs index 8d266c9..aca4543 100644 --- a/crates/payment_manager/src/pay_u_adapter/mod.rs +++ b/crates/payment_manager/src/pay_u_adapter/mod.rs @@ -2,7 +2,47 @@ use std::collections::HashMap; use model::*; -use crate::{Buyer, Error, PayUClient, Result}; +// use crate::{Buyer, Error, PayUClient, Result}; + +#[derive(Debug, thiserror::Error)] +pub enum Error {} + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub struct Buyer { + /// Required customer e-mail + pub email: String, + /// Required customer phone number + pub phone: String, + /// Required customer first name + pub first_name: String, + /// Required customer last name + pub last_name: String, + /// Required customer language + pub language: String, +} + +impl From for pay_u::Buyer { + fn from(b: Buyer) -> Self { + pay_u::Buyer::new(b.email, b.phone, b.first_name, b.last_name, b.language) + } +} + +#[derive(Debug)] +pub struct Product { + pub id: ProductId, + pub name: String, + pub unit_price: Price, + pub quantity_unit: QuantityUnit, + pub quantity: Quantity, +} + +impl From for pay_u::Product { + fn from(p: Product) -> Self { + pay_u::Product::new(p.name, **p.unit_price, **p.quantity as u32) + } +} pub struct CreatePayment { pub client: PayUClient, @@ -11,7 +51,7 @@ pub struct CreatePayment { pub currency: String, pub description: String, pub cart_products: Vec, - pub items: HashMap, + pub items: HashMap, pub order_ext_id: String, pub notify_uri: String, pub continue_uri: String, diff --git a/crates/payment_manager/src/rpc.rs b/crates/payment_manager/src/rpc.rs new file mode 100644 index 0000000..e69de29