diff --git a/Cargo.lock b/Cargo.lock index e6cfbdf..ee77d2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,6 +115,15 @@ dependencies = [ ] [[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener", +] + +[[package]] name = "async-trait" version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -122,7 +131,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -222,10 +231,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] +name = "bytecount" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7" + +[[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -234,6 +249,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -348,6 +394,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" [[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] name = "crossbeam-queue" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -484,23 +553,21 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ - "errno-dragonfly", "libc", "windows-sys", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "error-chain" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" dependencies = [ - "cc", - "libc", + "version_check", ] [[package]] @@ -635,7 +702,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -745,6 +812,24 @@ dependencies = [ ] [[package]] +name = "giterated-cache" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "futures-util", + "giterated-models", + "giterated-stack", + "moka", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] name = "giterated-daemon" version = "0.1.0" dependencies = [ @@ -821,6 +906,12 @@ dependencies = [ ] [[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] name = "h2" version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -850,9 +941,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" dependencies = [ "ahash 0.8.3", "allocator-api2", @@ -864,7 +955,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.0", + "hashbrown 0.14.1", ] [[package]] @@ -1051,12 +1142,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.1", ] [[package]] @@ -1091,9 +1182,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] @@ -1132,9 +1223,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libgit2-sys" @@ -1152,9 +1243,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" @@ -1195,9 +1286,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lock_api" @@ -1216,6 +1307,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] +name = "mach2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +dependencies = [ + "libc", +] + +[[package]] name = "md-5" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1227,9 +1327,18 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] [[package]] name = "mime" @@ -1264,6 +1373,30 @@ dependencies = [ ] [[package]] +name = "moka" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8017ec3548ffe7d4cef7ac0e12b044c01164a74c0f3119420faeaf13490ad8b" +dependencies = [ + "async-lock", + "async-trait", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "futures-util", + "once_cell", + "parking_lot", + "quanta", + "rustc_version", + "skeptic", + "smallvec", + "tagptr", + "thiserror", + "triomphe", + "uuid", +] + +[[package]] name = "native-tls" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1352,9 +1485,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", @@ -1414,7 +1547,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1570,14 +1703,41 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] +name = "pulldown-cmark" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quanta" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +dependencies = [ + "crossbeam-utils", + "libc", + "mach2", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + +[[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1617,6 +1777,15 @@ dependencies = [ ] [[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1627,9 +1796,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64 0.21.4", "bytes", @@ -1655,6 +1824,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", @@ -1718,10 +1888,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] name = "rustix" -version = "0.38.14" +version = "0.38.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +checksum = "5a74ee2d7c2581cd139b42447d7d9389b889bdaad3a73f1ebb16f2a3237bb19c" dependencies = [ "bitflags 2.4.0", "errno", @@ -1780,6 +1959,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] name = "schannel" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1839,9 +2027,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" dependencies = [ "serde", ] @@ -1863,7 +2051,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1922,9 +2110,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -1961,6 +2149,21 @@ dependencies = [ ] [[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + +[[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2067,7 +2270,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.0.0", + "indexmap 2.0.2", "log", "memchr", "native-tls", @@ -2261,9 +2464,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -2271,6 +2474,33 @@ dependencies = [ ] [[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] name = "tempfile" version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2300,7 +2530,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2358,9 +2588,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ "backtrace", "bytes", @@ -2383,7 +2613,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2475,7 +2705,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.0.2", "serde", "serde_spanned", "toml_datetime", @@ -2509,7 +2739,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2558,6 +2788,12 @@ dependencies = [ ] [[package]] +name = "triomphe" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee8098afad3fb0c54a9007aab6804558410503ad676d4633f9c2559a00ac0f" + +[[package]] name = "try-lock" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2590,6 +2826,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] name = "unicode-bidi" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2657,6 +2902,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom", +] + +[[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2675,6 +2929,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] name = "want" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2710,7 +2974,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -2744,7 +3008,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2794,6 +3058,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2876,9 +3149,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index f416814..93dbda5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,6 @@ members = [ "giterated-daemon", "giterated-models", - "giterated-stack" + "giterated-stack", + "giterated-cache" ] \ No newline at end of file diff --git a/giterated-cache/Cargo.toml b/giterated-cache/Cargo.toml new file mode 100644 index 0000000..4151ddb --- /dev/null +++ b/giterated-cache/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "giterated-cache" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +giterated-models = { path = "../giterated-models" } +async-trait = "0.1" +serde = { version = "1.0.188", features = [ "derive" ]} +serde_json = "1.0" +bincode = "1.3" +futures-util = "0.3" +tracing = "0.1" +tokio = { version = "1.32", features = [ "full" ] } +anyhow = "1" +thiserror = "1" +giterated-stack = { path = "../giterated-stack" } +moka = { version = "0.12.0", features = ["future"] } diff --git a/giterated-cache/src/cache_get.rs b/giterated-cache/src/cache_get.rs new file mode 100644 index 0000000..caa2e8c --- /dev/null +++ b/giterated-cache/src/cache_get.rs @@ -0,0 +1,16 @@ +// use std::sync::Arc; + +// use giterated_models::error::OperationError; +// use giterated_stack::GiteratedStack; +// use serde_json::Value; + +// use crate::{cache_update::AnyObject, CacheSubstack}; + +// pub async fn try_value_get( +// object: AnyObject<'_>, +// value_name: &str, +// cache: CacheSubstack, +// stack: Arc, +// ) -> Result> { +// todo!() +// } diff --git a/giterated-cache/src/cache_update.rs b/giterated-cache/src/cache_update.rs new file mode 100644 index 0000000..479b50c --- /dev/null +++ b/giterated-cache/src/cache_update.rs @@ -0,0 +1,348 @@ +// use std::{any::Any, pin::Pin, process::Output, sync::Arc}; + +// use futures_util::{future::LocalBoxFuture, Future, FutureExt}; +// use giterated_models::{ +// error::{ExtractorError, OperationError, RepositoryError}, +// object::GiteratedObject, +// operation::GiteratedOperation, +// repository::{Repository, RepositoryBranch, RepositoryBranchesRequest}, +// settings::SetSetting, +// user::{DisplayName, User}, +// value::{GetValue, GiteratedObjectValue}, +// }; +// use giterated_stack::{ +// AuthorizedUser, FromOperationState, GiteratedStack, MissingValue, StackOperationState, +// }; + +// use crate::CacheSubstack; + +// async fn value_update( +// object: AnyObject<'_>, +// value: AnyValue<'_>, +// cache: CacheSubstack, +// stack: Arc, +// ) -> Result<(), anyhow::Error> { +// todo!() +// } + +// pub struct AnyObject<'o>(&'o (dyn Any + Send + Sync)); + +// pub struct AnyValue<'v>(&'v (dyn Any + Send + Sync)); + +// #[async_trait::async_trait(?Send)] +// pub trait GiteratedHandler +// { +// async fn handle( +// &self, +// parameters: RequiredParameters, +// additional_parameters: AdditionalParameters, +// state: Arc, +// operation_state: &OperationState, +// ) -> Output; +// } + +// #[async_trait::async_trait(?Send)] +// impl GiteratedHandler<(R1,), (), S, O, Output> for F +// where +// F: FnMut(R1, S, &O) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// { +// async fn handle( +// &self, +// parameters: (R1,), +// additional_parameters: (), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl GiteratedHandler<(R1,), (A1,), S, O, Output> for F +// where +// F: FnMut(R1, S, &O, A1) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// A1: 'static + HandlerResolvable<(R1,), O, A1>, +// { +// async fn handle( +// &self, +// parameters: (R1,), +// additional_parameters: (A1,), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl GiteratedHandler<(R1,), (A1, A2), S, O, Output> for F +// where +// F: FnMut(R1, S, &O, A1, A2) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// A1: 'static + HandlerResolvable<(R1,), O, A1>, +// A2: 'static + HandlerResolvable<(R1,), O, A2>, +// { +// async fn handle( +// &self, +// parameters: (R1,), +// additional_parameters: (A1, A2), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl GiteratedHandler<(R1,), (A1, A2, A3), S, O, Output> for F +// where +// F: FnMut(R1, S, &O, A1, A2, A3) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// A1: 'static + HandlerResolvable<(R1,), O, A1>, +// A2: 'static + HandlerResolvable<(R1,), O, A2>, +// A3: 'static + HandlerResolvable<(R1,), O, A3>, +// { +// async fn handle( +// &self, +// parameters: (R1,), +// additional_parameters: (A1, A2, A3), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl GiteratedHandler<(R1, R2), (), S, O, Output> for F +// where +// F: FnMut(R1, R2, S, &O) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// R2: 'static, +// { +// async fn handle( +// &self, +// parameters: (R1, R2), +// additional_parameters: (), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl GiteratedHandler<(R1, R2), (A1,), S, O, Output> for F +// where +// F: FnMut(R1, R2, S, &O, A1) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// R2: 'static, +// A1: 'static + HandlerResolvable<(R1, R2), O, A1>, +// { +// async fn handle( +// &self, +// parameters: (R1, R2), +// additional_parameters: (A1,), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl GiteratedHandler<(R1, R2), (A1, A2), S, O, Output> for F +// where +// F: FnMut(R1, R2, S, &O, A1, A2) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// R2: 'static, +// A1: 'static + HandlerResolvable<(R1, R2), O, A1>, +// A2: 'static + HandlerResolvable<(R1, R2), O, A2>, +// { +// async fn handle( +// &self, +// parameters: (R1, R2), +// additional_parameters: (A1, A2), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl +// GiteratedHandler<(R1, R2), (A1, A2, A3), S, O, Output> for F +// where +// F: FnMut(R1, R2, S, &O, A1, A2, A3) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// R2: 'static, +// A1: 'static + HandlerResolvable<(R1, R2), O, A1>, +// A2: 'static + HandlerResolvable<(R1, R2), O, A2>, +// A3: 'static + HandlerResolvable<(R1, R2), O, A3>, +// { +// async fn handle( +// &self, +// parameters: (R1, R2), +// additional_parameters: (A1, A2, A3), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl GiteratedHandler<(R1, R2, R3), (), S, O, Output> for F +// where +// F: FnMut(R1, R2, R3, S, &O) -> Fut, +// Fut: Future, +// S: 'static, +// R1: 'static, +// R2: 'static, +// R3: 'static, +// { +// async fn handle( +// &self, +// parameters: (R1, R2, R3), +// additional_parameters: (), +// state: Arc, +// operation_state: &O, +// ) -> Output { +// todo!() +// } +// } + +// fn test_fn(handler: F) +// where +// F: GiteratedHandler<(O, V), A, S, StackOperationState, Result<(), anyhow::Error>>, +// O: GiteratedObject, +// V: GiteratedObjectValue, +// { +// } + +// fn other_fn() { +// let a = String::from("a"); +// let test = move |object: User, +// value: GetValue, +// state: (), +// operation_state: &StackOperationState, +// authorized_user: AuthorizedUser| { async move { () } }; + +// let wrapper = HandlerWrapper::<(User, GetValue), _>::new((), test); +// } + +// pub struct HandlerWrapper { +// func: Box LocalBoxFuture<'static, O>>, +// state: Arc, +// } + +// impl HandlerWrapper { +// pub fn new(state: S, handler: F) -> Self +// where +// F: GiteratedHandler, +// S: Send + Sync + 'static, +// A: HandlerResolvableGroup

, +// { +// let state = Arc::new(state); + +// let func = |required: P, operation_state: StackOperationState| { +// // async move { handler.handle(required, (), state, &operation_state) }.boxed_local() +// todo!() +// }; + +// Self { +// func: Box::new(func), +// state, +// } +// } +// } + +// #[async_trait::async_trait(?Send)] +// pub trait HandlerResolvable { +// async fn from_handler_state( +// required_parameters: &RequiredParameters, +// operation_state: &OperationState, +// ) -> Output; +// } + +// #[async_trait::async_trait(?Send)] +// impl HandlerResolvable<(User, GetValue), StackOperationState, Self> for Arc { +// async fn from_handler_state( +// required_parameters: &(User, GetValue), +// operation_state: &StackOperationState, +// ) -> Self { +// todo!() +// } +// } + +// // #[async_trait::async_trait(?Send)] +// // impl HandlerResolvable<(O, D), StackOperationState, T> for T +// // where +// // O: GiteratedObject, +// // D: GiteratedOperation, +// // T: FromOperationState, +// // { +// // async fn from_handler_state( +// // required_parameters: &(O, D), +// // operation_state: &StackOperationState, +// // ) -> T { +// // todo!() +// // } +// // } + +// #[async_trait::async_trait(?Send)] +// pub trait HandlerResolvableGroup { +// async fn group_from_handler_state( +// required_parameters: &RequiredParameters, +// operation_state: &StackOperationState, +// ) -> Self; +// } + +// #[async_trait::async_trait(?Send)] +// impl HandlerResolvableGroup for (A1,) +// where +// A1: HandlerResolvable, +// { +// async fn group_from_handler_state( +// required_parameters: &RequiredParameters, +// operation_state: &StackOperationState, +// ) -> (A1,) { +// (A1::from_handler_state(required_parameters, operation_state).await,) +// } +// } + +// #[async_trait::async_trait(?Send)] +// impl HandlerResolvableGroup for (A1, A2) +// where +// A1: HandlerResolvable, +// A2: HandlerResolvable, +// { +// async fn group_from_handler_state( +// required_parameters: &RequiredParameters, +// operation_state: &StackOperationState, +// ) -> (A1, A2) { +// ( +// A1::from_handler_state(required_parameters, operation_state).await, +// A2::from_handler_state(required_parameters, operation_state).await, +// ) +// } +// } diff --git a/giterated-cache/src/lib.rs b/giterated-cache/src/lib.rs new file mode 100644 index 0000000..28a558b --- /dev/null +++ b/giterated-cache/src/lib.rs @@ -0,0 +1,25 @@ +// pub mod cache_get; +// pub mod cache_update; + +// use giterated_stack::{ObjectValuePair, SubstackBuilder}; +// use moka::future::Cache; +// use serde_json::Value; + +// #[derive(Clone)] +// pub struct CacheSubstack { +// cache: Cache, +// } + +// impl Default for CacheSubstack { +// fn default() -> Self { +// Self { +// cache: Cache::new(20_000), +// } +// } +// } + +// impl CacheSubstack { +// pub fn into_substack(self) -> SubstackBuilder { +// todo!() +// } +// } diff --git a/giterated-daemon/src/backend/mod.rs b/giterated-daemon/src/backend/mod.rs index 39a233e..5b1b836 100644 --- a/giterated-daemon/src/backend/mod.rs +++ b/giterated-daemon/src/backend/mod.rs @@ -25,9 +25,8 @@ use giterated_models::repository::{ RepositoryLastCommitOfFileRequest, RepositoryStatistics, RepositoryStatisticsRequest, RepositorySummary, RepositoryTreeEntry, }; -use giterated_models::settings::AnySetting; + use giterated_models::user::User; -use giterated_models::value::AnyValue; #[async_trait] pub trait RepositoryBackend { @@ -137,14 +136,6 @@ pub trait AuthBackend { #[async_trait::async_trait] pub trait UserBackend: AuthBackend { - async fn get_value(&mut self, user: &User, name: &str) -> Result, Error>; - async fn get_setting(&mut self, user: &User, name: &str) -> Result; - async fn write_setting( - &mut self, - user: &User, - name: &str, - setting: &Value, - ) -> Result<(), Error>; async fn exists(&mut self, user: &User) -> Result; async fn repositories_for_user( &mut self, @@ -155,22 +146,14 @@ pub trait UserBackend: AuthBackend { #[async_trait::async_trait] pub trait MetadataBackend { - async fn user_get(&mut self, user: &User, name: &str) -> Result; - async fn user_write( - &mut self, - user: &User, - name: &str, - setting: AnySetting, - ) -> Result<(), Error>; - async fn repository_get( - &mut self, - repository: &Repository, - name: &str, - ) -> Result; + async fn user_get(&mut self, user: &User, name: &str) -> Result; + async fn user_write(&mut self, user: &User, name: &str, setting: Value) -> Result<(), Error>; + async fn repository_get(&mut self, repository: &Repository, name: &str) + -> Result; async fn repository_write( &mut self, repository: &Repository, name: &str, - setting: AnySetting, + setting: Value, ) -> Result<(), Error>; } diff --git a/giterated-daemon/src/backend/settings.rs b/giterated-daemon/src/backend/settings.rs index 13d5967..15acab0 100644 --- a/giterated-daemon/src/backend/settings.rs +++ b/giterated-daemon/src/backend/settings.rs @@ -3,10 +3,11 @@ use std::sync::Arc; use anyhow::Error; use giterated_models::repository::Repository; -use giterated_models::settings::AnySetting; + use giterated_models::user::User; use giterated_stack::GiteratedStack; +use serde_json::Value; use sqlx::PgPool; use tokio::sync::OnceCell; @@ -19,7 +20,7 @@ pub struct DatabaseSettings { #[async_trait::async_trait] impl MetadataBackend for DatabaseSettings { - async fn user_get(&mut self, user: &User, name: &str) -> Result { + async fn user_get(&mut self, user: &User, name: &str) -> Result { let row = sqlx::query_as!( UserSettingRow, "SELECT * FROM user_settings WHERE username = $1 AND name = $2", @@ -33,12 +34,7 @@ impl MetadataBackend for DatabaseSettings { Ok(setting) } - async fn user_write( - &mut self, - user: &User, - name: &str, - value: AnySetting, - ) -> Result<(), Error> { + async fn user_write(&mut self, user: &User, name: &str, value: Value) -> Result<(), Error> { sqlx::query!("INSERT INTO user_settings VALUES ($1, $2, $3) ON CONFLICT (username, name) DO UPDATE SET value = $3", user.username, name, serde_json::to_string(&value)?) .execute(&self.pg_pool).await?; @@ -50,7 +46,7 @@ impl MetadataBackend for DatabaseSettings { &mut self, repository: &Repository, name: &str, - ) -> Result { + ) -> Result { let row = sqlx::query_as!( RepositorySettingRow, "SELECT * FROM repository_settings WHERE repository = $1 AND name = $2", @@ -68,7 +64,7 @@ impl MetadataBackend for DatabaseSettings { &mut self, repository: &Repository, name: &str, - value: AnySetting, + value: Value, ) -> Result<(), Error> { sqlx::query!("INSERT INTO repository_settings VALUES ($1, $2, $3) ON CONFLICT (repository, name) DO UPDATE SET value = $3", repository.to_string(), name, serde_json::to_string(&value)?) diff --git a/giterated-daemon/src/backend/user.rs b/giterated-daemon/src/backend/user.rs index e984f0c..c8de1ac 100644 --- a/giterated-daemon/src/backend/user.rs +++ b/giterated-daemon/src/backend/user.rs @@ -5,9 +5,8 @@ use giterated_models::authenticated::UserAuthenticationToken; use giterated_models::instance::{AuthenticationTokenRequest, Instance, RegisterAccountRequest}; use giterated_models::repository::{Repository, RepositorySummary}; -use giterated_models::settings::{AnySetting, Setting}; -use giterated_models::user::{Bio, DisplayName, User, UserParseError}; -use giterated_models::value::AnyValue; +use giterated_models::user::User; + use giterated_stack::AuthenticatedUser; use std::sync::Arc; @@ -22,7 +21,7 @@ use rsa::{ }; use secrecy::ExposeSecret; -use serde_json::Value; + use sqlx::{Either, PgPool}; use tokio::sync::Mutex; @@ -56,36 +55,6 @@ impl UserAuth { #[async_trait::async_trait] impl UserBackend for UserAuth { - async fn get_value(&mut self, user: &User, name: &str) -> Result, Error> { - Ok(match name { - "display_name" => unsafe { - AnyValue::from_raw(self.get_setting(user, DisplayName::name()).await?.0) - }, - "bio" => unsafe { AnyValue::from_raw(self.get_setting(user, Bio::name()).await?.0) }, - _ => { - return Err(UserParseError.into()); - } - }) - } - async fn get_setting(&mut self, user: &User, name: &str) -> Result { - let mut provider = self.settings_provider.lock().await; - - Ok(provider.user_get(user, name).await?) - } - - async fn write_setting( - &mut self, - user: &User, - name: &str, - setting: &Value, - ) -> Result<(), Error> { - let mut provider = self.settings_provider.lock().await; - - provider - .user_write(user, name, AnySetting(setting.clone())) - .await - } - async fn exists(&mut self, user: &User) -> Result { Ok(sqlx::query_as!( UserRow, diff --git a/giterated-daemon/src/database_backend/handler.rs b/giterated-daemon/src/database_backend/handler.rs index 81cc470..b45cd0f 100644 --- a/giterated-daemon/src/database_backend/handler.rs +++ b/giterated-daemon/src/database_backend/handler.rs @@ -1,11 +1,8 @@ use std::sync::Arc; -use futures_util::{future::LocalBoxFuture, FutureExt}; use giterated_models::{ authenticated::UserAuthenticationToken, - error::{ - GetValueError, InstanceError, IntoInternalError, OperationError, RepositoryError, UserError, - }, + error::{InstanceError, IntoInternalError, OperationError, RepositoryError, UserError}, instance::{ AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest, }, @@ -18,584 +15,384 @@ use giterated_models::{ RepositoryInfoRequest, RepositoryLastCommitOfFileRequest, RepositoryStatistics, RepositoryStatisticsRequest, RepositorySummary, RepositoryView, Visibility, }, - settings::{GetSetting, GetSettingError}, - user::{Bio, DisplayName, User, UserRepositoriesRequest}, - value::{AnyValue, GetValueTyped}, + user::{User, UserRepositoriesRequest}, }; -use giterated_stack::{AuthenticatedUser, AuthorizedInstance, GiteratedStack, StackOperationState}; -use serde_json::Value; +use giterated_stack::{AuthenticatedUser, GiteratedStack, StackOperationState}; use super::DatabaseBackend; -pub fn user_get_repositories( - object: &User, +pub async fn user_get_repositories( + object: User, _operation: UserRepositoriesRequest, state: DatabaseBackend, _operation_state: StackOperationState, requester: Option, -) -> LocalBoxFuture<'static, Result, OperationError>> { +) -> Result, OperationError> { let object = object.clone(); - async move { - let mut user_backend = state.user_backend.lock().await; - let repositories_response = user_backend - .repositories_for_user(&requester, &object) - .await - .as_internal_error()?; - drop(user_backend); - let mut repositories_backend = state.repository_backend.lock().await; - - let mut repositories = vec![]; - - for repository in repositories_response { - if repositories_backend - .exists(&requester, &repository.repository) - .await - .as_internal_error()? - { - repositories.push(repository); - } - } - - Ok(repositories) - } - .boxed_local() -} + let mut user_backend = state.user_backend.lock().await; + let repositories_response = user_backend + .repositories_for_user(&requester, &object) + .await + .as_internal_error()?; + drop(user_backend); + let mut repositories_backend = state.repository_backend.lock().await; -pub fn user_get_value( - object: &User, - operation: GetValueTyped>, - state: DatabaseBackend, -) -> LocalBoxFuture<'static, Result, OperationError>> { - let object = object.clone(); + let mut repositories = vec![]; - async move { - let mut user_backend = state.user_backend.lock().await; - let value = user_backend - .get_value(&object, &operation.value_name) + for repository in repositories_response { + if repositories_backend + .exists(&requester, &repository.repository) .await - .as_internal_error()?; - - Ok(value) + .as_internal_error()? + { + repositories.push(repository); + } } - .boxed_local() -} - -pub fn user_get_setting( - object: &User, - operation: GetSetting, - state: DatabaseBackend, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let mut user_backend = state.user_backend.lock().await; - let value = user_backend - .get_setting(&object, &operation.setting_name) - .await - .as_internal_error()?; - Ok(value.0) - } - .boxed_local() + Ok(repositories) } -pub fn repository_info( - object: &Repository, +pub async fn repository_info( + object: Repository, operation: RepositoryInfoRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let mut object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - let mut repository_backend = state.repository_backend.lock().await; - let tree = repository_backend - .repository_file_inspect( - &requester, - object.object(), - &RepositoryFileInspectRequest { - extra_metadata: operation.extra_metadata, - path: operation.path, - rev: operation.rev.clone(), - }, - ) +) -> Result> { + let mut object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + let mut repository_backend = state.repository_backend.lock().await; + let tree = repository_backend + .repository_file_inspect( + &requester, + object.object(), + &RepositoryFileInspectRequest { + extra_metadata: operation.extra_metadata, + path: operation.path.clone(), + rev: operation.rev.clone(), + }, + ) + .await + .as_internal_error()?; + + let statistics = repository_backend + .repository_get_statistics( + &requester, + object.object(), + &RepositoryStatisticsRequest { + rev: operation.rev.clone(), + }, + ) + .await + .as_internal_error()?; + drop(repository_backend); + + let info = RepositoryView { + name: object.object().name.clone(), + owner: object.object().owner.clone(), + description: object.get::(&operation_state).await.ok(), + visibility: object + .get::(&operation_state) .await - .as_internal_error()?; - - let statistics = repository_backend - .repository_get_statistics( - &requester, - object.object(), - &RepositoryStatisticsRequest { - rev: operation.rev.clone(), - }, - ) + .as_internal_error()?, + default_branch: object + .get::(&operation_state) .await - .as_internal_error()?; - drop(repository_backend); - - let info = RepositoryView { - name: object.object().name.clone(), - owner: object.object().owner.clone(), - description: object.get::(&operation_state).await.ok(), - visibility: object - .get::(&operation_state) - .await - .as_internal_error()?, - default_branch: object - .get::(&operation_state) - .await - .as_internal_error()?, - // TODO: Can't be a simple get function, this needs to be returned alongside the tree as this differs depending on the rev and path. - latest_commit: object.get::(&operation_state).await.ok(), - stats: statistics, - tree_rev: operation.rev, - tree, - }; - - Ok(info) - } - .boxed_local() + .as_internal_error()?, + // TODO: Can't be a simple get function, this needs to be returned alongside the tree as this differs depending on the rev and path. + latest_commit: object.get::(&operation_state).await.ok(), + stats: statistics, + tree_rev: operation.rev.clone(), + tree, + }; + + Ok(info) } -pub fn repository_get_statistics( - object: &Repository, +pub async fn repository_get_statistics( + object: Repository, operation: RepositoryStatisticsRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let statistics = repository_backend - .repository_get_statistics( - &requester, - object.object(), - &RepositoryStatisticsRequest { rev: operation.rev }, - ) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(statistics) - } - .boxed_local() +) -> Result> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let statistics = repository_backend + .repository_get_statistics( + &requester, + object.object(), + &RepositoryStatisticsRequest { + rev: operation.rev.clone(), + }, + ) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(statistics) } -pub fn repository_get_branches( - object: &Repository, +pub async fn repository_get_branches( + object: Repository, operation: RepositoryBranchesRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result, OperationError>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let branches = repository_backend - .repository_get_branches(&requester, object.object(), &operation) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(branches) - } - .boxed_local() +) -> Result, OperationError> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let branches = repository_backend + .repository_get_branches(&requester, object.object(), &operation) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(branches) } -pub fn repository_file_from_id( - object: &Repository, +pub async fn repository_file_from_id( + object: Repository, operation: RepositoryFileFromIdRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let file = repository_backend - .repository_file_from_id( - &requester, - object.object(), - &RepositoryFileFromIdRequest(operation.0), - ) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(file) - } - .boxed_local() +) -> Result> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let file = repository_backend + .repository_file_from_id( + &requester, + object.object(), + &RepositoryFileFromIdRequest(operation.0.clone()), + ) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(file) } -pub fn repository_file_from_path( - object: &Repository, +pub async fn repository_file_from_path( + object: Repository, operation: RepositoryFileFromPathRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result<(RepositoryFile, String), OperationError>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let file = repository_backend - .repository_file_from_path( - &requester, - object.object(), - &RepositoryFileFromPathRequest { - rev: operation.rev, - path: operation.path, - }, - ) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(file) - } - .boxed_local() +) -> Result<(RepositoryFile, String), OperationError> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let file = repository_backend + .repository_file_from_path( + &requester, + object.object(), + &RepositoryFileFromPathRequest { + rev: operation.rev.clone(), + path: operation.path.clone(), + }, + ) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(file) } -pub fn repository_last_commit_of_file( - object: &Repository, +pub async fn repository_last_commit_of_file( + object: Repository, operation: RepositoryLastCommitOfFileRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let commit = repository_backend - .repository_last_commit_of_file( - &requester, - object.object(), - &RepositoryLastCommitOfFileRequest { - start_commit: operation.start_commit, - path: operation.path, - }, - ) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(commit) - } - .boxed_local() +) -> Result> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let commit = repository_backend + .repository_last_commit_of_file( + &requester, + object.object(), + &RepositoryLastCommitOfFileRequest { + start_commit: operation.start_commit.clone(), + path: operation.path.clone(), + }, + ) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(commit) } -pub fn repository_commit_by_id( - object: &Repository, +pub async fn repository_commit_by_id( + object: Repository, operation: RepositoryCommitFromIdRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let commit = repository_backend - .repository_commit_from_id( - &requester, - object.object(), - &RepositoryCommitFromIdRequest(operation.0), - ) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(commit) - } - .boxed_local() +) -> Result> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let commit = repository_backend + .repository_commit_from_id( + &requester, + object.object(), + &RepositoryCommitFromIdRequest(operation.0.clone()), + ) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(commit) } -pub fn repository_diff( - object: &Repository, +pub async fn repository_diff( + object: Repository, operation: RepositoryDiffRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let diff = repository_backend - .repository_diff(&requester, object.object(), &operation) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(diff) - } - .boxed_local() +) -> Result> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let diff = repository_backend + .repository_diff(&requester, object.object(), &operation) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(diff) } -pub fn repository_diff_patch( - object: &Repository, +pub async fn repository_diff_patch( + object: Repository, operation: RepositoryDiffPatchRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let patch = repository_backend - .repository_diff_patch(&requester, object.object(), &operation) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(patch) - } - .boxed_local() +) -> Result> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let patch = repository_backend + .repository_diff_patch(&requester, object.object(), &operation) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(patch) } -pub fn repository_commit_before( - object: &Repository, +pub async fn repository_commit_before( + object: Repository, operation: RepositoryCommitBeforeRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - let object = backend - .get_object::(&object.to_string(), &operation_state) - .await - .unwrap(); - - let mut repository_backend = state.repository_backend.lock().await; - let file = repository_backend - .repository_commit_before(&requester, object.object(), &operation) - .await - .as_internal_error()?; - drop(repository_backend); - - Ok(file) - } - .boxed_local() +) -> Result> { + let object = backend + .get_object::(&object.to_string(), &operation_state) + .await + .unwrap(); + + let mut repository_backend = state.repository_backend.lock().await; + let file = repository_backend + .repository_commit_before(&requester, object.object(), &operation) + .await + .as_internal_error()?; + drop(repository_backend); + + Ok(file) } -pub fn instance_authentication_request( - object: &Instance, +pub async fn instance_authentication_request( + object: Instance, operation: AuthenticationTokenRequest, state: DatabaseBackend, + _operation_state: StackOperationState, // Authorizes the request for SAME-INSTANCE - _authorized_instance: AuthorizedInstance, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - async move { - let mut backend = state.user_backend.lock().await; - - backend.login(&object, operation).await.as_internal_error() - } - .boxed_local() + // _authorized_instance: AuthorizedInstance, +) -> Result> { + let mut backend = state.user_backend.lock().await; + + backend + .login(&object, operation.clone()) + .await + .as_internal_error() } -pub fn instance_registration_request( - _object: &Instance, +pub async fn instance_registration_request( + _object: Instance, operation: RegisterAccountRequest, state: DatabaseBackend, - // Authorizes the request for SAME-INSTANCE - _authorized_instance: AuthorizedInstance, -) -> LocalBoxFuture<'static, Result>> { - async move { - let mut backend = state.user_backend.lock().await; - - backend.register(operation).await.as_internal_error() - } - .boxed_local() + _operation_state: StackOperationState, // Authorizes the request for SAME-INSTANCE + // _authorized_instance: AuthorizedInstance, +) -> Result> { + let mut backend = state.user_backend.lock().await; + + backend + .register(operation.clone()) + .await + .as_internal_error() } -pub fn instance_create_repository_request( - _object: &Instance, +pub async fn instance_create_repository_request( + _object: Instance, operation: RepositoryCreateRequest, state: DatabaseBackend, + _operation_state: StackOperationState, requester: AuthenticatedUser, // Authorizes the request for SAME-INSTANCE - _authorized_instance: AuthorizedInstance, -) -> LocalBoxFuture<'static, Result>> { - async move { - let mut backend = state.repository_backend.lock().await; - - backend - .create_repository(&requester, &operation) - .await - .as_internal_error() - } - .boxed_local() -} - -pub fn user_get_value_display_name( - object: &User, - _operation: GetValueTyped, - _state: DatabaseBackend, - stack: Arc, // _requester: AuthorizedUser, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - stack - .new_get_setting::<_, DisplayName>(&object) - .await - .as_internal_error() - } - .boxed_local() -} - -pub fn user_get_value_bio( - object: &User, - _operation: GetValueTyped, - _state: DatabaseBackend, - stack: Arc, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - stack - .new_get_setting::<_, Bio>(&object) - .await - .as_internal_error() - } - .boxed_local() -} - -pub fn repository_get_value_description( - object: &Repository, - _operation: GetValueTyped, - _state: DatabaseBackend, - stack: Arc, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - stack - .new_get_setting::<_, Description>(&object) - .await - .as_internal_error() - } - .boxed_local() -} - -pub fn repository_get_value_visibility( - object: &Repository, - _operation: GetValueTyped, - _state: DatabaseBackend, - stack: Arc, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - stack - .new_get_setting::<_, Visibility>(&object) - .await - .as_internal_error() - } - .boxed_local() -} - -pub fn repository_get_default_branch( - object: &Repository, - _operation: GetValueTyped, - _state: DatabaseBackend, - stack: Arc, -) -> LocalBoxFuture<'static, Result>> { - let object = object.clone(); - - async move { - stack - .new_get_setting::<_, DefaultBranch>(&object) - .await - .as_internal_error() - } - .boxed_local() -} - -pub fn repository_get_latest_commit( - object: &Repository, - _operation: GetValueTyped, - state: DatabaseBackend, - _stack: Arc, -) -> LocalBoxFuture<'static, Result>> { - let _object = object.clone(); - - async move { - let _backend = state.repository_backend.lock().await; - - // stack - // .new_get_setting::<_, LatestCommit>(&*object) - // .await - // .as_internal_error() - - Ok(LatestCommit(None)) - } - .boxed_local() + // _authorized_instance: AuthorizedInstance, +) -> Result> { + let mut backend = state.repository_backend.lock().await; + + backend + .create_repository(&requester, &operation) + .await + .as_internal_error() } diff --git a/giterated-daemon/src/database_backend/mod.rs b/giterated-daemon/src/database_backend/mod.rs index d34d0c8..ed1d86b 100644 --- a/giterated-daemon/src/database_backend/mod.rs +++ b/giterated-daemon/src/database_backend/mod.rs @@ -5,16 +5,13 @@ use std::any::Any; use std::sync::Arc; use anyhow::Context; -use giterated_models::error::OperationError; + use giterated_models::instance::Instance; -use giterated_models::object::{GiteratedObject, Object, ObjectRequestError}; -use giterated_models::object_backend::ObjectBackend; -use giterated_models::operation::GiteratedOperation; use giterated_models::repository::{DefaultBranch, Description, Repository, Visibility}; use giterated_models::user::{Bio, DisplayName, User}; use giterated_stack::provider::MetadataProvider; -use giterated_stack::{GiteratedStack, ObjectMeta, SubstackBuilder}; -use giterated_stack::{SettingMeta, StackOperationState}; +use giterated_stack::SettingMeta; +use giterated_stack::{AnyObject, AnySetting, GiteratedStack, ObjectMeta, SubstackBuilder}; use serde_json::Value; use sqlx::PgPool; use std::fmt::Debug; @@ -27,37 +24,10 @@ use self::handler::{ instance_authentication_request, instance_create_repository_request, instance_registration_request, repository_commit_before, repository_commit_by_id, repository_diff, repository_diff_patch, repository_file_from_id, repository_file_from_path, - repository_get_branches, repository_get_default_branch, repository_get_latest_commit, - repository_get_statistics, repository_get_value_description, repository_get_value_visibility, - repository_info, repository_last_commit_of_file, user_get_repositories, user_get_value_bio, - user_get_value_display_name, + repository_get_branches, repository_get_statistics, repository_info, + repository_last_commit_of_file, user_get_repositories, }; -#[derive(Clone, Debug)] -pub struct Foobackend {} - -#[async_trait::async_trait(?Send)] -impl ObjectBackend for Foobackend { - async fn object_operation + Debug>( - &self, - _object: O, - _operation: &str, - _payload: D, - _operation_state: &StackOperationState, - ) -> Result> { - // We don't handle operations with this backend - Err(OperationError::Unhandled) - } - - async fn get_object( - &self, - _object_str: &str, - _operation_state: &StackOperationState, - ) -> Result, OperationError> { - Err(OperationError::Unhandled) - } -} - /// A backend implementation which attempts to resolve data from the instance's database. #[derive(Clone)] #[allow(unused)] @@ -105,8 +75,6 @@ impl DatabaseBackend { .value_setting::() .value_setting::(); - builder.value(repository_get_latest_commit); - builder .operation(user_get_repositories) .operation(instance_registration_request) @@ -141,18 +109,18 @@ impl MetadataProvider for DatabaseBackend { async fn write( &self, - object: &(dyn Any + Send + Sync), + object: AnyObject, _object_meta: &ObjectMeta, - setting: &(dyn Any + Send + Sync), + setting: AnySetting, setting_meta: &SettingMeta, ) -> Result<(), anyhow::Error> { - if let Some(repository) = object.downcast_ref::() { + if let Some(repository) = object.0.downcast_ref::() { sqlx::query!("INSERT INTO repository_settings VALUES ($1, $2, $3) ON CONFLICT (repository, name) DO UPDATE SET value = $3", repository.to_string(), setting_meta.name, serde_json::to_string(&(setting_meta.serialize)(setting).unwrap())?) .execute(&self.pool).await?; Ok(()) - } else if let Some(user) = object.downcast_ref::() { + } else if let Some(user) = object.0.downcast_ref::() { sqlx::query!("INSERT INTO user_settings VALUES ($1, $2, $3) ON CONFLICT (username, name) DO UPDATE SET value = $3", user.username, setting_meta.name, serde_json::to_string(&(setting_meta.serialize)(setting).unwrap())?) .execute(&self.pool).await?; @@ -165,11 +133,11 @@ impl MetadataProvider for DatabaseBackend { async fn read( &self, - object: &(dyn Any + Send + Sync), + object: AnyObject, _object_meta: &ObjectMeta, setting_meta: &SettingMeta, ) -> Result { - if let Some(repository) = object.downcast_ref::() { + if let Some(repository) = object.0.downcast_ref::() { let row = sqlx::query_as!( RepositorySettingRow, "SELECT * FROM repository_settings WHERE repository = $1 AND name = $2", @@ -183,7 +151,7 @@ impl MetadataProvider for DatabaseBackend { serde_json::from_str(&row.value).context("deserializing setting from database")?; Ok(setting) - } else if let Some(user) = object.downcast_ref::() { + } else if let Some(user) = object.0.downcast_ref::() { info!("User for {}", setting_meta.name); let row = sqlx::query_as!( UserSettingRow, diff --git a/giterated-models/src/authenticated.rs b/giterated-models/src/authenticated.rs index eb4760a..7510d03 100644 --- a/giterated-models/src/authenticated.rs +++ b/giterated-models/src/authenticated.rs @@ -12,8 +12,8 @@ use serde::{Deserialize, Serialize}; use crate::{ instance::Instance, message::GiteratedMessage, - object::{AnyObject, GiteratedObject}, - operation::{AnyOperation, GiteratedOperation}, + object::{GiteratedObject, NetworkAnyObject}, + operation::{GiteratedOperation, NetworkAnyOperation}, user::User, }; @@ -39,11 +39,11 @@ pub struct AuthenticatedPayload { } impl AuthenticatedPayload { - pub fn into_message(self) -> GiteratedMessage { + pub fn into_message(self) -> GiteratedMessage { GiteratedMessage { - object: AnyObject(self.object), + object: NetworkAnyObject(self.object), operation: self.operation, - payload: AnyOperation(self.payload), + payload: NetworkAnyOperation(self.payload), } } } diff --git a/giterated-models/src/error.rs b/giterated-models/src/error.rs index b056171..c889e80 100644 --- a/giterated-models/src/error.rs +++ b/giterated-models/src/error.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use serde::{Deserialize, Serialize}; -#[derive(Debug, thiserror::Error, Deserialize, Serialize)] +#[derive(Debug, thiserror::Error, Deserialize, Serialize, Clone)] pub enum InstanceError { #[error("registration failed")] RegistrationFailure, @@ -10,19 +10,19 @@ pub enum InstanceError { AuthenticationFailed, } -#[derive(Debug, thiserror::Error, Serialize, Deserialize)] +#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)] pub enum RepositoryError {} -#[derive(Debug, thiserror::Error, Deserialize, Serialize)] +#[derive(Debug, thiserror::Error, Deserialize, Serialize, Clone)] pub enum UserError {} -#[derive(Debug, thiserror::Error, Serialize, Deserialize)] +#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)] pub enum GetValueError { #[error("invalid object")] InvalidObject, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, Clone)] #[error("unauthorized")] pub struct UnauthorizedError; diff --git a/giterated-models/src/message.rs b/giterated-models/src/message.rs index ffd4b09..9c95b19 100644 --- a/giterated-models/src/message.rs +++ b/giterated-models/src/message.rs @@ -1,8 +1,8 @@ use serde::Serialize; use crate::{ - object::{AnyObject, GiteratedObject}, - operation::{AnyOperation, GiteratedOperation}, + object::{GiteratedObject, NetworkAnyObject}, + operation::{GiteratedOperation, NetworkAnyOperation}, }; use std::fmt::Debug; @@ -42,7 +42,7 @@ mod string { } } -impl GiteratedMessage { +impl GiteratedMessage { pub fn try_into>( &self, ) -> Result, ()> { diff --git a/giterated-models/src/object.rs b/giterated-models/src/object.rs index d419efc..cae9377 100644 --- a/giterated-models/src/object.rs +++ b/giterated-models/src/object.rs @@ -10,8 +10,8 @@ use crate::{ error::{GetValueError, OperationError}, object_backend::ObjectBackend, operation::GiteratedOperation, - settings::{AnySetting, GetSetting, GetSettingError, SetSetting, SetSettingError, Setting}, - value::{GetValueTyped, GiteratedObjectValue}, + settings::{GetSetting, GetSettingError, SetSetting, SetSettingError, Setting}, + value::{GetValue, GiteratedObjectValue}, }; mod operations; @@ -75,15 +75,15 @@ impl< ) -> Result> { let result = self .request( - GetValueTyped:: { + GetValue { value_name: V::value_name().to_string(), - ty: Default::default(), }, operation_state, ) - .await; + .await + .unwrap(); - Ok(result?) + Ok(serde_json::from_value(result).unwrap()) } pub async fn get_setting( @@ -108,7 +108,7 @@ impl< self.request( SetSetting { setting_name: S::name().to_string(), - value: AnySetting(serde_json::to_value(setting).unwrap()), + value: serde_json::to_value(setting).unwrap(), }, operation_state, ) @@ -119,7 +119,11 @@ impl< &mut self, request: R, operation_state: &I, - ) -> Result> { + ) -> Result> + where + R::Success: Clone, + R::Failure: Clone, + { self.backend .object_operation( self.inner.clone(), diff --git a/giterated-models/src/object/operations.rs b/giterated-models/src/object/operations.rs index 9080d4d..532983e 100644 --- a/giterated-models/src/object/operations.rs +++ b/giterated-models/src/object/operations.rs @@ -9,7 +9,7 @@ use super::GiteratedObject; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ObjectRequest(pub String); -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] pub struct ObjectResponse(pub String); impl GiteratedOperation for ObjectRequest { @@ -18,7 +18,7 @@ impl GiteratedOperation for ObjectRequest { type Failure = ObjectRequestError; } -#[derive(Debug, thiserror::Error, Serialize, Deserialize)] +#[derive(Debug, Clone, thiserror::Error, Serialize, Deserialize)] pub enum ObjectRequestError { #[error("error decoding the object")] Deserialization(String), @@ -27,9 +27,9 @@ pub enum ObjectRequestError { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(transparent)] #[repr(transparent)] -pub struct AnyObject(pub String); +pub struct NetworkAnyObject(pub String); -impl GiteratedObject for AnyObject { +impl GiteratedObject for NetworkAnyObject { fn object_name() -> &'static str { "any" } @@ -39,13 +39,13 @@ impl GiteratedObject for AnyObject { } } -impl Display for AnyObject { +impl Display for NetworkAnyObject { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0) } } -impl FromStr for AnyObject { +impl FromStr for NetworkAnyObject { type Err = Infallible; fn from_str(s: &str) -> Result { diff --git a/giterated-models/src/object_backend.rs b/giterated-models/src/object_backend.rs index d231a2e..dc616a4 100644 --- a/giterated-models/src/object_backend.rs +++ b/giterated-models/src/object_backend.rs @@ -17,7 +17,9 @@ pub trait ObjectBackend: Sized + Clone + Send { ) -> Result> where O: GiteratedObject + Debug + 'static, - D: GiteratedOperation + Debug + 'static; + D: GiteratedOperation + Debug + 'static, + D::Success: Clone, + D::Failure: Clone; async fn get_object( &self, diff --git a/giterated-models/src/operation.rs b/giterated-models/src/operation.rs index ab1f443..911a7c3 100644 --- a/giterated-models/src/operation.rs +++ b/giterated-models/src/operation.rs @@ -18,9 +18,9 @@ pub trait GiteratedOperation: #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(transparent)] #[repr(transparent)] -pub struct AnyOperation(pub Vec); +pub struct NetworkAnyOperation(pub Vec); -impl GiteratedOperation for AnyOperation { +impl GiteratedOperation for NetworkAnyOperation { type Success = Vec; type Failure = Vec; diff --git a/giterated-models/src/settings/mod.rs b/giterated-models/src/settings/mod.rs index 39e95e5..78c416d 100644 --- a/giterated-models/src/settings/mod.rs +++ b/giterated-models/src/settings/mod.rs @@ -1,18 +1,13 @@ mod operations; +use std::{any::Any, sync::Arc}; + pub use operations::*; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json::Value; +use serde::{de::DeserializeOwned, Serialize}; pub trait Setting: Serialize + DeserializeOwned + Send + Sync { fn name() -> &'static str; } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AnySetting(pub Value); - -impl Setting for AnySetting { - fn name() -> &'static str { - "any" - } -} +#[derive(Debug, Clone)] +pub struct AnySetting(pub Arc); diff --git a/giterated-models/src/settings/operations.rs b/giterated-models/src/settings/operations.rs index 3adf3b7..caabcac 100644 --- a/giterated-models/src/settings/operations.rs +++ b/giterated-models/src/settings/operations.rs @@ -6,8 +6,6 @@ use thiserror::Error; use crate::{object::GiteratedObject, operation::GiteratedOperation}; -use super::AnySetting; - #[derive(Serialize, Deserialize, Debug, Clone)] pub struct GetSetting { pub setting_name: String, @@ -23,12 +21,12 @@ impl GiteratedOperation for GetSetting { type Failure = GetSettingError; } -#[derive(Error, Debug, Serialize, Deserialize)] +#[derive(Error, Debug, Serialize, Deserialize, Clone)] pub enum GetSettingError {} #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SetSetting { pub setting_name: String, - pub value: AnySetting, + pub value: Value, } impl GiteratedOperation for SetSetting { @@ -41,5 +39,5 @@ impl GiteratedOperation for SetSetting { type Failure = SetSettingError; } -#[derive(Error, Debug, Serialize, Deserialize)] +#[derive(Error, Debug, Serialize, Deserialize, Clone)] pub enum SetSettingError {} diff --git a/giterated-models/src/value.rs b/giterated-models/src/value.rs index f501620..5a566e9 100644 --- a/giterated-models/src/value.rs +++ b/giterated-models/src/value.rs @@ -26,7 +26,6 @@ impl GiteratedOperation for GetValue { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct GetValueTyped { - pub value_name: String, pub ty: PhantomData, } diff --git a/giterated-stack/src/handler.rs b/giterated-stack/src/handler.rs deleted file mode 100644 index 73229af..0000000 --- a/giterated-stack/src/handler.rs +++ /dev/null @@ -1,1272 +0,0 @@ -use std::{any::Any, collections::HashMap, sync::Arc}; - -use futures_util::FutureExt; -use giterated_models::{ - authenticated::AuthenticatedPayload, - error::{GetValueError, IntoInternalError, OperationError}, - instance::Instance, - message::GiteratedMessage, - object::{ - AnyObject, GiteratedObject, Object, ObjectRequest, ObjectRequestError, ObjectResponse, - }, - object_backend::ObjectBackend, - operation::{AnyOperation, GiteratedOperation}, - settings::{GetSetting, GetSettingError, SetSetting, Setting}, - value::{AnyValue, GetValue, GetValueTyped, GiteratedObjectValue}, -}; - -use serde::{Deserialize, Serialize}; -use tracing::trace; - -use crate::{ - provider::MetadataProvider, GiteratedOperationHandler, MissingValue, ObjectMeta, - ObjectOperationPair, ObjectSettingPair, ObjectValuePair, OperationMeta, OperationWrapper, - SettingMeta, SettingUpdate, StackOperationState, ValueMeta, -}; - -/// Temporary name for the next generation of Giterated stack -#[derive(Default)] -pub struct GiteratedStack { - operation_handlers: HashMap, - value_getters: HashMap, - setting_getters: HashMap, - value_change: HashMap, - setting_change: HashMap, - metadata_providers: Vec>, - metadata: RuntimeMetadata, -} - -impl Debug for GiteratedStack { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("GiteratedStack").finish() - } -} - -#[derive(Clone)] -pub struct ValueChangeEvent(Arc); - -impl GiteratedStack { - pub fn merge_builder( - &mut self, - mut builder: SubstackBuilder, - ) -> &mut Self { - for (target, handler) in builder.operation_handlers { - let tree = self.get_or_create_tree(&target); - - tree.push(handler); - } - - for (target, handler) in builder.value_getters { - assert!(self.value_getters.insert(target, handler).is_none()); - } - - for (target, handler) in builder.setting_getters { - assert!(self.setting_getters.insert(target, handler).is_none()); - } - - for (target, handler) in builder.value_change { - self.value_change.insert(target, handler); - } - - for (target, handler) in builder.setting_change { - self.setting_change.insert(target, handler); - } - - self.metadata_providers - .append(&mut builder.metadata_providers); - - self.metadata.append(builder.metadata); - - self - } - - pub async fn value_update( - &self, - object: O, - new_value: V, - operation_state: &StackOperationState, - ) where - O: GiteratedObject + 'static, - V: GiteratedObjectValue + 'static, - { - trace!("value updated {}::{}", O::object_name(), V::value_name()); - let target = ObjectValuePair::from_types::(); - - if let Some(handler) = self.value_change.get(&target) { - // TODO - let _ = handler - .handle( - &(Box::new(object) as _), - &(Box::new(ValueChangedShim { new_value }) as _), - operation_state, - ) - .await; - } - } - - pub async fn setting_update( - &self, - object: O, - new_setting: S, - operation_state: &StackOperationState, - ) where - O: GiteratedObject + 'static, - S: Setting + 'static, - { - trace!("setting updated {}::{}", O::object_name(), S::name()); - let target = ObjectSettingPair::from_types::(); - - if let Some(handler) = self.setting_change.get(&target) { - let _ = handler - .handle( - &(Box::new(object) as _), - &(Box::new(SettingUpdate(new_setting)) as _), - operation_state, - ) - .await; - } - } - - pub async fn new_object(&self, _new_object: &O, _operation_state: &StackOperationState) - where - O: GiteratedObject, - { - // TODO - } - - /// Writes a setting for the specified object. - pub async fn write_setting( - &self, - object: &O, - setting: S, - ) -> Result<(), OperationError<()>> - where - O: GiteratedObject + 'static, - S: Setting + 'static + Clone, - { - for provider in self.metadata_providers.iter() { - if provider.provides_for(object as &dyn Any) { - let setting_meta = self - .metadata - .settings - .get(&ObjectSettingPair { - object_kind: O::object_name().to_string(), - setting_name: S::name().to_string(), - }) - .ok_or_else(|| OperationError::Unhandled)?; - - let object_meta = self - .metadata - .objects - .get(O::object_name()) - .ok_or_else(|| OperationError::Unhandled)?; - - let result = provider - .write(object, object_meta, &setting, setting_meta) - .await - .as_internal_error_with_context(format!("writing setting {}", S::name())); - - return result; - } - } - - Err(OperationError::Unhandled) - } - - /// Gets a setting for the specified object. - pub async fn new_get_setting(&self, object: &O) -> Result> - where - O: GiteratedObject + 'static, - S: Setting + 'static, - { - for provider in self.metadata_providers.iter() { - if provider.provides_for(object as &dyn Any) { - trace!( - "Resolving setting {} for object {} from provider.", - S::name(), - O::object_name() - ); - - let setting_meta = self - .metadata - .settings - .get(&ObjectSettingPair { - object_kind: O::object_name().to_string(), - setting_name: S::name().to_string(), - }) - .ok_or_else(|| OperationError::Unhandled)?; - - let object_meta = self - .metadata - .objects - .get(O::object_name()) - .ok_or_else(|| OperationError::Unhandled)?; - - let value = provider - .read(object, object_meta, setting_meta) - .await - .as_internal_error_with_context(format!("getting setting {}", S::name()))?; - - return serde_json::from_value(value) - .as_internal_error_with_context("deserializing setting"); - } - } - trace!( - "No provider registered for setting {} and object {}", - S::name(), - O::object_name() - ); - - Err(OperationError::Unhandled) - } - - fn get_or_create_tree(&mut self, target: &ObjectOperationPair) -> &mut HandlerTree { - if self.operation_handlers.contains_key(target) { - self.operation_handlers.get_mut(target).unwrap() - } else { - self.operation_handlers - .insert(target.clone(), HandlerTree::default()); - - self.operation_handlers.get_mut(target).unwrap() - } - } -} - -#[derive(Default)] -pub struct HandlerTree { - elements: Vec, -} - -impl HandlerTree { - pub fn push(&mut self, handler: OperationWrapper) { - self.elements.push(handler); - } - - pub async fn handle( - &self, - object: &Box, - operation: &Box, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - for handler in self.elements.iter() { - match handler.handle(object, operation, operation_state).await { - Ok(success) => return Ok(success), - Err(err) => match err { - OperationError::Operation(failure) => { - return Err(OperationError::Operation(failure)) - } - OperationError::Internal(e) => return Err(OperationError::Internal(e)), - _ => { - continue; - } - }, - } - } - - Err(OperationError::Unhandled) - } -} - -/// Stores runtime metadata for all in-use Giterated protocol types. -#[derive(Default)] -struct RuntimeMetadata { - objects: HashMap, - operations: HashMap, - values: HashMap, - settings: HashMap, -} - -/// Defines a type that is a valid Giterated runtime state. -/// -/// This allows for extraction of state in handlers, based on a -/// [`FromOperationState`] impl on (what is in this case) [`Self`]. -pub trait GiteratedStackState: Send + Sync + Clone {} - -impl GiteratedStackState for T {} - -pub struct SubstackBuilder { - operation_handlers: HashMap, - value_getters: HashMap, - setting_getters: HashMap, - metadata: RuntimeMetadata, - value_change: HashMap, - metadata_providers: Vec>, - setting_change: HashMap, - - state: S, -} - -impl SubstackBuilder { - pub fn new(state: S) -> Self { - Self { - operation_handlers: Default::default(), - value_getters: Default::default(), - setting_getters: Default::default(), - metadata: Default::default(), - value_change: Default::default(), - metadata_providers: Default::default(), - setting_change: Default::default(), - state, - } - } -} - -impl SubstackBuilder { - /// Insert an operation handler into the runtime builder. - /// - /// # Type Registration - /// Inserting the handler will automatically, if required, register the operation type of the - /// handler. It will **not** register the object type automatically. - pub fn operation(&mut self, handler: H) -> &mut Self - where - O: GiteratedObject + 'static, - D: GiteratedOperation + 'static + Clone, - H: GiteratedOperationHandler + 'static + Clone + Send + Sync, - D::Failure: Send + Sync, - D::Success: Send + Sync, - { - let object_name = handler.object_name().to_string(); - let operation_name = handler.operation_name().to_string(); - - let wrapped = OperationWrapper::new(handler, self.state.clone()); - - let pair = ObjectOperationPair { - object_name, - operation_name, - }; - - self.operation_handlers.insert(pair, wrapped); - - self.metadata.register_operation::(); - - self - } - - /// Register a [`GiteratedObject`] type with the runtime. - /// - /// # Type Registration - /// This will register the provided object type. - pub fn object(&mut self) -> &mut Self { - self.metadata.register_object::(); - - // Insert handler so ObjectRequest is handled properly - let handler = move |_object: &Instance, - operation: ObjectRequest, - _state: S, - _operation_state: StackOperationState, - stack: Arc| { - async move { - for (_object_name, object_meta) in stack.metadata.objects.iter() { - if (object_meta.from_str)(&operation.0).is_ok() { - return Ok(ObjectResponse(operation.0)); - } - } - - Err(OperationError::Unhandled) - } - .boxed_local() - }; - - self.operation(handler); - - self - } - - /// Register a [`Setting`] type with the runtime. - /// - /// # Type Registration - /// This will register the provided setting type. - pub fn setting(&mut self) -> &mut Self { - self.metadata.register_setting::(); - - self - } - - /// Register a [`GiteratedObjectValue`] that is also a [`Setting`], which - /// allows for automatic value updates. - pub fn value_setting< - O: GiteratedObject + 'static + Clone, - T: GiteratedObjectValue + Setting + 'static + Clone, - >( - &mut self, - ) -> &mut Self { - self.metadata.register_setting::(); - self.metadata.register_value::(); - - self.setting_change.insert( - ObjectSettingPair { - object_kind: O::object_name().to_string(), - setting_name: T::name().to_string(), - }, - OperationWrapper::new( - move |object: &O, - setting: SettingUpdate, - _state: (), - operation_state: StackOperationState, - stack: Arc| { - trace!( - "value setting updated {}::{}", - O::object_name(), - T::value_name() - ); - let object = object.clone(); - async move { - stack - .value_update(object, setting.0, &operation_state) - .await; - Ok(()) - } - .boxed_local() - }, - (), - ), - ); - - let wrapped = OperationWrapper::new( - |object: &O, - operation: GetValueTyped, - state: _, - operation_state: StackOperationState, - stack: Arc| { - let object = object.clone(); - async move { - match stack - .get_setting( - Box::new(object.clone()) as _, - O::object_name().to_string(), - GetSetting { - setting_name: T::name().to_string(), - }, - &operation_state, - ) - .await - { - Ok(setting) => Ok(*setting.downcast::().unwrap()), - Err(err) => { - panic!("Error: {:?}", err); - } - } - } - .boxed_local() - }, - self.state.clone(), - ); - - self.value_getters.insert( - ObjectValuePair { - object_kind: O::object_name().to_string(), - value_kind: T::value_name().to_string(), - }, - wrapped, - ); - - self - } - - /// Register a [`GiteratedObjectValue`] type with the runtime, providing - /// its associated handler for [`GetValue`]. - /// - /// # Type Registration - /// This will register the provided [`GiteratedObjectValue`] type for its matching / specified - /// object type. It will **not** register the object type automatically. - pub fn value(&mut self, handler: F) -> &mut Self - where - O: GiteratedObject + 'static, - V: GiteratedObjectValue + 'static + Clone, - F: GiteratedOperationHandler, S> + Clone + 'static + Send + Sync, - { - let object_name = handler.object_name().to_string(); - let value_name = V::value_name().to_string(); - - let wrapped = OperationWrapper::new(handler, self.state.clone()); - - let handler_object_name = object_name.clone(); - let handler_value_name = value_name.clone(); - - // Insert handler so GetValue is handled properly - let _handler = move |object: &O, - operation: GetValueTyped>, - _state: S, - operation_state: StackOperationState, - stack: Arc| { - let stack = stack; - let object_name = handler_object_name; - let value_name = handler_value_name; - let object = object.clone(); - async move { - for (target, getter) in stack.value_getters.iter() { - if target.object_kind != object_name { - continue; - } - - if target.value_kind != value_name { - continue; - } - - return match getter - .handle( - &(Box::new(object.clone()) as Box), - &(Box::new(GetValueTyped:: { - value_name: operation.value_name, - ty: Default::default(), - }) as Box), - &operation_state, - ) - .await { - Ok(success) => Ok(*success.downcast::< as GiteratedOperation>::Success>().unwrap()), - Err(err) => Err(match err { - OperationError::Operation(failure) => OperationError::Operation(*failure.downcast::< as GiteratedOperation>::Failure>().unwrap()), - OperationError::Internal(internal) => OperationError::Internal(internal), - OperationError::Unhandled => OperationError::Unhandled, - }), - } - } - - Err(OperationError::Unhandled) - } - .boxed_local() - }; - - assert!(self - .value_getters - .insert( - ObjectValuePair { - object_kind: object_name, - value_kind: value_name - }, - wrapped - ) - .is_none()); - - self.metadata.register_value::(); - - self - } - - /// Register a handler for [`GetSetting`] for it's associated object type. - pub fn object_settings(&mut self, handler: F) -> &mut Self - where - O: GiteratedObject + 'static, - F: GiteratedOperationHandler + Clone + 'static + Send + Sync, - { - let object_name = handler.object_name().to_string(); - - let wrapped = OperationWrapper::new(handler, self.state.clone()); - - assert!(self.setting_getters.insert(object_name, wrapped).is_none()); - - self - } - - pub fn value_change(&mut self, handler: F) -> &mut Self - where - O: GiteratedObject + 'static, - F: GiteratedOperationHandler, S> + Clone + 'static + Send + Sync, - V: GiteratedObjectValue + Clone + 'static, - { - let object_name = handler.object_name().to_string(); - - let wrapped = OperationWrapper::new(handler, self.state.clone()); - - assert!(self.setting_getters.insert(object_name, wrapped).is_none()); - - self - } - - pub fn object_metadata_provider(&mut self, provider: Box) -> &mut Self { - self.metadata_providers.push(provider); - - self - } -} - -#[derive(Serialize, Deserialize, Clone)] -pub struct ValueChangedShim { - new_value: V, -} - -impl GiteratedOperation for ValueChangedShim -where - O: GiteratedObject, - V: GiteratedObjectValue, -{ - type Success = V; - - type Failure = MissingValue; -} - -impl RuntimeMetadata { - fn register_object(&mut self) { - let object_name = O::object_name().to_string(); - - let object_meta = ObjectMeta::new::(); - - if self.objects.insert(object_name, object_meta).is_some() { - trace!( - "Registration of object {} overwrote previous registration.", - O::object_name() - ); - } else { - trace!("Registration of object {}.", O::object_name()) - } - } - - fn register_operation + 'static>( - &mut self, - ) { - let object_name = O::object_name().to_string(); - let operation_name = D::operation_name().to_string(); - - if self - .operations - .insert( - ObjectOperationPair { - object_name: object_name, - operation_name: operation_name, - }, - OperationMeta::new::(), - ) - .is_some() - { - trace!( - "Registration of object operation {}<{}> overwrote previous registration.", - D::operation_name(), - O::object_name() - ); - } else { - trace!( - "Registration of object operation {}<{}>.", - D::operation_name(), - O::object_name() - ) - } - } - - fn register_value< - O: GiteratedObject + 'static, - V: GiteratedObjectValue + 'static, - >( - &mut self, - ) { - let object_name = O::object_name().to_string(); - let value_name = V::value_name().to_string(); - - if self - .values - .insert( - ObjectValuePair { - object_kind: object_name, - value_kind: value_name, - }, - ValueMeta::new::(), - ) - .is_some() - { - trace!( - "Registration of value <{}>::{} overwrote previous registration.", - O::object_name(), - V::value_name() - ); - } else { - trace!( - "Registration of value <{}>::{}.", - O::object_name(), - V::value_name() - ); - } - } - - fn register_setting(&mut self) { - if self - .settings - .insert( - ObjectSettingPair { - object_kind: O::object_name().to_string(), - setting_name: S::name().to_string(), - }, - SettingMeta::new::(), - ) - .is_some() - { - trace!( - "Registration of setting {} overwrote previous registration.", - S::name() - ); - } else { - trace!("Registration of setting {}.", S::name()); - } - } - - fn append(&mut self, other: Self) { - self.objects.extend(other.objects); - self.operations.extend(other.operations); - self.values.extend(other.values); - self.settings.extend(other.settings); - } -} -impl GiteratedStack { - /// Handles a giterated network message, returning either a raw success - /// payload or a serialized error payload. - pub async fn handle_network_message( - &self, - message: AuthenticatedPayload, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - let message: GiteratedMessage = message.into_message(); - - // Deserialize the object, also getting the object type's name - let (object_type, object) = { - let mut result = None; - - for (object_type, object_meta) in self.metadata.objects.iter() { - if let Ok(object) = (object_meta.from_str)(&message.object.0) { - result = Some((object_type.clone(), object)); - break; - } - } - - result - } - .ok_or_else(|| OperationError::Unhandled)?; - - trace!( - "Handling network message {}::<{}>", - message.operation, - object_type - ); - - if message.operation == "get_value" { - // Special case - let operation: GetValue = serde_json::from_slice(&message.payload.0).unwrap(); - - let result = self - .network_get_value( - object, - object_type.clone(), - operation.clone(), - operation_state, - ) - .await; - - // In the case of internal errors, attach context - let result = result.map_err(|err| match err { - OperationError::Operation(operation) => OperationError::Operation(operation), - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "{}::get_value::<{}> outcome", - object_type, operation.value_name - ))) - } - OperationError::Unhandled => OperationError::Unhandled, - }); - - return result; - } else if message.operation == "get_setting" { - let operation: GetSetting = serde_json::from_slice(&message.payload.0).unwrap(); - let setting_meta = self - .metadata - .settings - .get(&ObjectSettingPair { - object_kind: object_type.clone(), - setting_name: operation.setting_name.clone(), - }) - .ok_or_else(|| OperationError::Unhandled)?; - let raw_result = self - .get_setting(object, object_type.clone(), operation, operation_state) - .await; - return match raw_result { - Ok(success) => { - // Success is the setting type, serialize it - let serialized = (setting_meta.serialize)(&(*success)).unwrap(); - - Ok(serde_json::to_vec(&serialized).unwrap()) - } - Err(err) => Err(match err { - OperationError::Operation(failure) => { - // We know how to resolve this type - let failure: GetSettingError = *failure.downcast().unwrap(); - - OperationError::Operation(serde_json::to_vec(&failure).unwrap()) - } - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "{}::get_setting::<{}> handler outcome", - object_type, setting_meta.name - ))) - } - OperationError::Unhandled => OperationError::Unhandled, - }), - }; - } else if message.operation == "set_setting" { - let operation: SetSetting = serde_json::from_slice(&message.payload.0).unwrap(); - - trace!( - "Handling network {}::set_setting for {}", - object_type, - operation.setting_name - ); - - let setting_meta = self - .metadata - .settings - .get(&ObjectSettingPair { - object_kind: object_type.clone(), - setting_name: operation.setting_name.clone(), - }) - .unwrap(); - - let setting = (setting_meta.deserialize)(operation.value.0) - .as_internal_error_with_context(format!( - "deserializing setting {} for object {}", - operation.setting_name, object_type - ))?; - - trace!( - "Deserialized setting {} for object {}", - operation.setting_name, - object_type, - ); - - for provider in self.metadata_providers.iter() { - if provider.provides_for(object.as_ref()) { - trace!( - "Resolved setting provider for setting {} for object {}", - operation.setting_name, - object_type, - ); - - let object_meta = self - .metadata - .objects - .get(&object_type) - .ok_or_else(|| OperationError::Unhandled)?; - - let raw_result = provider - .write(&(*object), object_meta, &(*setting), setting_meta) - .await; - - return match raw_result { - Ok(_) => { - (setting_meta.setting_updated)( - object, - setting, - operation_state.runtime.clone(), - operation_state, - ) - .await; - - Ok(serde_json::to_vec(&()).unwrap()) - } - Err(e) => Err(OperationError::Internal(e.context(format!( - "writing object {} setting {}", - object_type, operation.setting_name - )))), - }; - } - - trace!( - "Failed to resolve setting provider for setting {} for object {}", - operation.setting_name, - object_type, - ); - } - } - - let target = ObjectOperationPair { - object_name: object_type.clone(), - operation_name: message.operation.clone(), - }; - - // Resolve the target operations from the handlers table - let handler = self - .operation_handlers - .get(&target) - .ok_or_else(|| OperationError::Unhandled)?; - - trace!( - "Resolved operation handler for network message {}::<{}>", - message.operation, - object_type - ); - - // Deserialize the operation - let meta = self - .metadata - .operations - .get(&target) - .ok_or_else(|| OperationError::Unhandled)?; - - let operation = - (meta.deserialize)(&message.payload.0).as_internal_error_with_context(format!( - "deserializing operation {}::{}", - target.object_name, target.operation_name - ))?; - - trace!( - "Deserialized operation for network message {}::<{}>", - message.operation, - object_type - ); - - trace!( - "Calling handler for network message {}::<{}>", - message.operation, - object_type - ); - - // Get the raw result of the operation, where the return values are boxed. - let raw_result = handler.handle(&object, &operation, operation_state).await; - - trace!( - "Finished handling network message {}::<{}>", - message.operation, - object_type - ); - - // Deserialize the raw result for the network - match raw_result { - Ok(success) => Ok((meta.serialize_success)(success).as_internal_error()?), - Err(err) => Err(match err { - OperationError::Operation(failure) => { - OperationError::Operation((meta.serialize_error)(failure).as_internal_error()?) - } - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "operation {}::{} handler outcome", - target.object_name, target.operation_name - ))) - } - OperationError::Unhandled => OperationError::Unhandled, - }), - } - } - - pub async fn network_get_value( - &self, - object: Box, - object_kind: String, - operation: GetValue, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - trace!("Handling network get_value for {}", operation.value_name); - - let value_meta = self - .metadata - .values - .get(&ObjectValuePair { - object_kind: object_kind.clone(), - value_kind: operation.value_name.clone(), - }) - .ok_or_else(|| OperationError::Unhandled)?; - - for (target, getter) in self.value_getters.iter() { - if target.object_kind != object_kind { - continue; - } - - if target.value_kind != operation.value_name { - continue; - } - - return match getter - .handle(&(object), &((value_meta.typed_get)()), operation_state) - .await - { - Ok(success) => { - // Serialize success, which is the value type itself - let serialized = (value_meta.serialize)(success).as_internal_error()?; - - Ok(serialized) - } - Err(err) => Err(match err { - OperationError::Operation(failure) => { - // Failure is sourced from GetValue operation, but this is hardcoded for now - let failure: GetValueError = *failure.downcast().unwrap(); - - OperationError::Operation(serde_json::to_vec(&failure).as_internal_error()?) - } - OperationError::Internal(internal) => OperationError::Internal(internal), - OperationError::Unhandled => OperationError::Unhandled, - }), - }; - } - - Err(OperationError::Unhandled) - } - - pub async fn get_setting( - &self, - object: Box, - object_kind: String, - operation: GetSetting, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - trace!( - "Handling network {}::get_setting for {}", - object_kind, - operation.setting_name - ); - - for provider in self.metadata_providers.iter() { - if provider.provides_for(object.as_ref()) { - let setting_meta = self - .metadata - .settings - .get(&ObjectSettingPair { - object_kind: object_kind.clone(), - setting_name: operation.setting_name.clone(), - }) - .ok_or_else(|| OperationError::Unhandled)?; - - let object_meta = self - .metadata - .objects - .get(&object_kind) - .ok_or_else(|| OperationError::Unhandled)?; - - let result = provider - .read(object.as_ref(), object_meta, setting_meta) - .await - .as_internal_error_with_context(format!( - "reading setting {}", - operation.setting_name - ))?; - - return Ok( - (setting_meta.deserialize)(result).as_internal_error_with_context(format!( - "deserializing setting {}", - operation.setting_name - ))?, - ); - } - } - - todo!() - } - - pub async fn network_set_setting( - &self, - object: Box, - object_kind: String, - operation: SetSetting, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - trace!( - "Handling network {}::set_setting for {}", - object_kind, - operation.setting_name - ); - - let target = ObjectSettingPair { - object_kind: object_kind.clone(), - setting_name: operation.setting_name.clone(), - }; - - let handler = self.setting_change.get(&target).unwrap(); - - let raw_result = handler - .handle(&object, &(Box::new(operation) as _), operation_state) - .await; - - match raw_result { - Ok(_) => { - // Serialize success, which is the value type itself - let serialized = serde_json::to_vec(&()).as_internal_error()?; - - Ok(serialized) - } - Err(err) => Err(match err { - OperationError::Operation(failure) => { - // Failure is sourced from GetValue operation, but this is hardcoded for now - let failure: GetValueError = *failure.downcast().unwrap(); - - OperationError::Operation(serde_json::to_vec(&failure).as_internal_error()?) - } - OperationError::Internal(internal) => OperationError::Internal(internal), - OperationError::Unhandled => OperationError::Unhandled, - }), - } - } -} - -use core::fmt::Debug; - -#[async_trait::async_trait(?Send)] -impl ObjectBackend for Arc { - async fn object_operation( - &self, - in_object: O, - operation_name: &str, - payload: D, - operation_state: &StackOperationState, - ) -> Result> - where - O: GiteratedObject + Debug + 'static, - D: GiteratedOperation + Debug + 'static, - { - // Erase object and operation types. - let object = Box::new(in_object.clone()) as Box; - let operation = Box::new(payload) as Box; - - // We need to hijack get_value, set_setting, and get_setting. - if operation_name == "get_value" { - let mut value_meta = None; - for (_, meta) in self.metadata.values.iter() { - if (meta.is_get_value_typed)(&operation) { - value_meta = Some(meta); - break; - } - } - - let value_meta = value_meta.ok_or_else(|| OperationError::Unhandled)?; - - let value_name = value_meta.name.clone(); - - trace!( - "Handling get_value for {}::{}", - O::object_name(), - value_name - ); - - for (target, getter) in self.value_getters.iter() { - if target.object_kind != O::object_name() { - continue; - } - - if target.value_kind != value_name { - continue; - } - - return match getter - .handle(&(object), &((value_meta.typed_get)()), operation_state) - .await - { - Ok(success) => Ok(*success.downcast().unwrap()), - Err(err) => Err(match err { - OperationError::Operation(failure) => { - OperationError::Operation(*failure.downcast::().unwrap()) - } - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "{}::get_value::<{}> handler outcome", - O::object_name(), - value_name - ))) - } - OperationError::Unhandled => OperationError::Unhandled, - }), - }; - } - - return Err(OperationError::Unhandled); - } else if operation.is::() { - let get_setting: Box = operation.downcast().unwrap(); - let setting_name = get_setting.setting_name.clone(); - - let raw_result = self - .get_setting( - object, - O::object_name().to_string(), - *get_setting, - operation_state, - ) - .await; - - return match raw_result { - Ok(success) => { - // Success is the setting type, serialize it - // let serialized = (setting_meta.serialize)(success).unwrap(); - - // Ok(serde_json::to_vec(&serialized).unwrap()) - Ok(*success.downcast().unwrap()) - } - Err(err) => Err(match err { - OperationError::Operation(failure) => { - // We know this is the right type - OperationError::Operation(*failure.downcast().unwrap()) - } - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "{}::get_setting::<{}> handler outcome", - O::object_name(), - setting_name - ))) - } - OperationError::Unhandled => OperationError::Unhandled, - }), - }; - } else if operation.is::() { - todo!() - } else if operation.is::() { - todo!() - } - - // Resolve the operation from the known operations table. - let operation_type = { - let mut operation_type = None; - - for (target, operation_meta) in self.metadata.operations.iter() { - // Skip elements that we know will not match - if target.object_name != O::object_name() { - continue; - } - - if target.operation_name != operation_name { - continue; - } - - if (operation_meta.any_is_same)(&operation) { - operation_type = Some(target.clone()); - break; - } - } - - operation_type - } - .ok_or_else(|| OperationError::Unhandled)?; - - // Resolve the handler from our handler tree - let handler_tree = self - .operation_handlers - .get(&operation_type) - .ok_or_else(|| OperationError::Unhandled)?; - - let raw_result = handler_tree - .handle(&object, &operation, operation_state) - .await; - - // Convert the dynamic result back into its concrete type - match raw_result { - Ok(result) => Ok(*result.downcast::().unwrap()), - Err(err) => Err(match err { - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "operation {}::{} handler outcome", - operation_type.object_name, operation_type.operation_name - ))) - } - OperationError::Operation(boxed_error) => { - OperationError::Operation(*boxed_error.downcast::().unwrap()) - } - OperationError::Unhandled => OperationError::Unhandled, - }), - } - } - - async fn get_object( - &self, - object_str: &str, - _operation_state: &StackOperationState, - ) -> Result, OperationError> { - // TODO: Authorization? - for (_object_name, object_meta) in self.metadata.objects.iter() { - if let Ok(object) = (object_meta.from_str)(object_str) { - return Ok(unsafe { - Object::new_unchecked(*object.downcast::().unwrap(), self.clone()) - }); - } - } - - Err(OperationError::Unhandled) - } -} diff --git a/giterated-stack/src/handler/handler_impl.rs b/giterated-stack/src/handler/handler_impl.rs new file mode 100644 index 0000000..989f0e3 --- /dev/null +++ b/giterated-stack/src/handler/handler_impl.rs @@ -0,0 +1,272 @@ +use futures_util::Future; +use giterated_models::error::OperationError; + +use crate::{HandlerResolvable, IntoGiteratedHandler}; + +#[async_trait::async_trait(?Send)] +impl + IntoGiteratedHandler<(R1,), (), S, OS, Result>> for H +where + H: FnMut(R1, S, OS) -> Fut + Clone, + Fut: Future>> + 'static, + Success: 'static, + Failure: 'static, + R1: 'static, + S: 'static, + OS: 'static, +{ + type Future = Fut; + + async fn handle( + &self, + parameters: (R1,), + state: S, + operation_state: OS, + ) -> Result> { + let (r1,) = parameters; + (self.clone())(r1, state, operation_state).await + } +} + +#[async_trait::async_trait(?Send)] +impl + IntoGiteratedHandler<(R1,), (A1,), S, OS, Result>> for H +where + H: FnMut(R1, S, OS, A1) -> Fut + Clone, + Fut: Future>> + 'static, + Success: 'static, + Failure: 'static, + R1: 'static, + S: 'static, + OS: 'static, + A1: HandlerResolvable<(R1,), OS>, + A1::Error: Into, +{ + type Future = Fut; + + async fn handle( + &self, + parameters: (R1,), + state: S, + operation_state: OS, + ) -> Result> { + let a1 = A1::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let (r1,) = parameters; + (self.clone())(r1, state, operation_state, a1).await + } +} + +#[async_trait::async_trait(?Send)] +impl + IntoGiteratedHandler<(R1,), (A1, A2), S, OS, Result>> for H +where + H: FnMut(R1, S, OS, A1, A2) -> Fut + Clone, + Fut: Future>> + 'static, + Success: 'static, + Failure: 'static, + R1: 'static, + S: 'static, + OS: 'static, + A1: HandlerResolvable<(R1,), OS>, + A1::Error: Into, + A2: HandlerResolvable<(R1,), OS>, + A2::Error: Into, +{ + type Future = Fut; + + async fn handle( + &self, + parameters: (R1,), + state: S, + operation_state: OS, + ) -> Result> { + let a1 = A1::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let a2 = A2::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let (r1,) = parameters; + (self.clone())(r1, state, operation_state, a1, a2).await + } +} + +#[async_trait::async_trait(?Send)] +impl + IntoGiteratedHandler<(R1,), (A1, A2, A3), S, OS, Result>> for H +where + H: FnMut(R1, S, OS, A1, A2, A3) -> Fut + Clone, + Fut: Future>> + 'static, + Success: 'static, + Failure: 'static, + R1: 'static, + S: 'static, + OS: 'static, + A1: HandlerResolvable<(R1,), OS>, + A1::Error: Into, + A2: HandlerResolvable<(R1,), OS>, + A2::Error: Into, + A3: HandlerResolvable<(R1,), OS>, + A3::Error: Into, +{ + type Future = Fut; + + async fn handle( + &self, + parameters: (R1,), + state: S, + operation_state: OS, + ) -> Result> { + let a1 = A1::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let a2 = A2::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let a3 = A3::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let (r1,) = parameters; + (self.clone())(r1, state, operation_state, a1, a2, a3).await + } +} + +#[async_trait::async_trait(?Send)] +impl + IntoGiteratedHandler<(R1, R2), (), S, OS, Result>> for H +where + H: FnMut(R1, R2, S, OS) -> Fut + Clone, + Fut: Future>> + 'static, + Success: 'static, + Failure: 'static, + R1: 'static, + R2: 'static, + S: 'static, + OS: 'static, +{ + type Future = Fut; + + async fn handle( + &self, + parameters: (R1, R2), + state: S, + operation_state: OS, + ) -> Result> { + let (r1, r2) = parameters; + (self.clone())(r1, r2, state, operation_state).await + } +} + +#[async_trait::async_trait(?Send)] +impl + IntoGiteratedHandler<(R1, R2), (A1,), S, OS, Result>> for H +where + H: FnMut(R1, R2, S, OS, A1) -> Fut + Clone, + Fut: Future>> + 'static, + Success: 'static, + Failure: 'static, + R1: 'static, + R2: 'static, + S: 'static, + OS: 'static, + A1: HandlerResolvable<(R1, R2), OS>, + A1::Error: Into, +{ + type Future = Fut; + + async fn handle( + &self, + parameters: (R1, R2), + state: S, + operation_state: OS, + ) -> Result> { + let a1 = A1::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + + let (r1, r2) = parameters; + (self.clone())(r1, r2, state, operation_state, a1).await + } +} + +#[async_trait::async_trait(?Send)] +impl + IntoGiteratedHandler<(R1, R2), (A1, A2), S, OS, Result>> for H +where + H: FnMut(R1, R2, S, OS, A1, A2) -> Fut + Clone, + Fut: Future>> + 'static, + Success: 'static, + Failure: 'static, + R1: 'static, + R2: 'static, + S: 'static, + OS: 'static, + A1: HandlerResolvable<(R1, R2), OS>, + A1::Error: Into, + A2: HandlerResolvable<(R1, R2), OS>, + A2::Error: Into, +{ + type Future = Fut; + + async fn handle( + &self, + parameters: (R1, R2), + state: S, + operation_state: OS, + ) -> Result> { + let a1 = A1::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let a2 = A2::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + + let (r1, r2) = parameters; + (self.clone())(r1, r2, state, operation_state, a1, a2).await + } +} + +#[async_trait::async_trait(?Send)] +impl + IntoGiteratedHandler<(R1, R2), (A1, A2, A3), S, OS, Result>> + for H +where + H: FnMut(R1, R2, S, OS, A1, A2, A3) -> Fut + Clone, + Fut: Future>> + 'static, + Success: 'static, + Failure: 'static, + R1: 'static, + R2: 'static, + S: 'static, + OS: 'static, + A1: HandlerResolvable<(R1, R2), OS>, + A1::Error: Into, + A2: HandlerResolvable<(R1, R2), OS>, + A2::Error: Into, + A3: HandlerResolvable<(R1, R2), OS>, + A3::Error: Into, +{ + type Future = Fut; + + async fn handle( + &self, + parameters: (R1, R2), + state: S, + operation_state: OS, + ) -> Result> { + let a1 = A1::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let a2 = A2::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + let a3 = A3::from_handler_state(¶meters, &operation_state) + .await + .map_err(|e| OperationError::Internal(e.into()))?; + + let (r1, r2) = parameters; + (self.clone())(r1, r2, state, operation_state, a1, a2, a3).await + } +} diff --git a/giterated-stack/src/handler/mod.rs b/giterated-stack/src/handler/mod.rs new file mode 100644 index 0000000..5a2d173 --- /dev/null +++ b/giterated-stack/src/handler/mod.rs @@ -0,0 +1,239 @@ +use std::{any::Any, sync::Arc}; +pub mod handler_impl; +use futures_util::{future::LocalBoxFuture, Future, FutureExt}; +use giterated_models::error::OperationError; + +use crate::{ + AuthenticatedInstance, AuthenticatedUser, GiteratedStack, MissingValue, StackOperationState, +}; + +#[async_trait::async_trait(?Send)] +pub trait IntoGiteratedHandler +where + // Output cannot have non-static references + Output: 'static, +{ + type Future: Future; + + async fn handle(&self, parameters: Params, state: State, operation_state: OState) -> Output; +} + +pub struct HandlerTree { + elements: Vec, +} + +impl Default for HandlerTree { + fn default() -> Self { + Self { + elements: Default::default(), + } + } +} + +impl<'fut: 'o + 'p, 'p, 'o, P, O, E> HandlerTree> +where + P: Clone, +{ + pub fn push(&mut self, handler: HandlerWrapper) { + self.elements.push(handler); + } + pub async fn handle( + &self, + parameters: P, + operation_state: StackOperationState, + ) -> Result> { + for handler in self.elements.iter() { + match handler + .handle(parameters.clone(), operation_state.clone()) + .await + { + Ok(handled) => return Ok(handled), + Err(err) => match err { + OperationError::Internal(err) => return Err(OperationError::Internal(err)), + OperationError::Operation(err) => return Err(OperationError::Operation(err)), + OperationError::Unhandled => continue, + }, + } + } + + Err(OperationError::Unhandled) + } +} + +pub struct HandlerWrapper { + func: Arc< + dyn Fn( + P, + Arc, + StackOperationState, + ) -> LocalBoxFuture<'static, Result>> + + Send + + Sync, + >, + state: Arc, +} + +impl HandlerWrapper { + pub fn new(state: S, handler: F) -> Self + where + F: IntoGiteratedHandler>> + + Send + + Sync, + S: Send + Sync + Clone + 'static, + E: 'static, + P: 'static + Clone, + F: 'static, + O: 'static, + { + let state = Arc::new(state); + + let handler_func = Arc::new(handler); + let state_two = state.clone(); + HandlerWrapper { + func: Arc::new( + move |args: P, + state: Arc, + operation_state: StackOperationState| { + let handler = handler_func.clone(); + let operation_state = operation_state.clone(); + let state = state.downcast_ref::().unwrap(); + let state = state.clone(); + async move { + let handler = handler.clone(); + let operation_state = operation_state; + handler.handle(args, state, operation_state).await + } + .boxed_local() + }, + ), + state: state_two, + } + } + + pub async fn handle( + &self, + required: P, + operation_state: StackOperationState, + ) -> Result> { + (self.func)(required, self.state.clone(), operation_state).await + } + + pub fn map(self, predicate: F) -> HandlerWrapper + where + F: Fn(&N, &StackOperationState) -> Result> + Clone + Send + Sync, + R: std::fmt::Debug + 'static, + E: Into> + 'static, + F: 'static, + N: 'static, + P: 'static, + O: 'static, + { + let func = Arc::new(self.func); + let predicate = Arc::new(predicate); + HandlerWrapper { + func: Arc::new( + move |args: N, + state: Arc, + operation_state: StackOperationState| { + let predicate_output = predicate(&args, &operation_state); + let func = func.clone(); + let operation_state: StackOperationState = operation_state.clone(); + async move { + let predicate_output = predicate_output?; + let operation_state = operation_state; + match (func)(predicate_output, state, operation_state).await { + Ok(success) => Ok(success), + Err(_) => todo!(), + } + } + .boxed_local() + }, + ), + state: self.state, + } + } + + pub fn map_return(self, predicate: F) -> HandlerWrapper + where + F: Fn(Result>, &StackOperationState) -> Result> + + Clone + + Send + + Sync, + O: 'static, + F: 'static, + E: 'static, + P: 'static, + { + let predicate = Arc::new(predicate); + let func = self.func; + HandlerWrapper { + func: Arc::new( + move |args: P, + state: Arc, + operation_state: StackOperationState| { + let clone = predicate.clone(); + let func = func.clone(); + let _statoperation_statee = operation_state.clone(); + + async move { + let func = func.clone(); + let clone = clone; + let operation_state = operation_state; + clone( + (func)(args, state, operation_state.clone()).await, + &operation_state, + ) + } + .boxed_local() + }, + ), + state: self.state, + } + } +} + +#[async_trait::async_trait(?Send)] +pub trait HandlerResolvable: Sized { + type Error; + + async fn from_handler_state( + required_parameters: &RequiredParameters, + operation_state: &OperationState, + ) -> Result; +} + +#[async_trait::async_trait(?Send)] +impl HandlerResolvable for Arc { + type Error = MissingValue; + + async fn from_handler_state( + _required_parameters: &R, + operation_state: &StackOperationState, + ) -> Result { + Ok(operation_state.runtime.clone()) + } +} + +#[async_trait::async_trait(?Send)] +impl HandlerResolvable for AuthenticatedUser { + type Error = MissingValue; + + async fn from_handler_state( + _required_parameters: &R, + operation_state: &StackOperationState, + ) -> Result { + operation_state.user.clone().ok_or_else(|| MissingValue) + } +} + +#[async_trait::async_trait(?Send)] +impl HandlerResolvable for AuthenticatedInstance { + type Error = MissingValue; + + async fn from_handler_state( + _required_parameters: &R, + operation_state: &StackOperationState, + ) -> Result { + operation_state.instance.clone().ok_or_else(|| MissingValue) + } +} diff --git a/giterated-stack/src/lib.rs b/giterated-stack/src/lib.rs index 676ef9e..523ef00 100644 --- a/giterated-stack/src/lib.rs +++ b/giterated-stack/src/lib.rs @@ -1,18 +1,22 @@ mod handler; +pub use handler::*; mod meta; -pub mod provider; -pub use handler::{GiteratedStack, GiteratedStackState, *}; pub use meta::*; +pub mod provider; +mod stack; +pub use stack::*; +mod substack; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +pub use stack::*; +pub use substack::*; pub mod state; pub mod update; -use std::{any::Any, convert::Infallible, future::Future, ops::Deref, pin::Pin, sync::Arc}; +use std::{any::Any, convert::Infallible, ops::Deref, sync::Arc}; use core::fmt::Debug; -use futures_util::FutureExt; use giterated_models::{ - error::{ExtractorError, IntoInternalError, OperationError, UnauthorizedError}, + error::{ExtractorError, UnauthorizedError}, instance::{ AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest, }, @@ -26,335 +30,52 @@ use giterated_models::{ }; #[derive(Clone, Debug, Hash, Eq, PartialEq)] -struct ObjectOperationPair { - pub object_name: String, - pub operation_name: String, +pub struct ObjectOperationPair<'a> { + pub object_name: &'a str, + pub operation_name: &'a str, } -impl ObjectOperationPair { +impl ObjectOperationPair<'static> { #[allow(unused)] pub fn from_types>() -> Self { Self { - object_name: O::object_name().to_string(), - operation_name: D::operation_name().to_string(), + object_name: O::object_name(), + operation_name: D::operation_name(), } } } #[derive(Clone, Debug, Hash, Eq, PartialEq)] -pub struct ObjectValuePair { - pub object_kind: String, - pub value_kind: String, +pub struct ObjectValuePair<'a> { + pub object_kind: &'a str, + pub value_kind: &'a str, } -impl ObjectValuePair { - pub fn from_types>() -> Self { +impl ObjectValuePair<'static> { + pub fn from_types>() -> Self { Self { - object_kind: O::object_name().to_string(), - value_kind: D::value_name().to_string(), + object_kind: O::object_name(), + value_kind: V::value_name(), } } } #[derive(Clone, Debug, Hash, Eq, PartialEq)] -pub struct ObjectSettingPair { - pub object_kind: String, - pub setting_name: String, +pub struct ObjectSettingPair<'a> { + pub object_kind: &'a str, + pub setting_name: &'a str, } -impl ObjectSettingPair { +impl ObjectSettingPair<'static> { pub fn from_types() -> Self { Self { - object_kind: O::object_name().to_string(), - setting_name: S::name().to_string(), + object_kind: O::object_name(), + setting_name: S::name(), } } } #[async_trait::async_trait(?Send)] -pub trait GiteratedOperationHandler< - L, - O: GiteratedObject, - D: GiteratedOperation, - S: Send + Sync + Clone, -> -{ - fn operation_name(&self) -> &str; - fn object_name(&self) -> &str; - - async fn handle( - &self, - object: &O, - operation: D, - state: S, - operation_state: &StackOperationState, - ) -> Result>; -} - -#[async_trait::async_trait(?Send)] -impl GiteratedOperationHandler<(), O, D, S> for F -where - F: FnMut( - &O, - D, - S, - ) - -> Pin>>>> - + Send - + Sync - + Clone, - O: GiteratedObject + Send + Sync, - D: GiteratedOperation + 'static, - >::Failure: Send, - S: Send + Sync + Clone + 'static, -{ - fn operation_name(&self) -> &str { - D::operation_name() - } - - fn object_name(&self) -> &str { - O::object_name() - } - - async fn handle( - &self, - object: &O, - operation: D, - state: S, - _operation_state: &StackOperationState, - ) -> Result> { - self.clone()(object, operation, state).await - } -} - -#[async_trait::async_trait(?Send)] -impl GiteratedOperationHandler<(O1,), O, D, S> for F -where - F: FnMut( - &O, - D, - S, - O1, - ) - -> Pin>>>> - + Send - + Sync - + Clone, - O: GiteratedObject + Send + Sync, - D: GiteratedOperation + 'static + Send + Sync, - >::Failure: Send, - S: Send + Sync + Clone + 'static, - O1: FromOperationState, - ExtractorError<>::Error>: Into, -{ - fn operation_name(&self) -> &str { - D::operation_name() - } - - fn object_name(&self) -> &str { - O::object_name() - } - - async fn handle( - &self, - object: &O, - operation: D, - state: S, - operation_state: &StackOperationState, - ) -> Result> { - let o1 = O1::from_state(object, &operation, operation_state) - .await - .as_internal_error()?; - self.clone()(object, operation, state, o1).await - } -} - -#[async_trait::async_trait(?Send)] -impl GiteratedOperationHandler<(O1, O2), O, D, S> for F -where - F: FnMut( - &O, - D, - S, - O1, - O2, - ) - -> Pin>>>> - + Send - + Sync - + Clone, - O: GiteratedObject + Send + Sync, - D: GiteratedOperation + 'static + Send + Sync, - >::Failure: Send, - S: Send + Sync + Clone + 'static, - O1: FromOperationState, - ExtractorError<>::Error>: Into, - O2: FromOperationState, - ExtractorError<>::Error>: Into, -{ - fn operation_name(&self) -> &str { - D::operation_name() - } - - fn object_name(&self) -> &str { - O::object_name() - } - - async fn handle( - &self, - object: &O, - operation: D, - state: S, - operation_state: &StackOperationState, - ) -> Result> { - let o1 = O1::from_state(object, &operation, operation_state) - .await - .as_internal_error()?; - let o2 = O2::from_state(object, &operation, operation_state) - .await - .as_internal_error()?; - self.clone()(object, operation, state, o1, o2).await - } -} - -#[async_trait::async_trait(?Send)] -impl GiteratedOperationHandler<(O1, O2, O3), O, D, S> for F -where - F: FnMut( - &O, - D, - S, - O1, - O2, - O3, - ) - -> Pin>>>> - + Send - + Sync - + Clone, - O: GiteratedObject + Send + Sync, - D: GiteratedOperation + 'static + Send + Sync, - >::Failure: Send, - S: Send + Sync + Clone + 'static, - O1: FromOperationState, - ExtractorError<>::Error>: Into, - O2: FromOperationState, - ExtractorError<>::Error>: Into, - O3: FromOperationState, - ExtractorError<>::Error>: Into, -{ - fn operation_name(&self) -> &str { - D::operation_name() - } - - fn object_name(&self) -> &str { - O::object_name() - } - - async fn handle( - &self, - object: &O, - operation: D, - state: S, - operation_state: &StackOperationState, - ) -> Result> { - let o1 = O1::from_state(object, &operation, operation_state) - .await - .as_internal_error()?; - let o2 = O2::from_state(object, &operation, operation_state) - .await - .as_internal_error()?; - let o3 = O3::from_state(object, &operation, operation_state) - .await - .as_internal_error()?; - self.clone()(object, operation, state, o1, o2, o3).await - } -} - -pub struct OperationWrapper { - func: Box< - dyn Fn( - &(dyn Any + Send + Sync), - &(dyn Any + Send + Sync), - &(dyn Any + Send + Sync), - StackOperationState, - ) -> Pin< - Box< - dyn Future< - Output = Result< - Box, - OperationError>, - >, - >, - >, - > + Send - + Sync, - >, - state: Box, -} - -impl OperationWrapper { - pub fn new< - A, - O: GiteratedObject + Send + Sync + 'static, - D: GiteratedOperation + 'static + Clone, - F: GiteratedOperationHandler + 'static + Send + Sync + Clone, - S: GiteratedStackState + 'static, - >( - handler: F, - state: S, - ) -> Self - where - D::Failure: Send + Sync, - D::Success: Send + Sync, - { - Self { - func: Box::new(move |object, operation, state, operation_state| { - let handler = handler.clone(); - let state = state.downcast_ref::().unwrap().clone(); - let object: &O = object.downcast_ref().unwrap(); - let operation: &D = operation.downcast_ref().unwrap(); - let object = object.clone(); - let operation = operation.clone(); - async move { - let result = handler - .handle(&object, operation, state, &operation_state) - .await; - result - .map(|success| Box::new(success) as _) - .map_err(|err| match err { - OperationError::Operation(err) => { - OperationError::Operation(Box::new(err) as _) - } - OperationError::Internal(internal) => { - OperationError::Internal(internal) - } - OperationError::Unhandled => OperationError::Unhandled, - }) - } - .boxed_local() - }), - state: Box::new(state), - } - } - - async fn handle( - &self, - object: &Box, - operation: &Box, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - (self.func)( - (*object).as_ref(), - (*operation).as_ref(), - self.state.as_ref(), - operation_state.clone(), - ) - .await - } -} - -#[async_trait::async_trait(?Send)] pub trait FromOperationState>: Sized + Clone { type Error: Into; @@ -367,21 +88,6 @@ pub trait FromOperationState>: Size #[async_trait::async_trait(?Send)] impl> FromOperationState - for Arc -{ - type Error = Infallible; - - async fn from_state( - _object: &O, - _operation: &D, - state: &StackOperationState, - ) -> Result> { - Ok(state.runtime.clone()) - } -} - -#[async_trait::async_trait(?Send)] -impl> FromOperationState for StackOperationState { type Error = Infallible; @@ -688,15 +394,6 @@ impl + Send + Sync> FromOperationState FromOperationState for Option { -// type Error = (); - -// async fn from_state(state: &StackOperationState) -> Result, OperationError<()>> { -// Ok(T::from_state(] -// impl); + +#[derive(Clone)] +pub struct AnyOperation(pub Arc); + +#[derive(Clone)] +pub struct AnySuccess(pub Arc); + +#[derive(Clone)] +pub struct AnyFailure(pub Arc); + +#[derive(Clone)] +pub struct AnyValue(pub Arc); + +#[derive(Clone)] +pub struct AnySetting(pub Arc); diff --git a/giterated-stack/src/meta/mod.rs b/giterated-stack/src/meta/mod.rs index bfe18cc..f85ef5c 100644 --- a/giterated-stack/src/meta/mod.rs +++ b/giterated-stack/src/meta/mod.rs @@ -1,4 +1,4 @@ -use std::{any::Any, str::FromStr, sync::Arc}; +use std::{any::Any, collections::HashMap, str::FromStr, sync::Arc}; use futures_util::{future::LocalBoxFuture, FutureExt}; use giterated_models::{ @@ -8,23 +8,134 @@ use giterated_models::{ value::{GetValueTyped, GiteratedObjectValue}, }; use serde_json::Value; +use tracing::trace; -use crate::{GiteratedStack, StackOperationState}; +use crate::{ + AnyFailure, AnyObject, AnyOperation, AnySetting, AnySuccess, AnyValue, GiteratedStack, + ObjectOperationPair, ObjectSettingPair, ObjectValuePair, StackOperationState, +}; + +/// Stores runtime metadata for all in-use Giterated protocol types. +#[derive(Default)] +pub struct RuntimeMetadata { + pub objects: HashMap, + pub operations: HashMap, OperationMeta>, + pub values: HashMap, ValueMeta>, + pub settings: HashMap, SettingMeta>, +} + +impl RuntimeMetadata { + pub fn register_object(&mut self) { + let object_name = O::object_name().to_string(); + + let object_meta = ObjectMeta::new::(); + + if self.objects.insert(object_name, object_meta).is_some() { + trace!( + "Registration of object {} overwrote previous registration.", + O::object_name() + ); + } else { + trace!("Registration of object {}.", O::object_name()) + } + } + + pub fn register_operation + 'static>( + &mut self, + ) { + let _object_name = O::object_name().to_string(); + let _operation_name = D::operation_name().to_string(); + + if self + .operations + .insert( + ObjectOperationPair::from_types::(), + OperationMeta::new::(), + ) + .is_some() + { + trace!( + "Registration of object operation {}<{}> overwrote previous registration.", + D::operation_name(), + O::object_name() + ); + } else { + trace!( + "Registration of object operation {}<{}>.", + D::operation_name(), + O::object_name() + ) + } + } + + pub fn register_value< + O: GiteratedObject + 'static, + V: GiteratedObjectValue + 'static, + >( + &mut self, + ) { + let _object_name = O::object_name().to_string(); + let _value_name = V::value_name().to_string(); + + if self + .values + .insert(ObjectValuePair::from_types::(), ValueMeta::new::()) + .is_some() + { + trace!( + "Registration of value <{}>::{} overwrote previous registration.", + O::object_name(), + V::value_name() + ); + } else { + trace!( + "Registration of value <{}>::{}.", + O::object_name(), + V::value_name() + ); + } + } + + pub fn register_setting(&mut self) { + if self + .settings + .insert( + ObjectSettingPair::from_types::(), + SettingMeta::new::(), + ) + .is_some() + { + trace!( + "Registration of setting {} overwrote previous registration.", + S::name() + ); + } else { + trace!("Registration of setting {}.", S::name()); + } + } + + pub fn append(&mut self, other: Self) { + self.objects.extend(other.objects); + self.operations.extend(other.operations); + self.values.extend(other.values); + self.settings.extend(other.settings); + } +} pub struct ValueMeta { pub name: String, - pub deserialize: fn(&[u8]) -> Result, serde_json::Error>, - pub serialize: fn(Box) -> Result, serde_json::Error>, + pub deserialize: fn(&[u8]) -> Result, + pub serialize: fn(AnyValue) -> Result, serde_json::Error>, pub typed_get: fn() -> Box, - pub is_get_value_typed: fn(&Box) -> bool, + pub is_get_value_typed: fn(AnyOperation) -> bool, } pub trait IntoValueMeta { fn name() -> String; - fn deserialize(buffer: &[u8]) -> Result, serde_json::Error>; - fn serialize(value: Box) -> Result, serde_json::Error>; + fn deserialize(buffer: &[u8]) -> Result; + fn serialize(value: AnyValue) -> Result, serde_json::Error>; fn typed_get() -> Box; - fn is_get_value_typed(typed_get_value: &Box) -> bool; + fn is_get_value_typed(typed_get_value: AnyOperation) -> bool; } impl + 'static> IntoValueMeta for V { @@ -32,25 +143,24 @@ impl + 'static> IntoValu V::value_name().to_string() } - fn deserialize(buffer: &[u8]) -> Result, serde_json::Error> { - Ok(Box::new(serde_json::from_slice(buffer)?)) + fn deserialize(buffer: &[u8]) -> Result { + Ok(AnyValue(Arc::new(serde_json::from_slice(buffer)?))) } - fn serialize(value: Box) -> Result, serde_json::Error> { - let value = value.downcast::().unwrap(); + fn serialize(value: AnyValue) -> Result, serde_json::Error> { + let value = value.0.downcast_ref::().unwrap(); serde_json::to_vec(&*value) } fn typed_get() -> Box { Box::new(GetValueTyped:: { - value_name: V::value_name().to_string(), ty: Default::default(), }) } - fn is_get_value_typed(typed_get_value: &Box) -> bool { - typed_get_value.is::>() + fn is_get_value_typed(typed_get_value: AnyOperation) -> bool { + typed_get_value.0.is::>() } } @@ -69,17 +179,17 @@ impl ValueMeta { pub struct OperationMeta { pub name: String, pub object_kind: String, - pub deserialize: fn(&[u8]) -> Result, serde_json::Error>, + pub deserialize: fn(&[u8]) -> Result, pub any_is_same: fn(&dyn Any) -> bool, - pub serialize_success: fn(Box) -> Result, serde_json::Error>, - pub serialize_error: fn(Box) -> Result, serde_json::Error>, + pub serialize_success: fn(AnySuccess) -> Result, serde_json::Error>, + pub serialize_error: fn(AnyFailure) -> Result, serde_json::Error>, } pub trait IntoOperationMeta { fn name() -> String; - fn deserialize(buffer: &[u8]) -> Result, serde_json::Error>; - fn serialize_success(success: Box) -> Result, serde_json::Error>; - fn serialize_failure(failure: Box) -> Result, serde_json::Error>; + fn deserialize(buffer: &[u8]) -> Result; + fn serialize_success(success: AnySuccess) -> Result, serde_json::Error>; + fn serialize_failure(failure: AnyFailure) -> Result, serde_json::Error>; fn any_is_same(other: &dyn Any) -> bool; } @@ -94,17 +204,19 @@ where D::operation_name().to_string() } - fn deserialize(buffer: &[u8]) -> Result, serde_json::Error> { - Ok(Box::new(serde_json::from_slice::(buffer)?) as Box) + fn deserialize(buffer: &[u8]) -> Result { + Ok(AnyOperation( + Arc::new(serde_json::from_slice::(buffer)?) as Arc + )) } - fn serialize_success(success: Box) -> Result, serde_json::Error> { - let to_serialize = success.downcast::().unwrap(); + fn serialize_success(success: AnySuccess) -> Result, serde_json::Error> { + let to_serialize = success.0.downcast_ref::().unwrap(); serde_json::to_vec(&to_serialize) } - fn serialize_failure(failure: Box) -> Result, serde_json::Error> { - let to_serialize = failure.downcast::().unwrap(); + fn serialize_failure(failure: AnyFailure) -> Result, serde_json::Error> { + let to_serialize = failure.0.downcast_ref::().unwrap(); serde_json::to_vec(&to_serialize) } @@ -128,7 +240,7 @@ impl OperationMeta { pub struct ObjectMeta { pub name: String, - pub from_str: Box Result, ()> + Send + Sync>, + pub from_str: Box Result + Send + Sync>, pub any_is_same: fn(&dyn Any) -> bool, } @@ -154,7 +266,7 @@ impl ObjectMeta { from_str: Box::new(|source| { let object = I::from_str(source).map_err(|_| ())?; - Ok(Box::new(object) as Box) + Ok(AnyObject(Arc::new(object) as Arc)) }), any_is_same: I::any_is_same, } @@ -163,11 +275,11 @@ impl ObjectMeta { pub struct SettingMeta { pub name: String, - pub deserialize: fn(Value) -> Result, serde_json::Error>, - pub serialize: fn(&(dyn Any + Send + Sync)) -> Result, + pub deserialize: fn(Value) -> Result, + pub serialize: fn(AnySetting) -> Result, pub setting_updated: for<'fut> fn( - Box, - Box, + AnyObject, + AnySetting, Arc, &StackOperationState, ) -> LocalBoxFuture<'_, ()>, @@ -175,40 +287,40 @@ pub struct SettingMeta { pub trait IntoSettingMeta { fn name() -> String; - fn deserialize(value: Value) -> Result, serde_json::Error>; - fn serialize(setting: &(dyn Any + Send + Sync)) -> Result; + fn deserialize(value: Value) -> Result; + fn serialize(setting: AnySetting) -> Result; fn setting_updated( - object: Box, - setting: Box, + object: AnyObject, + setting: AnySetting, stack: Arc, operation_state: &StackOperationState, ) -> LocalBoxFuture<'_, ()>; } -impl IntoSettingMeta for S { +impl IntoSettingMeta for S { fn name() -> String { S::name().to_string() } - fn deserialize(value: Value) -> Result, serde_json::Error> { - Ok(Box::new(serde_json::from_value::(value)?)) + fn deserialize(value: Value) -> Result { + Ok(AnySetting(Arc::new(serde_json::from_value::(value)?))) } - fn serialize(setting: &(dyn Any + Send + Sync)) -> Result { - serde_json::to_value(setting.downcast_ref::().unwrap()) + fn serialize(setting: AnySetting) -> Result { + serde_json::to_value(setting.0.downcast_ref::().unwrap()) } fn setting_updated( - object: Box, - setting: Box, + object: AnyObject, + setting: AnySetting, stack: Arc, operation_state: &StackOperationState, ) -> LocalBoxFuture<'_, ()> { async move { stack .setting_update( - *object.downcast::().unwrap(), - *setting.downcast::().unwrap(), + object.0.downcast_ref::().unwrap().clone(), + setting.0.downcast_ref::().unwrap().clone(), operation_state, ) .await diff --git a/giterated-stack/src/provider/metadata.rs b/giterated-stack/src/provider/metadata.rs index 4fec98f..451b301 100644 --- a/giterated-stack/src/provider/metadata.rs +++ b/giterated-stack/src/provider/metadata.rs @@ -4,21 +4,21 @@ use anyhow::Error; use serde_json::Value; -use crate::{ObjectMeta, SettingMeta}; +use crate::{AnyObject, AnySetting, ObjectMeta, SettingMeta}; #[async_trait::async_trait] pub trait MetadataProvider: Send + Sync + 'static { fn provides_for(&self, object: &dyn Any) -> bool; async fn write( &self, - object: &(dyn Any + Send + Sync), + object: AnyObject, object_meta: &ObjectMeta, - setting: &(dyn Any + Send + Sync), + setting: AnySetting, setting_meta: &SettingMeta, ) -> Result<(), Error>; async fn read( &self, - object: &(dyn Any + Send + Sync), + object: AnyObject, object_meta: &ObjectMeta, setting_meta: &SettingMeta, ) -> Result; diff --git a/giterated-stack/src/stack.rs b/giterated-stack/src/stack.rs new file mode 100644 index 0000000..4399df9 --- /dev/null +++ b/giterated-stack/src/stack.rs @@ -0,0 +1,865 @@ +use std::any::Any; + +use std::fmt::Debug; +use std::{collections::HashMap, sync::Arc}; + +use giterated_models::authenticated::AuthenticatedPayload; +use giterated_models::error::{GetValueError, IntoInternalError}; +use giterated_models::message::GiteratedMessage; +use giterated_models::object::NetworkAnyObject; +use giterated_models::operation::NetworkAnyOperation; +use giterated_models::settings::{GetSettingError, Setting}; +use giterated_models::value::{GetValue, GiteratedObjectValue}; +use giterated_models::{ + error::OperationError, + object::{GiteratedObject, Object, ObjectRequest, ObjectRequestError}, + object_backend::ObjectBackend, + operation::GiteratedOperation, + settings::{GetSetting, SetSetting}, +}; +use tracing::trace; + +use crate::handler::HandlerTree; +use crate::provider::MetadataProvider; +use crate::{ + AnyFailure, AnyObject, AnyOperation, AnySetting, AnySuccess, AnyValue, HandlerResolvable, + HandlerWrapper, MissingValue, ObjectOperationPair, ObjectSettingPair, ObjectValuePair, + RuntimeMetadata, StackOperationState, SubstackBuilder, +}; + +pub type OperationHandler = HandlerWrapper<(AnyObject, AnyOperation), AnySuccess, AnyFailure>; + +pub type ValueGetter = HandlerWrapper<(AnyObject,), AnyValue, AnyFailure>; + +pub type SettingGetter = HandlerWrapper<(AnyObject,), AnySetting, AnyFailure>; + +pub type ValueChange = HandlerWrapper<(AnyObject, AnyValue), (), anyhow::Error>; + +pub type SettingChange = HandlerWrapper<(AnyObject, AnySetting), (), anyhow::Error>; + +#[derive(Default)] +pub struct GiteratedStack { + operation_handlers: HashMap, HandlerTree>, + value_getters: HashMap, ValueGetter>, + setting_getters: HashMap<&'static str, SettingGetter>, + value_change: HashMap, ValueChange>, + setting_change: HashMap, SettingChange>, + metadata_providers: Vec>, + pub metadata: RuntimeMetadata, +} + +impl Debug for GiteratedStack { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GiteratedStack").finish() + } +} + +impl GiteratedStack { + pub fn merge_builder( + &mut self, + mut builder: SubstackBuilder, + ) -> &mut Self { + for (target, handler) in builder.operation_handlers { + let tree = self.get_or_create_tree(&target); + + tree.push(handler); + } + + for (target, handler) in builder.value_getters { + assert!(self.value_getters.insert(target, handler).is_none()); + } + + for (target, handler) in builder.setting_getters { + assert!(self.setting_getters.insert(target, handler).is_none()); + } + + for (target, handler) in builder.value_change { + self.value_change.insert(target, handler); + } + + for (target, handler) in builder.setting_change { + self.setting_change.insert(target, handler); + } + + self.metadata_providers + .append(&mut builder.metadata_providers); + + self.metadata.append(builder.metadata); + + self + } + + pub async fn value_update( + &self, + object: O, + new_value: V, + operation_state: &StackOperationState, + ) where + O: GiteratedObject + 'static, + V: GiteratedObjectValue + 'static, + { + trace!("value updated {}::{}", O::object_name(), V::value_name()); + let target = ObjectValuePair::from_types::(); + + if let Some(handler) = self.value_change.get(&target) { + // TODO + let _ = handler + .handle( + (AnyObject(Arc::new(object)), AnyValue(Arc::new(new_value))), + operation_state.clone(), + ) + .await; + } + } + + pub async fn setting_update( + &self, + object: O, + new_setting: S, + operation_state: &StackOperationState, + ) where + O: GiteratedObject + 'static, + S: Setting + 'static, + { + trace!("setting updated {}::{}", O::object_name(), S::name()); + let target = ObjectSettingPair::from_types::(); + + if let Some(handler) = self.setting_change.get(&target) { + let _ = handler + .handle( + ( + AnyObject(Arc::new(object)), + AnySetting(Arc::new(new_setting)), + ), + operation_state.clone(), + ) + .await; + } + } + + pub async fn new_object(&self, _new_object: &O, _operation_state: &StackOperationState) + where + O: GiteratedObject, + { + // TODO + } + + /// Writes a setting for the specified object. + pub async fn write_setting( + &self, + object: &O, + setting: S, + ) -> Result<(), OperationError<()>> + where + O: GiteratedObject + 'static + Clone, + S: Setting + 'static + Clone, + { + for provider in self.metadata_providers.iter() { + if provider.provides_for(object as &dyn Any) { + let setting_meta = self + .metadata + .settings + .get(&ObjectSettingPair::from_types::()) + .ok_or_else(|| OperationError::Unhandled)?; + + let object_meta = self + .metadata + .objects + .get(O::object_name()) + .ok_or_else(|| OperationError::Unhandled)?; + + let result = provider + .write( + AnyObject(Arc::new(object.clone())), + object_meta, + AnySetting(Arc::new(setting)), + setting_meta, + ) + .await + .as_internal_error_with_context(format!("writing setting {}", S::name())); + + return result; + } + } + + Err(OperationError::Unhandled) + } + + /// Gets a setting for the specified object. + pub async fn new_get_setting(&self, object: &O) -> Result> + where + O: GiteratedObject + 'static + Clone, + S: Setting + 'static, + { + for provider in self.metadata_providers.iter() { + if provider.provides_for(object as &dyn Any) { + trace!( + "Resolving setting {} for object {} from provider.", + S::name(), + O::object_name() + ); + + let setting_meta = self + .metadata + .settings + .get(&ObjectSettingPair::from_types::()) + .ok_or_else(|| OperationError::Unhandled)?; + + let object_meta = self + .metadata + .objects + .get(O::object_name()) + .ok_or_else(|| OperationError::Unhandled)?; + + let value = provider + .read( + AnyObject(Arc::new(object.clone())), + object_meta, + setting_meta, + ) + .await + .as_internal_error_with_context(format!("getting setting {}", S::name()))?; + + return serde_json::from_value(value) + .as_internal_error_with_context("deserializing setting"); + } + } + trace!( + "No provider registered for setting {} and object {}", + S::name(), + O::object_name() + ); + + Err(OperationError::Unhandled) + } + + fn get_or_create_tree( + &mut self, + target: &ObjectOperationPair<'static>, + ) -> &mut HandlerTree { + if self.operation_handlers.contains_key(target) { + self.operation_handlers.get_mut(target).unwrap() + } else { + self.operation_handlers + .insert(target.clone(), HandlerTree::default()); + + self.operation_handlers.get_mut(target).unwrap() + } + } +} + +impl GiteratedStack { + /// Handles a giterated network message, returning either a raw success + /// payload or a serialized error payload. + pub async fn handle_network_message( + &self, + message: AuthenticatedPayload, + operation_state: &StackOperationState, + ) -> Result, OperationError>> { + let message: GiteratedMessage = + message.into_message(); + + // Deserialize the object, also getting the object type's name + let (object_type, object) = { + let mut result = None; + + for (object_type, object_meta) in self.metadata.objects.iter() { + if let Ok(object) = (object_meta.from_str)(&message.object.0) { + result = Some((object_type.clone(), object)); + break; + } + } + + result + } + .ok_or_else(|| OperationError::Unhandled)?; + + trace!( + "Handling network message {}::<{}>", + message.operation, + object_type + ); + + if message.operation == "get_value" { + // Special case + let operation: GetValue = serde_json::from_slice(&message.payload.0).unwrap(); + + let result = self + .network_get_value( + object, + object_type.clone(), + operation.clone(), + operation_state, + ) + .await; + + // In the case of internal errors, attach context + let result = result.map_err(|err| match err { + OperationError::Operation(operation) => OperationError::Operation(operation), + OperationError::Internal(internal) => { + OperationError::Internal(internal.context(format!( + "{}::get_value::<{}> outcome", + object_type, operation.value_name + ))) + } + OperationError::Unhandled => OperationError::Unhandled, + }); + + return result; + } else if message.operation == "get_setting" { + let operation: GetSetting = serde_json::from_slice(&message.payload.0).unwrap(); + let setting_meta = self + .metadata + .settings + .get(&ObjectSettingPair { + object_kind: &object_type, + setting_name: &operation.setting_name, + }) + .ok_or_else(|| OperationError::Unhandled)?; + let raw_result = self + .get_setting( + object, + object_type.clone(), + operation.clone(), + operation_state, + ) + .await; + return match raw_result { + Ok(success) => { + // Success is the setting type, serialize it + let serialized = (setting_meta.serialize)(success).unwrap(); + + Ok(serde_json::to_vec(&serialized).unwrap()) + } + Err(err) => Err(match err { + OperationError::Operation(failure) => { + // We know how to resolve this type + let failure: GetSettingError = *failure.downcast().unwrap(); + + OperationError::Operation(serde_json::to_vec(&failure).unwrap()) + } + OperationError::Internal(internal) => { + OperationError::Internal(internal.context(format!( + "{}::get_setting::<{}> handler outcome", + object_type, setting_meta.name + ))) + } + OperationError::Unhandled => OperationError::Unhandled, + }), + }; + } else if message.operation == "set_setting" { + let operation: SetSetting = serde_json::from_slice(&message.payload.0).unwrap(); + + trace!( + "Handling network {}::set_setting for {}", + object_type, + operation.setting_name + ); + + let setting_meta = self + .metadata + .settings + .get(&ObjectSettingPair { + object_kind: &object_type, + setting_name: &operation.setting_name, + }) + .unwrap(); + + let setting = (setting_meta.deserialize)(operation.value) + .as_internal_error_with_context(format!( + "deserializing setting {} for object {}", + operation.setting_name, object_type + ))?; + + trace!( + "Deserialized setting {} for object {}", + operation.setting_name, + object_type, + ); + + for provider in self.metadata_providers.iter() { + if provider.provides_for(object.0.as_ref()) { + trace!( + "Resolved setting provider for setting {} for object {}", + operation.setting_name, + object_type, + ); + + let object_meta = self + .metadata + .objects + .get(&object_type) + .ok_or_else(|| OperationError::Unhandled)?; + + let raw_result = provider + .write(object.clone(), object_meta, setting.clone(), setting_meta) + .await; + + return match raw_result { + Ok(_) => { + (setting_meta.setting_updated)( + object, + setting, + operation_state.runtime.clone(), + operation_state, + ) + .await; + + Ok(serde_json::to_vec(&()).unwrap()) + } + Err(e) => Err(OperationError::Internal(e.context(format!( + "writing object {} setting {}", + object_type, operation.setting_name + )))), + }; + } + + trace!( + "Failed to resolve setting provider for setting {} for object {}", + operation.setting_name, + object_type, + ); + } + } + + let target = ObjectOperationPair { + object_name: &object_type, + operation_name: &message.operation, + }; + + // Resolve the target operations from the handlers table + let handler = self + .operation_handlers + .get(&target) + .ok_or_else(|| OperationError::Unhandled)?; + + trace!( + "Resolved operation handler for network message {}::<{}>", + message.operation, + object_type + ); + + // Deserialize the operation + let meta = self + .metadata + .operations + .get(&target) + .ok_or_else(|| OperationError::Unhandled)?; + + let operation = + (meta.deserialize)(&message.payload.0).as_internal_error_with_context(format!( + "deserializing operation {}::{}", + target.object_name, target.operation_name + ))?; + + trace!( + "Deserialized operation for network message {}::<{}>", + message.operation, + object_type + ); + + trace!( + "Calling handler for network message {}::<{}>", + message.operation, + object_type + ); + + // Get the raw result of the operation, where the return values are boxed. + let raw_result = handler + .handle((object.clone(), operation.clone()), operation_state.clone()) + .await; + + trace!( + "Finished handling network message {}::<{}>", + message.operation, + object_type + ); + + // Deserialize the raw result for the network + match raw_result { + Ok(success) => Ok((meta.serialize_success)(success).as_internal_error()?), + Err(err) => Err(match err { + OperationError::Operation(failure) => { + OperationError::Operation((meta.serialize_error)(failure).as_internal_error()?) + } + OperationError::Internal(internal) => { + OperationError::Internal(internal.context(format!( + "operation {}::{} handler outcome", + target.object_name, target.operation_name + ))) + } + OperationError::Unhandled => OperationError::Unhandled, + }), + } + } + + pub async fn network_get_value( + &self, + object: AnyObject, + object_kind: String, + operation: GetValue, + operation_state: &StackOperationState, + ) -> Result, OperationError>> { + trace!("Handling network get_value for {}", operation.value_name); + + let value_meta = self + .metadata + .values + .get(&ObjectValuePair { + object_kind: &object_kind, + value_kind: &operation.value_name, + }) + .ok_or_else(|| OperationError::Unhandled)?; + + for (target, getter) in self.value_getters.iter() { + if target.object_kind != object_kind { + continue; + } + + if target.value_kind != operation.value_name { + continue; + } + + return match getter + .handle((object.clone(),), operation_state.clone()) + .await + { + Ok(success) => { + // Serialize success, which is the value type itself + let serialized = (value_meta.serialize)(success).as_internal_error()?; + + Ok(serialized) + } + Err(err) => Err(match err { + OperationError::Operation(failure) => { + // Failure is sourced from GetValue operation, but this is hardcoded for now + let failure: &GetValueError = failure.0.downcast_ref().unwrap(); + + OperationError::Operation(serde_json::to_vec(&failure).as_internal_error()?) + } + OperationError::Internal(internal) => OperationError::Internal(internal), + OperationError::Unhandled => OperationError::Unhandled, + }), + }; + } + + Err(OperationError::Unhandled) + } + + pub async fn get_setting( + &self, + object: AnyObject, + object_kind: String, + operation: GetSetting, + _operation_state: &StackOperationState, + ) -> Result>> { + trace!( + "Handling network {}::get_setting for {}", + object_kind, + operation.setting_name + ); + + for provider in self.metadata_providers.iter() { + if provider.provides_for(object.0.as_ref()) { + let setting_meta = self + .metadata + .settings + .get(&ObjectSettingPair { + object_kind: &object_kind, + setting_name: &operation.setting_name, + }) + .ok_or_else(|| OperationError::Unhandled)?; + + let object_meta = self + .metadata + .objects + .get(&object_kind) + .ok_or_else(|| OperationError::Unhandled)?; + + let result = provider + .read(object.clone(), object_meta, setting_meta) + .await + .as_internal_error_with_context(format!( + "reading setting {}", + operation.setting_name + ))?; + + return (setting_meta.deserialize)(result).as_internal_error_with_context(format!( + "deserializing setting {}", + operation.setting_name + )); + } + } + + trace!("setting {} doesn't exist", operation.setting_name); + + Err(OperationError::Unhandled) + } + + pub async fn network_set_setting( + &self, + object: AnyObject, + object_kind: String, + operation: SetSetting, + operation_state: &StackOperationState, + ) -> Result, OperationError>> { + trace!( + "Handling network {}::set_setting for {}", + object_kind, + operation.setting_name + ); + + let target = ObjectSettingPair { + object_kind: &object_kind, + setting_name: &operation.setting_name, + }; + + let handler = self.setting_change.get(&target).unwrap(); + + let setting_meta = self + .metadata + .settings + .get(&ObjectSettingPair { + object_kind: &object_kind, + setting_name: &operation.setting_name, + }) + .ok_or_else(|| OperationError::Unhandled)?; + + let setting = + (setting_meta.deserialize)(operation.value).as_internal_error_with_context(format!( + "deserializing setting {} for object {}", + operation.setting_name, object_kind + ))?; + + let raw_result = handler + .handle((object, setting.clone()), operation_state.clone()) + .await; + + match raw_result { + Ok(_) => { + // Serialize success, which is the value type itself + let serialized = serde_json::to_vec(&()).as_internal_error()?; + + Ok(serialized) + } + Err(err) => Err(match err { + OperationError::Operation(operation) => OperationError::Internal(operation), + OperationError::Internal(internal) => OperationError::Internal(internal), + OperationError::Unhandled => OperationError::Unhandled, + }), + } + } +} + +#[async_trait::async_trait(?Send)] +impl ObjectBackend for Arc { + async fn object_operation( + &self, + in_object: O, + operation_name: &str, + payload: D, + operation_state: &StackOperationState, + ) -> Result> + where + O: GiteratedObject + Debug + 'static, + D: GiteratedOperation + Debug + 'static, + D::Success: Clone, + D::Failure: Clone, + { + // Erase object and operation types. + let object = AnyObject(Arc::new(in_object.clone()) as Arc); + let operation = AnyOperation(Arc::new(payload) as Arc); + + // We need to hijack get_value, set_setting, and get_setting. + if operation_name == "get_value" { + let mut value_meta = None; + for (_, meta) in self.metadata.values.iter() { + if (meta.is_get_value_typed)(operation.clone()) { + value_meta = Some(meta); + break; + } + } + + let value_meta = value_meta.ok_or_else(|| OperationError::Unhandled)?; + + let value_name = value_meta.name.clone(); + + trace!( + "Handling get_value for {}::{}", + O::object_name(), + value_name + ); + + for (target, getter) in self.value_getters.iter() { + if target.object_kind != O::object_name() { + continue; + } + + if target.value_kind != value_name { + continue; + } + + return match getter + .handle((object.clone(),), operation_state.clone()) + .await + { + Ok(success) => Ok(success.0.downcast_ref::().unwrap().clone()), + Err(err) => Err(match err { + OperationError::Operation(failure) => OperationError::Operation( + failure.0.downcast_ref::().unwrap().clone(), + ), + OperationError::Internal(internal) => { + OperationError::Internal(internal.context(format!( + "{}::get_value::<{}> handler outcome", + O::object_name(), + value_name + ))) + } + OperationError::Unhandled => OperationError::Unhandled, + }), + }; + } + + return Err(OperationError::Unhandled); + } else if operation.0.is::() { + let get_setting: &GetSetting = operation.0.downcast_ref().unwrap(); + let setting_name = get_setting.setting_name.clone(); + + let raw_result = self + .get_setting( + object, + O::object_name().to_string(), + get_setting.clone(), + operation_state, + ) + .await; + + return match raw_result { + Ok(success) => { + // Success is the setting type, serialize it + // let serialized = (setting_meta.serialize)(success).unwrap(); + + // Ok(serde_json::to_vec(&serialized).unwrap()) + Ok(success.0.downcast_ref::().unwrap().clone()) + } + Err(err) => Err(match err { + OperationError::Operation(failure) => { + // We know this is the right type + OperationError::Operation(*failure.downcast().unwrap()) + } + OperationError::Internal(internal) => { + OperationError::Internal(internal.context(format!( + "{}::get_setting::<{}> handler outcome", + O::object_name(), + setting_name + ))) + } + OperationError::Unhandled => OperationError::Unhandled, + }), + }; + } else if operation.0.is::() { + todo!() + } else if operation.0.is::() { + todo!() + } + + // Resolve the operation from the known operations table. + let operation_type = { + let mut operation_type = None; + + for (target, operation_meta) in self.metadata.operations.iter() { + // Skip elements that we know will not match + if target.object_name != O::object_name() { + continue; + } + + if target.operation_name != operation_name { + continue; + } + + if (operation_meta.any_is_same)(&operation) { + operation_type = Some(target.clone()); + break; + } + } + + operation_type + } + .ok_or_else(|| OperationError::Unhandled)?; + + // Resolve the handler from our handler tree + let handler_tree = self + .operation_handlers + .get(&operation_type) + .ok_or_else(|| OperationError::Unhandled)?; + + let raw_result = handler_tree + .handle((object, operation), operation_state.clone()) + .await; + + // Convert the dynamic result back into its concrete type + match raw_result { + Ok(result) => Ok(result.0.downcast_ref::().unwrap().clone()), + Err(err) => Err(match err { + OperationError::Internal(internal) => { + OperationError::Internal(internal.context(format!( + "operation {}::{} handler outcome", + operation_type.object_name, operation_type.operation_name + ))) + } + OperationError::Operation(boxed_error) => OperationError::Operation( + boxed_error.0.downcast_ref::().unwrap().clone(), + ), + OperationError::Unhandled => OperationError::Unhandled, + }), + } + } + + async fn get_object( + &self, + object_str: &str, + _operation_state: &StackOperationState, + ) -> Result, OperationError> + where + O: GiteratedObject + Debug + 'static, + { + // TODO: Authorization? + for (_object_name, object_meta) in self.metadata.objects.iter() { + if let Ok(object) = (object_meta.from_str)(object_str) { + return Ok(unsafe { + Object::new_unchecked( + object.0.downcast_ref::().unwrap().clone(), + self.clone(), + ) + }); + } + } + + Err(OperationError::Unhandled) + } +} + +/// Defines a type that is a valid Giterated runtime state. +/// +/// This allows for extraction of state in handlers, based on a +/// [`FromOperationState`] impl on (what is in this case) [`Self`]. +pub trait GiteratedStackState: Send + Sync + Clone {} + +impl GiteratedStackState for T {} + +#[async_trait::async_trait(?Send)] +impl HandlerResolvable for Option +where + T: HandlerResolvable, +{ + type Error = MissingValue; + + async fn from_handler_state( + required_parameters: &R, + operation_state: &S, + ) -> Result, MissingValue> { + Ok(T::from_handler_state(required_parameters, operation_state) + .await + .ok()) + } +} diff --git a/giterated-stack/src/substack.rs b/giterated-stack/src/substack.rs new file mode 100644 index 0000000..df4bd91 --- /dev/null +++ b/giterated-stack/src/substack.rs @@ -0,0 +1,325 @@ +use std::{collections::HashMap, sync::Arc}; + +use futures_util::FutureExt; +use giterated_models::{ + error::OperationError, + instance::Instance, + object::{GiteratedObject, ObjectRequest, ObjectResponse}, + operation::GiteratedOperation, + settings::Setting, + value::{GetValueTyped, GiteratedObjectValue}, +}; +use tracing::{info, trace}; + +use crate::{ + handler::HandlerWrapper, provider::MetadataProvider, AnyFailure, AnyObject, AnyOperation, + AnySetting, AnySuccess, AnyValue, GiteratedStack, GiteratedStackState, IntoGiteratedHandler, + ObjectOperationPair, ObjectSettingPair, ObjectValuePair, OperationHandler, RuntimeMetadata, + SettingChange, SettingGetter, StackOperationState, ValueChange, ValueGetter, +}; + +pub struct SubstackBuilder { + pub(crate) operation_handlers: HashMap, OperationHandler>, + pub(crate) value_getters: HashMap, ValueGetter>, + pub(crate) setting_getters: HashMap<&'static str, SettingGetter>, + pub(crate) metadata: RuntimeMetadata, + pub(crate) value_change: HashMap, ValueChange>, + pub(crate) metadata_providers: Vec>, + pub(crate) setting_change: HashMap, SettingChange>, + + pub(crate) state: S, +} + +impl SubstackBuilder { + pub fn new(state: S) -> Self { + Self { + operation_handlers: Default::default(), + value_getters: Default::default(), + setting_getters: Default::default(), + metadata: Default::default(), + value_change: Default::default(), + metadata_providers: Default::default(), + setting_change: Default::default(), + state, + } + } +} + +impl SubstackBuilder { + /// Insert an operation handler into the runtime builder. + /// + /// # Type Registration + /// Inserting the handler will automatically, if required, register the operation type of the + /// handler. It will **not** register the object type automatically. + pub fn operation(&mut self, handler: H) -> &mut Self + where + O: GiteratedObject + Clone, + D: GiteratedOperation + Clone, + H: IntoGiteratedHandler< + (O, D), + A, + S, + StackOperationState, + Result>, + > + Send + + Sync + + 'static, + O: 'static, + D: 'static, + D::Failure: std::fmt::Debug + 'static, + D::Success: 'static, + { + let wrapped = HandlerWrapper::new(self.state.clone(), handler); + + let wrapped = wrapped.map( + |(any_object, any_operation): &(AnyObject, AnyOperation), + _state: &StackOperationState| { + Ok(( + any_object.0.downcast_ref::().unwrap().clone(), + any_operation.0.downcast_ref::().unwrap().clone(), + )) + }, + ); + + let wrapped = wrapped.map_return(|ret_val, _state| match ret_val { + Ok(success) => Ok(AnySuccess(Arc::new(success))), + Err(err) => Err(match err { + OperationError::Operation(failure) => { + OperationError::Operation(AnyFailure(Arc::new(failure))) + } + OperationError::Internal(err) => OperationError::Internal(err), + OperationError::Unhandled => OperationError::Unhandled, + }), + }); + + let pair = ObjectOperationPair::from_types::(); + + self.operation_handlers.insert(pair, wrapped); + + self.metadata.register_operation::(); + + self + } + + /// Register a [`GiteratedObject`] type with the runtime. + /// + /// # Type Registration + /// This will register the provided object type. + pub fn object(&mut self) -> &mut Self { + self.metadata.register_object::(); + + // Insert handler so ObjectRequest is handled properly + + self.operation( + move |_object: Instance, + operation: ObjectRequest, + _state: S, + _operation_state: StackOperationState, + stack: Arc| { + let operation = operation.clone(); + async move { + for (_object_name, object_meta) in stack.metadata.objects.iter() { + if (object_meta.from_str)(&operation.0).is_ok() { + return Ok(ObjectResponse(operation.0.clone())); + } + } + + Err(OperationError::Unhandled) + } + .boxed_local() + }, + ); + + self + } + + /// Register a [`Setting`] type with the runtime. + /// + /// # Type Registration + /// This will register the provided setting type. + pub fn setting( + &mut self, + ) -> &mut Self { + self.metadata.register_setting::(); + + self + } + + /// Register a [`GiteratedObjectValue`] that is also a [`Setting`], which + /// allows for automatic value updates. + pub fn value_setting< + O: GiteratedObject + 'static + Clone, + T: GiteratedObjectValue + Setting + 'static + Clone, + >( + &mut self, + ) -> &mut Self { + self.metadata.register_setting::(); + self.metadata.register_value::(); + + self.setting_change.insert( + ObjectSettingPair::from_types::(), + HandlerWrapper::new( + (), + move |object: AnyObject, + setting: AnySetting, + _state: (), + operation_state: StackOperationState, + stack: Arc| { + trace!( + "value setting updated {}::{}", + O::object_name(), + T::value_name() + ); + let object = object.clone(); + async move { + let object = object.0.downcast_ref::().unwrap(); + let setting = setting.0.downcast_ref::().unwrap(); + stack + .value_update(object.clone(), setting.clone(), &operation_state) + .await; + Ok(()) + } + .boxed_local() + }, + ), + ); + + let wrapped = HandlerWrapper::new( + self.state.clone(), + |object: AnyObject, + _state: _, + _operation_state: StackOperationState, + stack: Arc| { + info!("a setting handler called"); + let object = object.clone(); + async move { + match stack + .new_get_setting::(object.0.downcast_ref().unwrap()) + .await + { + Ok(setting) => Ok(AnyValue(Arc::new(setting))), + Err(err) => { + panic!("Error: {:?}", err); + } + } + } + .boxed_local() + }, + ); + + self.value_getters + .insert(ObjectValuePair::from_types::(), wrapped); + + self + } + + /// Register a [`GiteratedObjectValue`] type with the runtime, providing + /// its associated handler for [`GetValue`]. + /// + /// # Type Registration + /// This will register the provided [`GiteratedObjectValue`] type for its matching / specified + /// object type. It will **not** register the object type automatically. + pub fn value(&mut self, handler: F) -> &mut Self + where + O: GiteratedObject + 'static, + V: GiteratedObjectValue + 'static + Clone, + F: IntoGiteratedHandler< + (O, GetValueTyped), + A, + S, + StackOperationState, + Result>, + > + Send + + Sync, + E: Into + 'static + std::fmt::Debug + Clone, + F: 'static, + { + let wrapped = HandlerWrapper::new(self.state.clone(), handler); + + let wrapped = wrapped.map( + |(any_object,): &(AnyObject,), _state: &StackOperationState| { + Ok(( + any_object + .0 + .downcast_ref::() + .ok_or_else(|| OperationError::Internal(DowncastError.into()))? + .clone(), + GetValueTyped { + ty: std::marker::PhantomData, + }, + )) + }, + ); + + let wrapped = wrapped.map_return(|ret_val, _state| match ret_val { + Ok(success) => Ok(AnyValue(Arc::new(success))), + Err(err) => Err(match err { + OperationError::Operation(failure) => OperationError::Internal(failure.into()), + OperationError::Internal(err) => OperationError::Internal(err), + OperationError::Unhandled => OperationError::Unhandled, + }), + }); + + assert!(self + .value_getters + .insert(ObjectValuePair::from_types::(), wrapped) + .is_none()); + + self.metadata.register_value::(); + + self + } + + pub fn value_change(&mut self, handler: F) -> &mut Self + where + O: GiteratedObject + 'static, + F: IntoGiteratedHandler< + (O, V), + A, + S, + StackOperationState, + Result<(), OperationError>, + > + Send + + Sync, + V: GiteratedObjectValue + Clone + 'static, + O: 'static, + V: 'static, + F: 'static, + { + let wrapped = HandlerWrapper::new(self.state.clone(), handler); + + let wrapped = wrapped.map( + |(any_object, any_value): &(AnyObject, AnyValue), _state: &StackOperationState| { + Ok(( + any_object + .0 + .downcast_ref::() + .ok_or_else(|| OperationError::Internal(DowncastError.into()))? + .clone(), + any_value + .0 + .downcast_ref::() + .ok_or_else(|| OperationError::Internal(DowncastError.into()))? + .clone(), + )) + }, + ); + + assert!(self + .value_change + .insert(ObjectValuePair::from_types::(), wrapped) + .is_none()); + + self + } + + pub fn object_metadata_provider(&mut self, provider: Box) -> &mut Self { + self.metadata_providers.push(provider); + + self + } +} + +#[derive(Debug, Clone, thiserror::Error)] +#[error("downcast error")] +pub struct DowncastError; diff --git a/giterated-stack/src/update.rs b/giterated-stack/src/update.rs index 9879358..1b043e1 100644 --- a/giterated-stack/src/update.rs +++ b/giterated-stack/src/update.rs @@ -116,20 +116,19 @@ impl HandleSettingUpdatedFunction { setting_name: setting_name.to_string(), }, - function: Box::new(move |object, setting_name, value, state| { + function: Box::new(move |object, _setting_name, _value, _state| { async move { - let mut handler = handler; + let _handler = handler; - let object = match O::from_str(&object) { + let _object = match O::from_str(&object) { Ok(object) => object, Err(_) => return Err(()), }; - let setting: S = serde_json::from_value(value.0).unwrap(); - - let _ = handler - .handle_setting_update(object, setting_name, setting, &state) - .await; + // let setting: S = serde_json::from_value( + // let _ = handler + // .handle_setting_update(object, setting_name, setting, &state) + // .await;value.0).unwrap(); Ok(()) } @@ -168,20 +167,20 @@ impl HandleValueUpdatedFunction { value_name: value_name.to_string(), }, - function: Box::new(move |object, setting_name, value, state| { + function: Box::new(move |object, _setting_name, _value, _state| { async move { - let mut handler = handler; + let _handler = handler; - let object = match O::from_str(&object) { + let _object = match O::from_str(&object) { Ok(object) => object, Err(_) => return Err(()), }; - let setting: V = serde_json::from_value(value.0).unwrap(); + // let setting: V = serde_json::from_value(value.0).unwrap(); - let _ = handler - .handle_value_update(object, setting_name, setting, &state) - .await; + // let _ = handler + // .handle_value_update(object, setting_name, setting, &state) + // .await; Ok(()) }