From 0c113831ef08c4ac7dd05bed126fcdf985913016 Mon Sep 17 00:00:00 2001 From: Priec Date: Sat, 18 Jul 2026 15:20:32 +0200 Subject: [PATCH] moving ECB to a separate proto file --- Cargo.lock | 299 +++++++++++++++++++++++- common/build.rs | 2 + common/proto/ecb.proto | 67 ++++++ common/src/lib.rs | 3 + common/src/proto/descriptor.bin | Bin 105778 -> 110077 bytes common/src/proto/komp_ac.ecb.rs | 395 ++++++++++++++++++++++++++++++++ server | 2 +- 7 files changed, 759 insertions(+), 9 deletions(-) create mode 100644 common/proto/ecb.proto create mode 100644 common/src/proto/komp_ac.ecb.rs diff --git a/Cargo.lock b/Cargo.lock index 76f107f..02fc7d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,7 +156,7 @@ dependencies = [ "objc2-foundation", "parking_lot", "percent-encoding", - "windows-sys 0.52.0", + "windows-sys 0.59.0", "x11rb", ] @@ -737,7 +737,7 @@ version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" dependencies = [ - "darling 0.20.11", + "darling 0.23.0", "ident_case", "prettyplease", "proc-macro2", @@ -2156,6 +2156,37 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c286de4e81ea2590afc24d754e0f83810c566f50a1388fa75ebd57928c0d9745" +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "deltae" version = "0.3.2" @@ -2401,7 +2432,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2900,8 +2931,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -2925,11 +2958,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", "rand_core 0.10.1", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -3280,6 +3315,22 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + [[package]] name = "hyper-timeout" version = "0.5.2" @@ -3299,13 +3350,16 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64", "bytes", "futures-channel", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -3666,6 +3720,38 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jiff" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "961d16382652bfdd8c6f68b223b26a8c93e0d475c672f414411db31c6c5c900e" +dependencies = [ + "defmt", + "jiff-static", + "jiff-tzdb", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0879bd39df99c4c5e2c6615ccc026391a423dde10532c573e6086eb94a802cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + [[package]] name = "jni" version = "0.22.4" @@ -4006,6 +4092,12 @@ dependencies = [ "hashbrown 0.17.1", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lz4_flex" version = "0.13.1" @@ -4939,6 +5031,15 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "postgres-native-tls" version = "0.5.3" @@ -5114,7 +5215,7 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "itertools", "log", "multimap", @@ -5212,6 +5313,62 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "bytes", + "getrandom 0.4.2", + "lru-slab", + "rand 0.10.1", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + [[package]] name = "quote" version = "1.0.45" @@ -5317,6 +5474,15 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rand_xoshiro" version = "0.6.0" @@ -5509,6 +5675,44 @@ dependencies = [ "tstr", ] +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + [[package]] name = "resolv-conf" version = "0.7.6" @@ -5720,7 +5924,42 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -5987,11 +6226,13 @@ dependencies = [ "casbin", "chrono", "common", + "csv", "dashmap", "datafusion", "datafusion-table-providers", "dotenvy", "futures", + "jiff", "jsonwebtoken", "lazy_static", "once_cell", @@ -6000,6 +6241,7 @@ dependencies = [ "prost-types", "rand 0.10.1", "regex", + "reqwest", "rstest", "rust-stemmers", "rust_decimal", @@ -6009,6 +6251,7 @@ dependencies = [ "serde", "serde_json", "serial_test", + "sha2 0.10.9", "sqlx", "steel-core", "steel-decimal", @@ -6229,7 +6472,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f103c50866b8743da9429b8a581d81a27c2d3a9c4ac7df8f8571c1dd7896eda" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.117", @@ -6690,6 +6933,9 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -6914,7 +7160,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -7193,6 +7439,16 @@ dependencies = [ "whoami", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.18" @@ -7381,6 +7637,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.0", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -8039,6 +8313,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "weezl" version = "0.1.12" @@ -8167,7 +8450,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/common/build.rs b/common/build.rs index a58bd0d..453e5c9 100644 --- a/common/build.rs +++ b/common/build.rs @@ -217,6 +217,7 @@ fn main() -> Result<(), Box> { &[ "proto/common.proto", "proto/document_data.proto", + "proto/ecb.proto", "proto/adresar.proto", "proto/analytics.proto", "proto/auth.proto", @@ -243,6 +244,7 @@ fn main() -> Result<(), Box> { for proto in [ "proto/common.proto", "proto/document_data.proto", + "proto/ecb.proto", "proto/adresar.proto", "proto/analytics.proto", "proto/auth.proto", diff --git a/common/proto/ecb.proto b/common/proto/ecb.proto new file mode 100644 index 0000000..efea97d --- /dev/null +++ b/common/proto/ecb.proto @@ -0,0 +1,67 @@ +syntax = "proto3"; + +package komp_ac.ecb; + +// Read-only access to ECB conversion audit evidence. +// +// This service exists for manual visual verification. It exposes conversions +// already recorded by backend posting workflows and never recalculates money. +service EcbService { + // List immutable ECB conversion evidence for one money value. + rpc ListEcbConversionEvidence(ListEcbConversionEvidenceRequest) + returns (ListEcbConversionEvidenceResponse); +} + +// Identify one logical money cell whose conversion history should be inspected. +message ListEcbConversionEvidenceRequest { + // Required. Profile containing the table. + string profile_name = 1; + + // Required. Logical table name within the profile. + string table_name = 2; + + // Required. Dynamic table row id. + int64 record_id = 3; + + // Required. Current display name of the money column. The server resolves it + // to the stable physical column name used by immutable evidence. + string column_name = 4; + + // Optional. Maximum rows to return. Zero uses 100; maximum is 500. + int32 limit = 5; + + // Optional cursor. Return evidence ids lower than this value. + optional int64 before_evidence_id = 6; +} + +// One immutable explanation of how a posted EUR value was determined. +message EcbConversionEvidence { + int64 evidence_id = 1; + string original_amount = 2; + string original_currency = 3; + string eur_amount = 4; + string conversion_context = 5; + string anchor_date = 6; + string determination_method = 7; + string rounding_method = 8; + optional string rate_date = 9; + optional string units_per_eur = 10; + optional int64 rate_observation_id = 11; + optional string observation_hash = 12; + optional string source_payload_hash = 13; + optional string rate_fetched_at = 14; + optional int64 import_batch_id = 15; + optional string source_endpoint = 16; + string evidence_created_at = 17; +} + +message ListEcbConversionEvidenceResponse { + // True when at least one evidence row for this cell used an ECB rate. + bool has_exchange = 1; + + // Newest-first immutable history for this page. + repeated EcbConversionEvidence evidence = 2; + + // True when another page exists using the last evidence_id as the cursor. + bool has_more = 3; +} diff --git a/common/src/lib.rs b/common/src/lib.rs index edba9b1..4a6aa34 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -23,6 +23,9 @@ pub mod proto { pub mod document_data { include!("proto/komp_ac.document_data.rs"); } + pub mod ecb { + include!("proto/komp_ac.ecb.rs"); + } pub mod table_structure { include!("proto/komp_ac.table_structure.rs"); } diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index 0f530738c92376971b4475250c99b3605c1e1f51..13e1018a85c76729f9c66ee9754cf224401153ce 100644 GIT binary patch delta 4163 zcmaJ^OK%&=5!Uojd^9DI9LW|%ujQuJ)?3ue@?zn{iD+wKJMr2(+3aEWK#Ybhb6|3Y zo*7DJE(63DA9C6p4CI!75abddzaXa^gtNbDu3_Fh7!q&>~31z?bqWHu;y&w4JJdC`+KRNfh z+;{(IeE<0E!*7k{qW#5Rd;2y~mK zTaUWd8m$DO_uTWHe#aREBR{SanZR7SeJppaEm})=I_@Y8LBY6gLNzJb)l_m{3#{vu z@==%~DoRS&(O^5&ax+3Z_!;w8ik^~PyOe-*ArM(OzS|4JPS=UK68SuClbn69~%lvz?CsHIb50P)z^Pi{MMU{EFtrZz9h47(#mxKz=rzo}_ z;PWOi3}DTUd@qhVLmqaJW}Qkk!!FD1XFNO^g*ZX$kj_i2;56dlxe67hUWU5)kk~aL ze0nL9$8NP~byC0QM7{cqbYR+*Ah}e32#NL*1*6dAouM=C2Tr#mZDyrS&aNrpGbKxn zw!nu-^Nh!Ck9RvxT%VH$)Aph{z*jEW` z(~6FV``uySp~$Kdx?s;K!HM1%*eyDr7HG!}Ib6$NYQn;}cbWt7c zDxK@RcNp!fbV11{S@gQ?d0OjCZV8g4@(0LkTePY`F8PsrUZQ!>G|0^#WxMicgEl{Q zk#L(w!@!TY)ub~Bp~GLfJ;#5}>!MqWb{Tsodds>;izxxXxgiI~a9}G(JQ&z4xHDfgXX)v2R-JQVikD24TJc?Kxu#@|3c6nlbt*L z5eM=Nofc@oruiG`ieSZlnXXLBELZmEca-GdwKBD0G@i0Yc->;}Y|MfLnEl{680l+l zm-qYZq6bbUC}AKs4#F{udcmjS6 zi=>dQ;B2v2OIJW%T)0C2WJqYNu92n2A4K8493?7S^-RXB>qW!9GiG9LV8IzuP7hH{ z4=offmvt-4Ckp!KC><}RqUeQkqzYr$8%Oe#l$pXCMXEF}>xZ8wa&*zv0SZkdaxEj& zL?YKp3px=~guYm(Ph}oC%UmW_qs^WU#rx{?TkMJR${UOZf*jd}A&*C)-(uhLFktW= zvHiWhyXY~ch7LSR_VzLobMU>Kk(h(;<>IXNorCY?YK=aYzMu8A7H^TrD1z`)E z3YS@{;>40afRX!oKEyZE}0_J$fQZqlbjaV<*If&jUbw}Ptz5GXs)i&uh1Tb zmAf_dnbA05Ptg<;l)l0Ns*yt+U=MZT$V&j+pZwNV&e??%F*$-Hm`}2%z*A@5Dqg2$ zBx#7ISS5Ao8ViKAs=2`mimOFcx>zBsRg|tWgJ_Lh*JcLH*7R{2MBuNLQbi%*oycnezC}H+XLba3>!pUqB(Ph*zO2o#*vO(3)w7YAiR#%XrBRCN*~p><=bMDl znFNh%5OMOGnVmTK&C)gPPMrMaG6p_L3KX}R$CloCL8F%v6)C4lU% z+|(IR%iJTIT0{Y|mw`}#BzwBn4MKskSG$?20%dP)L!*=}bDykhQ5h)v8A=%_`&lSu zfb3f-(`A6{-&)fkGnRQkwlv5LKn@5^(j`z1GL#vh99U`UGe9|5-_$6xmU&3lwAn0B z4zo~Z0dkmu%mU<4j8O6vW&v_|b5(=PS>|oB3Q;1;Zw@H8Gn6@?+|F2;1Iq1MdX{rQ zx&7%ajZ(49qb!sPK#nqy3P6ssP$~d9%0j6C@2~|BQHhykjobW*Q6Mq#QdzUW`H8ByCg3I!3qxV7F1(ng|P0Tv41ArLv)X{ z8oTUEet|h}=gbS=8(GrPKnz=OoJ4HsJil~gfW>>7MM4bp?Y*)hA1i^~+|WUY>+9b3 z4*f>D#qD)W78;Kxv-ShLh@r$!N4!y_1__KYf)9RvU%h|$Z-wDX7B8rNNz{8l- cWiF^bE>v^~;wC({=3l>C`rErDS!6$rEd diff --git a/common/src/proto/komp_ac.ecb.rs b/common/src/proto/komp_ac.ecb.rs new file mode 100644 index 0000000..4b08e82 --- /dev/null +++ b/common/src/proto/komp_ac.ecb.rs @@ -0,0 +1,395 @@ +// This file is @generated by prost-build. +/// Identify one logical money cell whose conversion history should be inspected. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ListEcbConversionEvidenceRequest { + /// Required. Profile containing the table. + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, + /// Required. Logical table name within the profile. + #[prost(string, tag = "2")] + pub table_name: ::prost::alloc::string::String, + /// Required. Dynamic table row id. + #[prost(int64, tag = "3")] + pub record_id: i64, + /// Required. Current display name of the money column. The server resolves it + /// to the stable physical column name used by immutable evidence. + #[prost(string, tag = "4")] + pub column_name: ::prost::alloc::string::String, + /// Optional. Maximum rows to return. Zero uses 100; maximum is 500. + #[prost(int32, tag = "5")] + pub limit: i32, + /// Optional cursor. Return evidence ids lower than this value. + #[prost(int64, optional, tag = "6")] + pub before_evidence_id: ::core::option::Option, +} +/// One immutable explanation of how a posted EUR value was determined. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct EcbConversionEvidence { + #[prost(int64, tag = "1")] + pub evidence_id: i64, + #[prost(string, tag = "2")] + pub original_amount: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub original_currency: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub eur_amount: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub conversion_context: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub anchor_date: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub determination_method: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub rounding_method: ::prost::alloc::string::String, + #[prost(string, optional, tag = "9")] + pub rate_date: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "10")] + pub units_per_eur: ::core::option::Option<::prost::alloc::string::String>, + #[prost(int64, optional, tag = "11")] + pub rate_observation_id: ::core::option::Option, + #[prost(string, optional, tag = "12")] + pub observation_hash: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "13")] + pub source_payload_hash: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "14")] + pub rate_fetched_at: ::core::option::Option<::prost::alloc::string::String>, + #[prost(int64, optional, tag = "15")] + pub import_batch_id: ::core::option::Option, + #[prost(string, optional, tag = "16")] + pub source_endpoint: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, tag = "17")] + pub evidence_created_at: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListEcbConversionEvidenceResponse { + /// True when at least one evidence row for this cell used an ECB rate. + #[prost(bool, tag = "1")] + pub has_exchange: bool, + /// Newest-first immutable history for this page. + #[prost(message, repeated, tag = "2")] + pub evidence: ::prost::alloc::vec::Vec, + /// True when another page exists using the last evidence_id as the cursor. + #[prost(bool, tag = "3")] + pub has_more: bool, +} +/// Generated client implementations. +pub mod ecb_service_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Read-only access to ECB conversion audit evidence. + /// + /// This service exists for manual visual verification. It exposes conversions + /// already recorded by backend posting workflows and never recalculates money. + #[derive(Debug, Clone)] + pub struct EcbServiceClient { + inner: tonic::client::Grpc, + } + impl EcbServiceClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl EcbServiceClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> EcbServiceClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + EcbServiceClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// List immutable ECB conversion evidence for one money value. + pub async fn list_ecb_conversion_evidence( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.ecb.EcbService/ListEcbConversionEvidence", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.ecb.EcbService", + "ListEcbConversionEvidence", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod ecb_service_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with EcbServiceServer. + #[async_trait] + pub trait EcbService: std::marker::Send + std::marker::Sync + 'static { + /// List immutable ECB conversion evidence for one money value. + async fn list_ecb_conversion_evidence( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + } + /// Read-only access to ECB conversion audit evidence. + /// + /// This service exists for manual visual verification. It exposes conversions + /// already recorded by backend posting workflows and never recalculates money. + #[derive(Debug)] + pub struct EcbServiceServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl EcbServiceServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for EcbServiceServer + where + T: EcbService, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/komp_ac.ecb.EcbService/ListEcbConversionEvidence" => { + #[allow(non_camel_case_types)] + struct ListEcbConversionEvidenceSvc(pub Arc); + impl< + T: EcbService, + > tonic::server::UnaryService< + super::ListEcbConversionEvidenceRequest, + > for ListEcbConversionEvidenceSvc { + type Response = super::ListEcbConversionEvidenceResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::ListEcbConversionEvidenceRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::list_ecb_conversion_evidence( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListEcbConversionEvidenceSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + let mut response = http::Response::new( + tonic::body::Body::default(), + ); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } + } + } + } + impl Clone for EcbServiceServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "komp_ac.ecb.EcbService"; + impl tonic::server::NamedService for EcbServiceServer { + const NAME: &'static str = SERVICE_NAME; + } +} diff --git a/server b/server index 0635958..fd73fe9 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit 0635958988452125f9a4fc462a9f418981753365 +Subproject commit fd73fe9b2a1bb449addafa20e5c116127939b99f