diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b1af5035d6..17843fd0a4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,16 +36,7 @@ jobs: - uses: actions/upload-artifact@v2 with: name: linux_musl_x86_64 - path: target/x86_64-unknown-linux-musl/release/${{ env.BINARY_NAME }}* - - name: Build-musl - uses: gmiam/rust-musl-action@9e6a37bf27ecfffb6b92240ea276bea5487fa15d - continue-on-error: false - with: - args: cargo build --target $BUILD_TARGET --release --features controller - - uses: actions/upload-artifact@v2 - with: - name: fastn_controller_linux_musl_x86_64 - path: target/x86_64-unknown-linux-musl/release/${{ env.BINARY_NAME }}* + path: target/x86_64-unknown-linux-musl/release/${{ env.BINARY_NAME }} release-windows: name: Build for Windows runs-on: windows-latest @@ -131,10 +122,6 @@ jobs: with: name: linux_musl_x86_64 path: ~/download/linux_musl - - uses: actions/download-artifact@v2 - with: - name: fastn_controller_linux_musl_x86_64 - path: ~/download/fastn_controller_linux_musl - uses: actions/download-artifact@v2 with: name: windows_x64_latest @@ -149,16 +136,13 @@ jobs: mv ~/download/windows/windows_x64_installer.exe ~/download/windows/fastn_setup.exe mv ~/download/macos/fastn ~/download/macos/fastn_macos_x86_64 mv ~/download/linux_musl/fastn ~/download/linux_musl/fastn_linux_musl_x86_64 - mv ~/download/linux_musl/fastn.d ~/download/linux_musl/fastn_linux_musl_x86_64.d - mv ~/download/fastn_controller_linux_musl/fastn ~/download/fastn_controller_linux_musl/fastn_controller_linux_musl_x86_64 - mv ~/download/fastn_controller_linux_musl/fastn.d ~/download/fastn_controller_linux_musl/fastn_controller_linux_musl_x86_64.d - name: Update .github/RELEASE_TEMPLATE.md run: | sed -i "s/GITHUB_SHA/${GITHUB_SHA}/g" .github/RELEASE_TEMPLATE.md sed -i "s/DATE/$(date)/g" .github/RELEASE_TEMPLATE.md - uses: ncipollo/release-action@v1 with: - artifacts: "~/download/windows/fastn_windows_x86_64.exe,~/download/windows/fastn_setup.exe,~/download/macos/fastn_macos_x86_64,~/download/linux_musl/fastn_linux_musl_x86_64,~/download/linux_musl/fastn_linux_musl_x86_64.d,~/download/fastn_controller_linux_musl/fastn_controller_linux_musl_x86_64,~/download/fastn_controller_linux_musl/fastn_controller_linux_musl_x86_64.d" + artifacts: "~/download/windows/fastn_windows_x86_64.exe,~/download/windows/fastn_setup.exe,~/download/macos/fastn_macos_x86_64,~/download/linux_musl/fastn_linux_musl_x86_64" generateReleaseNotes: true token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ github.event.inputs.releaseTag }} diff --git a/Cargo.lock b/Cargo.lock index 00eaad5bf3..0bcc593a3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,8 +35,8 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.3", - "base64 0.21.4", + "ahash 0.8.6", + "base64 0.21.5", "bitflags 2.4.1", "brotli", "bytes", @@ -108,7 +108,7 @@ dependencies = [ "actix-utils", "futures-core", "futures-util", - "mio 0.8.8", + "mio 0.8.9", "socket2 0.5.5", "tokio", "tracing", @@ -150,7 +150,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.3", + "ahash 0.8.6", "bytes", "bytestring", "cfg-if", @@ -187,54 +187,6 @@ dependencies = [ "syn 2.0.38", ] -[[package]] -name = "actix-web-lab" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b7c50a90657ef1868db9dd85f74e82c4d9858ce583d4639ae3583f0bb97775" -dependencies = [ - "actix-http", - "actix-router", - "actix-service", - "actix-utils", - "actix-web", - "actix-web-lab-derive", - "ahash 0.8.3", - "arc-swap", - "async-trait", - "bytes", - "bytestring", - "csv", - "derive_more", - "futures-core", - "futures-util", - "http", - "impl-more", - "itertools 0.11.0", - "local-channel", - "mediatype", - "mime", - "once_cell", - "pin-project-lite", - "regex", - "serde", - "serde_html_form", - "serde_json", - "tokio", - "tracing", -] - -[[package]] -name = "actix-web-lab-derive" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16294584c7794939b1e5711f28e7cae84ef30e62a520db3f9af425f85269bcd2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "addr2line" version = "0.21.0" @@ -275,9 +227,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ "getrandom", "once_cell", @@ -286,14 +238,15 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -416,12 +369,6 @@ version = "1.0.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72" -[[package]] -name = "arc-swap" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" - [[package]] name = "arrayvec" version = "0.5.2" @@ -494,9 +441,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64-simd" @@ -612,9 +559,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da74e2b81409b1b743f8f0c62cc6254afefb8b8e50bbfe3735550f7aeefa3448" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -681,9 +628,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytestring" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" dependencies = [ "bytes", ] @@ -782,18 +729,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", @@ -803,9 +750,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" @@ -928,9 +875,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -1011,7 +958,7 @@ dependencies = [ "bitflags 1.3.2", "crossterm_winapi", "libc", - "mio 0.8.8", + "mio 0.8.9", "parking_lot 0.12.1", "signal-hook", "signal-hook-mio", @@ -1027,7 +974,7 @@ dependencies = [ "bitflags 2.4.1", "crossterm_winapi", "libc", - "mio 0.8.8", + "mio 0.8.9", "parking_lot 0.12.1", "signal-hook", "signal-hook-mio", @@ -1094,27 +1041,6 @@ dependencies = [ "syn 2.0.38", ] -[[package]] -name = "csv" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" -dependencies = [ - "memchr", -] - [[package]] name = "darling" version = "0.14.4" @@ -1669,7 +1595,6 @@ name = "fastn-core" version = "0.1.0" dependencies = [ "actix-web", - "actix-web-lab", "antidote", "async-lock", "async-recursion", @@ -1688,6 +1613,8 @@ dependencies = [ "fluent", "ftd 0.3.0", "futures", + "futures-core", + "futures-util", "hyper", "ignore", "indoc 2.0.4", @@ -1875,6 +1802,13 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foo" +version = "0.1.0" +dependencies = [ + "tokio", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -1951,7 +1885,7 @@ dependencies = [ "format_num", "futures", "include_dir", - "indexmap 2.0.2", + "indexmap 2.1.0", "indoc 2.0.4", "itertools 0.11.0", "once_cell", @@ -1967,7 +1901,7 @@ dependencies = [ "serde_json", "slug", "syntect", - "taffy 0.3.16", + "taffy 0.3.18", "thiserror", "tokio", "tracing", @@ -1981,9 +1915,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -1996,9 +1930,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -2006,15 +1940,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -2023,15 +1957,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", @@ -2040,21 +1974,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -2159,7 +2093,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.7", ] [[package]] @@ -2168,7 +2102,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", ] [[package]] @@ -2177,7 +2111,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "allocator-api2", ] @@ -2286,9 +2220,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", @@ -2367,12 +2301,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "impl-more" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" - [[package]] name = "include_dir" version = "0.7.3" @@ -2404,9 +2332,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.2", @@ -2484,9 +2412,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" @@ -2534,9 +2462,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -2592,9 +2520,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libquickjs-sys" @@ -2606,6 +2534,17 @@ dependencies = [ "copy_dir", ] +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "libsqlite3-sys" version = "0.26.0" @@ -2619,11 +2558,11 @@ dependencies = [ [[package]] name = "lightningcss" -version = "1.0.0-alpha.49" +version = "1.0.0-alpha.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06476660ee1e593a2672e4a342a1289708fd9936dcdf3e74433ad078145e9e3d" +checksum = "c2999490cc10a59ad8a87d731791a5d438d2d025e3f137aa7d4c23e1827985b0" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.7", "bitflags 2.4.1", "const-str", "cssparser", @@ -2664,9 +2603,9 @@ checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "local-channel" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a493488de5f18c8ffcba89eebb8532ffc562dc400490eb65b84893fae0b178" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" dependencies = [ "futures-core", "futures-sink", @@ -2675,9 +2614,9 @@ dependencies = [ [[package]] name = "local-waker" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" @@ -2745,12 +2684,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "mediatype" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c408dc227d302f1496c84d9dc68c00fec6f56f9228a18f3023f976f3ca7c945" - [[package]] name = "memchr" version = "2.6.4" @@ -2806,9 +2739,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "log", @@ -2861,7 +2794,7 @@ dependencies = [ "kqueue", "libc", "log", - "mio 0.8.8", + "mio 0.8.9", "walkdir", "windows-sys", ] @@ -2947,9 +2880,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -2979,9 +2912,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" dependencies = [ "cc", "libc", @@ -3018,9 +2951,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parcel_selectors" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f000cdd23df6cebe999cf2b02a3bf40d55758f74883d7fd43a33690565618c8" +checksum = "05d74befe2d076330d9a58bf9ca2da424568724ab278adf15fb5718253133887" dependencies = [ "bitflags 2.4.1", "cssparser", @@ -3137,9 +3070,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ "memchr", "thiserror", @@ -3148,9 +3081,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", @@ -3158,9 +3091,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", @@ -3171,9 +3104,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", @@ -3280,12 +3213,12 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "plist" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06" +checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" dependencies = [ - "base64 0.21.4", - "indexmap 1.9.3", + "base64 0.21.5", + "indexmap 2.1.0", "line-wrap", "quick-xml", "serde", @@ -3311,7 +3244,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "byteorder", "bytes", "fallible-iterator", @@ -3462,9 +3395,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" dependencies = [ "memchr", ] @@ -3585,12 +3518,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] @@ -3650,7 +3583,7 @@ version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", @@ -3705,17 +3638,16 @@ checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" [[package]] name = "ring" -version = "0.16.20" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ "cc", + "getrandom", "libc", - "once_cell", "spin", "untrusted", - "web-sys", - "winapi", + "windows-sys", ] [[package]] @@ -3774,7 +3706,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bitflags 2.4.1", "serde", "serde_derive", @@ -3864,9 +3796,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.20" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.1", "errno", @@ -3877,9 +3809,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", "ring", @@ -3893,14 +3825,14 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", @@ -3956,9 +3888,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", @@ -4007,9 +3939,9 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] @@ -4026,33 +3958,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", "syn 2.0.38", ] -[[package]] -name = "serde_html_form" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde65b75f2603066b78d6fa239b2c07b43e06ead09435f60554d3912962b4a3c" -dependencies = [ - "form_urlencoded", - "indexmap 2.0.2", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -4071,9 +3990,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", @@ -4182,7 +4101,7 @@ checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", "mio 0.7.14", - "mio 0.8.8", + "mio 0.8.9", "signal-hook", ] @@ -4277,9 +4196,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "stringprep" @@ -4381,9 +4300,9 @@ dependencies = [ [[package]] name = "taffy" -version = "0.3.16" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c488aa2bf4bb0cafed312e0876b79a591e3cfa47391f842b7198f9a56547561b" +checksum = "3c2287b6d7f721ada4cddf61ade5e760b2c6207df041cac9bfaa192897362fd3" dependencies = [ "arrayvec 0.7.4", "grid", @@ -4415,13 +4334,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "rustix", "windows-sys", ] @@ -4538,7 +4457,7 @@ dependencies = [ "backtrace", "bytes", "libc", - "mio 0.8.8", + "mio 0.8.9", "num_cpus", "parking_lot 0.12.1", "pin-project-lite", @@ -4607,9 +4526,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -4630,9 +4549,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" [[package]] name = "toml_edit" @@ -4640,7 +4559,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -4686,12 +4605,12 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static 1.4.0", "log", + "once_cell", "tracing-core", ] @@ -4835,9 +4754,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" @@ -4914,9 +4833,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4924,9 +4843,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", @@ -4939,9 +4858,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -4951,9 +4870,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4961,9 +4880,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", @@ -4974,15 +4893,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -5124,9 +5043,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] @@ -5171,6 +5090,26 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "zerocopy" +version = "0.7.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "zip" version = "0.6.6" diff --git a/Cargo.toml b/Cargo.toml index 47b87cb96b..77f9159d31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "fastn-issues", "fastn-js", "fastn-grammar", + "foo", # "fastn-wasm", # "fastn-runtime", ] @@ -15,7 +16,6 @@ exclude = ["fastn-runtime", "fastn-wasm"] resolver = "2" [workspace.package] -version = "0.3.0" authors = [ "Amit Upadhyay ", "Arpita Jaiswal ", @@ -90,6 +90,8 @@ format_num = "0.1" ftd = { path = "ftd" } fastn-js = { path = "fastn-js" } futures = "0.3" +futures-util = { version = "0.3", default-features = false, features = ["std"] } +futures-core = "0.3" home = "0.5" ignore = "0.4" include_dir = "0.7" diff --git a/fastn-core/Cargo.toml b/fastn-core/Cargo.toml index 509bf5e86b..c60572d680 100644 --- a/fastn-core/Cargo.toml +++ b/fastn-core/Cargo.toml @@ -31,7 +31,6 @@ github-auth = ["dep:oauth2"] [dependencies] actix-web.workspace = true -actix-web-lab.workspace = true antidote.workspace = true async-lock.workspace = true dirs.workspace = true @@ -41,6 +40,8 @@ clap.workspace = true colored.workspace = true native-tls.workspace = true deadpool-postgres.workspace = true +futures-util.workspace = true +futures-core.workspace = true postgres-types.workspace = true postgres-native-tls.workspace = true tokio-postgres.workspace = true diff --git a/fastn-core/src/apis/cache.rs b/fastn-core/src/apis/cache.rs index d957bcbb9a..d98b0fbe14 100644 --- a/fastn-core/src/apis/cache.rs +++ b/fastn-core/src/apis/cache.rs @@ -38,7 +38,10 @@ fn query(uri: &str) -> fastn_core::Result { }) } -pub async fn clear(req: &fastn_core::http::Request) -> fastn_core::http::Response { +pub async fn clear( + config: &fastn_core::Config, + req: &fastn_core::http::Request, +) -> fastn_core::http::Response { let query = match query(req.uri()) { Ok(q) => q, Err(err) => { @@ -50,7 +53,7 @@ pub async fn clear(req: &fastn_core::http::Request) -> fastn_core::http::Respons } }; - if let Err(err) = clear_(&query, req).await { + if let Err(err) = clear_(config, &query, req).await { return fastn_core::server_error!( "fastn-Error: /-/clear-cache/, query: {:?}, error: {:?}", query, @@ -62,12 +65,10 @@ pub async fn clear(req: &fastn_core::http::Request) -> fastn_core::http::Respons } pub async fn clear_( + config: &fastn_core::Config, query: &QueryParams, - req: &fastn_core::http::Request, + _req: &fastn_core::http::Request, ) -> fastn_core::Result<()> { - let config = - fastn_core::time("Config::read()") - .it(fastn_core::Config::read(None, false, Some(req)).await?); if config.package.download_base_url.is_none() { return Err(fastn_core::Error::APIResponseError( "cannot remove anything, package does not have `download_base_url`".to_string(), @@ -112,7 +113,7 @@ pub async fn clear_( // Download FASTN.ftd again after removing all the content if !config.root.join("FASTN.ftd").exists() { - fastn_core::commands::serve::download_init_package(config.package.download_base_url) + fastn_core::commands::serve::download_init_package(&config.package.download_base_url) .await?; } diff --git a/fastn-core/src/apis/clone.rs b/fastn-core/src/apis/clone.rs index 007acfa9ac..a678f16d46 100644 --- a/fastn-core/src/apis/clone.rs +++ b/fastn-core/src/apis/clone.rs @@ -5,20 +5,17 @@ pub struct CloneResponse { pub reserved_crs: Vec, } -pub async fn clone( - req: fastn_core::http::Request, -) -> fastn_core::Result { +pub async fn clone(config: &fastn_core::Config) -> fastn_core::Result { // TODO: implement authentication - match clone_worker(req).await { + match clone_worker(config).await { Ok(data) => fastn_core::http::api_ok(data), Err(err) => fastn_core::http::api_error(err.to_string()), } } -async fn clone_worker(req: fastn_core::http::Request) -> fastn_core::Result { +async fn clone_worker(config: &fastn_core::Config) -> fastn_core::Result { use itertools::Itertools; - let config = fastn_core::Config::read(None, false, Some(&req)).await?; let all_files = config .get_all_file_path(&config.package, Default::default())? .into_iter() diff --git a/fastn-core/src/apis/cr.rs b/fastn-core/src/apis/cr.rs index b754afeaa8..1aa2644591 100644 --- a/fastn-core/src/apis/cr.rs +++ b/fastn-core/src/apis/cr.rs @@ -4,10 +4,10 @@ pub struct CreateCRRequest { } pub async fn create_cr( - req: &fastn_core::http::Request, + config: &fastn_core::Config, cr_req: CreateCRRequest, ) -> fastn_core::Result { - match create_cr_worker(req, cr_req).await { + match create_cr_worker(config, cr_req).await { Ok(cr_number) => { #[derive(serde::Serialize)] struct CreateCRResponse { @@ -21,10 +21,9 @@ pub async fn create_cr( } async fn create_cr_worker( - req: &fastn_core::http::Request, + config: &fastn_core::Config, cr_request: CreateCRRequest, ) -> fastn_core::Result { - let config = fastn_core::Config::read(None, false, Some(req)).await?; let cr_number = config.extract_cr_number().await?; let default_title = format!("CR#{cr_number}"); let cr_meta = fastn_core::cr::CRMeta { @@ -32,24 +31,25 @@ async fn create_cr_worker( cr_number: cr_number as usize, open: true, }; - fastn_core::commands::create_cr::add_cr_to_workspace(&config, &cr_meta).await?; + fastn_core::commands::create_cr::add_cr_to_workspace(config, &cr_meta).await?; Ok(cr_number as usize) } pub async fn create_cr_page( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { - match create_cr_page_worker(req).await { + match create_cr_page_worker(config, req).await { Ok(body) => Ok(body), Err(err) => fastn_core::http::api_error(err.to_string()), } } async fn create_cr_page_worker( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { - let mut config = fastn_core::Config::read(None, false, Some(&req)).await?; - let create_cr_ftd = fastn_core::package_info_create_cr(&config)?; + let create_cr_ftd = fastn_core::package_info_create_cr(config)?; let main_document = fastn_core::Document { id: "create-cr.ftd".to_string(), @@ -58,7 +58,10 @@ async fn create_cr_page_worker( package_name: config.package.name.clone(), }; - fastn_core::package::package_doc::read_ftd(&mut config, &main_document, "/", false, false) + let mut req_config = + fastn_core::RequestConfig::new(config, &req, main_document.id.as_str(), "/"); + + fastn_core::package::package_doc::read_ftd(&mut req_config, &main_document, "/", false, false) .await .map(Into::into) } diff --git a/fastn-core/src/apis/edit.rs b/fastn-core/src/apis/edit.rs index 53a7d1a34e..f46f3e77e4 100644 --- a/fastn-core/src/apis/edit.rs +++ b/fastn-core/src/apis/edit.rs @@ -25,16 +25,14 @@ pub struct EditResponse { } pub async fn edit( + config: &fastn_core::Config, req: &fastn_core::http::Request, req_data: EditRequest, ) -> fastn_core::Result { - let mut config = match fastn_core::Config::read(None, false, Some(req)).await { - Ok(config) => config, - Err(err) => return fastn_core::http::api_error(err.to_string()), - }; - config.current_document = Some(req_data.path.to_string()); + let mut req_config = fastn_core::RequestConfig::new(config, req, "edit.ftd", "/"); + req_config.current_document = Some(req_data.path.to_string()); - match config.can_write(req, req_data.path.as_str()).await { + match req_config.can_write(req_data.path.as_str()).await { Ok(can_write) => { if !can_write { return Ok(fastn_core::unauthorised!( @@ -59,7 +57,7 @@ pub async fn edit( } pub(crate) async fn edit_worker( - config: fastn_core::Config, + config: &fastn_core::Config, request: EditRequest, ) -> fastn_core::Result { if request.is_delete() { @@ -110,7 +108,7 @@ pub(crate) async fn edit_worker( .await { let snapshots = fastn_core::snapshot::get_latest_snapshots(&config.root).await?; - let workspaces = fastn_core::snapshot::get_workspace(&config).await?; + let workspaces = fastn_core::snapshot::get_workspace(config).await?; let file = fastn_core::get_file( config.package.name.to_string(), @@ -149,7 +147,7 @@ pub(crate) async fn edit_worker( if let Some(before_update_status) = before_update_status { let snapshots = fastn_core::snapshot::get_latest_snapshots(&config.root).await?; - let workspaces = fastn_core::snapshot::get_workspace(&config).await?; + let workspaces = fastn_core::snapshot::get_workspace(config).await?; let file = fastn_core::get_file( config.package.name.to_string(), &config.root.join(&file_name), @@ -174,14 +172,8 @@ pub(crate) async fn edit_worker( }) } -pub async fn sync( - req: fastn_core::http::Request, -) -> fastn_core::Result { - let config = match fastn_core::Config::read(None, false, Some(&req)).await { - Ok(config) => config, - Err(err) => return fastn_core::http::api_error(err.to_string()), - }; - match fastn_core::commands::sync::sync(&config, None).await { +pub async fn sync(config: &fastn_core::Config) -> fastn_core::Result { + match fastn_core::commands::sync::sync(config, None).await { Ok(_) => { #[derive(serde::Serialize)] struct SyncResponse { @@ -199,15 +191,10 @@ pub struct RevertRequest { } pub async fn revert( - req: &fastn_core::http::Request, + config: &fastn_core::Config, rev: RevertRequest, ) -> fastn_core::Result { - let config = match fastn_core::Config::read(None, false, Some(req)).await { - Ok(config) => config, - Err(err) => return fastn_core::http::api_error(err.to_string()), - }; - - match fastn_core::commands::revert::revert(&config, rev.path.as_str()).await { + match fastn_core::commands::revert::revert(config, rev.path.as_str()).await { Ok(_) => { #[derive(serde::Serialize)] struct RevertResponse { diff --git a/fastn-core/src/apis/edit_source.rs b/fastn-core/src/apis/edit_source.rs index a59f721b26..cb93e8edba 100644 --- a/fastn-core/src/apis/edit_source.rs +++ b/fastn-core/src/apis/edit_source.rs @@ -1,4 +1,7 @@ -pub(crate) async fn edit_source(req: &fastn_core::http::Request) -> fastn_core::http::Response { +pub(crate) async fn edit_source( + config: &fastn_core::Config, + req: &fastn_core::http::Request, +) -> fastn_core::http::Response { // TODO: Need to remove unwrap let path = { let mut path: camino::Utf8PathBuf = @@ -9,7 +12,7 @@ pub(crate) async fn edit_source(req: &fastn_core::http::Request) -> fastn_core:: path }; - match handle_view_source(req, path.as_str()).await { + match handle_view_source(config, req, path.as_str()).await { Ok(body) => fastn_core::http::ok(body), Err(e) => { fastn_core::server_error!("new_path: {}, Error: {:?}", path, e) @@ -18,16 +21,18 @@ pub(crate) async fn edit_source(req: &fastn_core::http::Request) -> fastn_core:: } async fn handle_view_source( + config: &fastn_core::Config, req: &fastn_core::http::Request, path: &str, ) -> fastn_core::Result> { - let mut config = fastn_core::Config::read(None, false, Some(req)).await?; + let mut req_config = fastn_core::RequestConfig::new(config, req, "editor-source.ftd", "/"); + let file_name = config.get_file_path_and_resolve(path).await?; - let file = config.get_file_and_package_by_id(path).await?; + let file = req_config.get_file_and_package_by_id(path).await?; match file { fastn_core::File::Ftd(_) | fastn_core::File::Markdown(_) | fastn_core::File::Code(_) => { - let editor_ftd = fastn_core::package_editor_source(&config, file_name.as_str())?; + let editor_ftd = fastn_core::package_editor_source(config, file_name.as_str())?; let main_document = fastn_core::Document { id: "editor-source.ftd".to_string(), content: editor_ftd, @@ -35,7 +40,7 @@ async fn handle_view_source( package_name: config.package.name.clone(), }; fastn_core::package::package_doc::read_ftd( - &mut config, + &mut req_config, &main_document, "/", false, diff --git a/fastn-core/src/apis/sync.rs b/fastn-core/src/apis/sync.rs index e7e57ba45f..617c3d2163 100644 --- a/fastn-core/src/apis/sync.rs +++ b/fastn-core/src/apis/sync.rs @@ -63,25 +63,24 @@ pub struct SyncRequest { /// If conflict occur, Then send back updated version in latest.ftd with conflicted content /// pub async fn sync( - req: &fastn_core::http::Request, + config: &fastn_core::Config, sync_req: SyncRequest, ) -> fastn_core::Result { dbg!("remote server call", &sync_req.package_name); - match sync_worker(req, sync_req).await { + match sync_worker(config, sync_req).await { Ok(data) => fastn_core::http::api_ok(data), Err(err) => fastn_core::http::api_error(err.to_string()), } } pub(crate) async fn sync_worker( - req: &fastn_core::http::Request, + config: &fastn_core::Config, request: SyncRequest, ) -> fastn_core::Result { use itertools::Itertools; // TODO: Need to call at once only - let config = fastn_core::Config::read(None, false, Some(req)).await?; let mut snapshots = fastn_core::snapshot::get_latest_snapshots(&config.root).await?; let client_snapshots = fastn_core::snapshot::resolve_snapshots(&request.latest_ftd).await?; // let latest_ftd = tokio::fs::read_to_string(config.history_dir().join(".latest.ftd")).await?; @@ -229,12 +228,12 @@ pub(crate) async fn sync_worker( } } - client_current_files(&config, &snapshots, &client_snapshots, &mut synced_files).await?; + client_current_files(config, &snapshots, &client_snapshots, &mut synced_files).await?; - let history_files = clone_history_files(&config, &snapshots, &client_snapshots).await?; + let history_files = clone_history_files(config, &snapshots, &client_snapshots).await?; fastn_core::snapshot::create_latest_snapshots( - &config, + config, &snapshots .into_iter() .map(|(filename, timestamp)| fastn_core::Snapshot { diff --git a/fastn-core/src/apis/sync2.rs b/fastn-core/src/apis/sync2.rs index debff5668b..a6d2524c05 100644 --- a/fastn-core/src/apis/sync2.rs +++ b/fastn-core/src/apis/sync2.rs @@ -110,12 +110,12 @@ pub struct File { } pub async fn sync2( - req: &fastn_core::http::Request, + config: &fastn_core::Config, sync_req: SyncRequest, ) -> fastn_core::Result { dbg!("remote server call", &sync_req.package_name); - match sync_worker(req, sync_req).await { + match sync_worker(config, sync_req).await { Ok(data) => fastn_core::http::api_ok(data), Err(err) => fastn_core::http::api_error(err.to_string()), } @@ -308,14 +308,13 @@ pub(crate) async fn do_sync( } pub(crate) async fn sync_worker( - req: &fastn_core::http::Request, + config: &fastn_core::Config, request: SyncRequest, ) -> fastn_core::Result { use itertools::Itertools; // TODO: Need to call at once only - let config = fastn_core::Config::read(None, false, Some(req)).await?; - let mut synced_files = do_sync(&config, request.files.as_slice()).await?; + let mut synced_files = do_sync(config, request.files.as_slice()).await?; let remote_history = config.get_history().await?; let remote_manifest = fastn_core::history::FileHistory::get_remote_manifest(remote_history.as_slice(), true)?; @@ -324,9 +323,9 @@ pub(crate) async fn sync_worker( let client_latest = fastn_core::history::FileHistory::get_remote_manifest(clone_history.as_slice(), true)?; - client_current_files(&config, &remote_manifest, &client_latest, &mut synced_files).await?; + client_current_files(config, &remote_manifest, &client_latest, &mut synced_files).await?; - let history_files = clone_history_files(&config, &remote_manifest, &client_latest).await?; + let history_files = clone_history_files(config, &remote_manifest, &client_latest).await?; Ok(SyncResponse { files: synced_files.into_values().collect_vec(), diff --git a/fastn-core/src/apis/view_source.rs b/fastn-core/src/apis/view_source.rs index 306616c04f..90a866982d 100644 --- a/fastn-core/src/apis/view_source.rs +++ b/fastn-core/src/apis/view_source.rs @@ -1,4 +1,7 @@ -pub(crate) async fn view_source(req: &fastn_core::http::Request) -> fastn_core::http::Response { +pub(crate) async fn view_source( + config: &fastn_core::Config, + req: &fastn_core::http::Request, +) -> fastn_core::http::Response { // TODO: Need to remove unwrap let path = { let mut path: camino::Utf8PathBuf = @@ -9,7 +12,7 @@ pub(crate) async fn view_source(req: &fastn_core::http::Request) -> fastn_core:: path }; - match handle_view_source(req, path.as_str()).await { + match handle_view_source(config, req, path.as_str()).await { Ok(body) => fastn_core::http::ok(body), Err(e) => { fastn_core::server_error!("new_path: {}, Error: {:?}", path, e) @@ -18,18 +21,19 @@ pub(crate) async fn view_source(req: &fastn_core::http::Request) -> fastn_core:: } async fn handle_view_source( + config: &fastn_core::Config, req: &fastn_core::http::Request, path: &str, ) -> fastn_core::Result> { - let mut config = fastn_core::Config::read(None, false, Some(req)).await?; + let mut req_config = fastn_core::RequestConfig::new(config, req, "editor.ftd", "/"); let file_name = config.get_file_path_and_resolve(path).await?; - let file = config.get_file_and_package_by_id(path).await?; + let file = req_config.get_file_and_package_by_id(path).await?; match file { fastn_core::File::Ftd(_) | fastn_core::File::Markdown(_) | fastn_core::File::Code(_) => { let snapshots = fastn_core::snapshot::get_latest_snapshots(&config.root).await?; let diff = get_diff(&file, &snapshots).await; - let editor_ftd = fastn_core::package_info_editor(&config, file_name.as_str(), diff)?; + let editor_ftd = fastn_core::package_info_editor(config, file_name.as_str(), diff)?; let main_document = fastn_core::Document { id: "editor.ftd".to_string(), content: editor_ftd, @@ -37,7 +41,7 @@ async fn handle_view_source( package_name: config.package.name.clone(), }; fastn_core::package::package_doc::read_ftd( - &mut config, + &mut req_config, &main_document, "/", false, diff --git a/fastn-core/src/auth/processor.rs b/fastn-core/src/auth/processor.rs index cd2dd82a9f..e392061501 100644 --- a/fastn-core/src/auth/processor.rs +++ b/fastn-core/src/auth/processor.rs @@ -3,19 +3,16 @@ pub fn user_details( section: &ftd::ftd2021::p1::Section, doc: &ftd::ftd2021::p2::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::ftd2021::p1::Result { let mut found_cookie = false; - let is_login = match &config.request { - Some(req) => { - for auth_provider in fastn_core::auth::AuthProviders::AUTH_ITER.iter() { - if req.cookie(auth_provider.as_str()).is_some() { - found_cookie = true; - } + let is_login = { + for auth_provider in fastn_core::auth::AuthProviders::AUTH_ITER.iter() { + if req_config.request.cookie(auth_provider.as_str()).is_some() { + found_cookie = true; } - found_cookie } - None => false, + found_cookie }; #[derive(Debug, serde::Serialize)] diff --git a/fastn-core/src/catch_panic.rs b/fastn-core/src/catch_panic.rs new file mode 100644 index 0000000000..b1c175e142 --- /dev/null +++ b/fastn-core/src/catch_panic.rs @@ -0,0 +1,155 @@ +// borrowed from https://github.com/robjtede/actix-web-lab/ (MIT) +use std::{ + future::{ready, Ready}, + panic::AssertUnwindSafe, + rc::Rc, +}; + +use actix_web::{ + dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}, + error, +}; +use futures_core::future::LocalBoxFuture; +use futures_util::FutureExt as _; + +/// A middleware to catch panics in wrapped handlers and middleware, returning empty 500 responses. +/// +/// **This middleware should never be used as replacement for proper error handling.** See [this +/// thread](https://github.com/actix/actix-web/issues/1501#issuecomment-627517783) for historical +/// discussion on why Actix Web does not do this by default. +/// +/// It is recommended that this middleware be registered last. That is, `wrap`ed after everything +/// else except `Logger`. +/// +/// # Examples +/// +/// ```ignore +/// # use actix_web::App; +/// use actix_web_lab::middleware::CatchPanic; +/// +/// App::new().wrap(CatchPanic::default()) +/// # ; +/// ``` +/// +/// ```ignore +/// # use actix_web::App; +/// use actix_web::middleware::{Logger, NormalizePath}; +/// use actix_web_lab::middleware::CatchPanic; +/// +/// // recommended wrap order +/// App::new() +/// .wrap(NormalizePath::default()) +/// .wrap(CatchPanic::default()) // <- after everything except logger +/// .wrap(Logger::default()) +/// # ; +/// ``` +#[derive(Debug, Clone, Default)] +#[non_exhaustive] +pub struct CatchPanic; + +impl Transform for CatchPanic +where + S: Service, Error = actix_web::Error> + 'static, +{ + type Response = ServiceResponse; + type Error = actix_web::Error; + type Transform = CatchPanicMiddleware; + type InitError = (); + type Future = Ready>; + + fn new_transform(&self, service: S) -> Self::Future { + ready(Ok(CatchPanicMiddleware { + service: Rc::new(service), + })) + } +} + +pub struct CatchPanicMiddleware { + service: Rc, +} + +impl Service for CatchPanicMiddleware +where + S: Service, Error = actix_web::Error> + 'static, +{ + type Response = ServiceResponse; + type Error = actix_web::Error; + type Future = LocalBoxFuture<'static, Result>; + + forward_ready!(service); + + fn call(&self, req: ServiceRequest) -> Self::Future { + AssertUnwindSafe(self.service.call(req)) + .catch_unwind() + .map(move |res| match res { + Ok(Ok(res)) => Ok(res), + Ok(Err(svc_err)) => Err(svc_err), + Err(_panic_err) => Err(error::ErrorInternalServerError( + INTERNAL_SERVER_ERROR_MESSAGE, + )), + }) + .boxed_local() + } +} + +const INTERNAL_SERVER_ERROR_MESSAGE: &str = "500 Server Error"; + +#[cfg(test)] +mod tests { + use actix_web::{ + body::{to_bytes, MessageBody}, + dev::{Service as _, ServiceFactory}, + http::StatusCode, + test, web, App, Error, + }; + + use super::*; + + fn test_app() -> App< + impl ServiceFactory< + ServiceRequest, + Response = ServiceResponse, + Config = (), + InitError = (), + Error = Error, + >, + > { + App::new() + .wrap(CatchPanic::default()) + .route("/", web::get().to(|| async { "content" })) + .route( + "/disco", + #[allow(unreachable_code)] + web::get().to(|| async { + panic!("the disco"); + "" + }), + ) + } + + #[actix_web::test] + async fn pass_through_no_panic() { + let app = test::init_service(test_app()).await; + + let req = test::TestRequest::default().to_request(); + let res = test::call_service(&app, req).await; + assert_eq!(res.status(), StatusCode::OK); + let body = test::read_body(res).await; + assert_eq!(body, "content"); + } + + #[actix_web::test] + async fn catch_panic_return_internal_server_error_response() { + let app = test::init_service(test_app()).await; + + let req = test::TestRequest::with_uri("/disco").to_request(); + let err = match app.call(req).await { + Ok(_) => panic!("unexpected Ok response"), + Err(err) => err, + }; + let res = err.error_response(); + assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR); + let body = to_bytes(res.into_body()).await.unwrap(); + assert_eq!(body, INTERNAL_SERVER_ERROR_MESSAGE) + } +} diff --git a/fastn-core/src/commands/build.rs b/fastn-core/src/commands/build.rs index 6a21114dc6..237f98a393 100644 --- a/fastn-core/src/commands/build.rs +++ b/fastn-core/src/commands/build.rs @@ -1,6 +1,6 @@ // #[tracing::instrument(skip(config))] pub async fn build( - config: &mut fastn_core::Config, + config: &fastn_core::Config, only_id: Option<&str>, base_url: &str, ignore_failed: bool, @@ -197,7 +197,7 @@ fn is_virtual_dep(path: &str) -> bool { } async fn handle_dependency_file( - config: &mut fastn_core::Config, + config: &fastn_core::Config, cache: &mut cache::Cache, documents: &std::collections::BTreeMap, base_url: &str, @@ -228,7 +228,7 @@ async fn handle_dependency_file( // removes deleted documents from cache and build folder fn remove_deleted_documents( - config: &mut fastn_core::Config, + config: &fastn_core::Config, c: &mut cache::Cache, documents: &std::collections::BTreeMap, ) -> fastn_core::Result<()> { @@ -278,7 +278,7 @@ fn remove_deleted_documents( #[tracing::instrument(skip(config, documents))] async fn incremental_build( - config: &mut fastn_core::Config, + config: &fastn_core::Config, documents: &std::collections::BTreeMap, base_url: &str, ignore_failed: bool, @@ -411,7 +411,7 @@ async fn incremental_build( #[tracing::instrument(skip(config, documents))] async fn handle_only_id( id: &str, - config: &mut fastn_core::Config, + config: &fastn_core::Config, base_url: &str, ignore_failed: bool, test: bool, @@ -432,7 +432,7 @@ async fn handle_only_id( async fn handle_file( document: &fastn_core::File, - config: &mut fastn_core::Config, + config: &fastn_core::Config, base_url: &str, ignore_failed: bool, test: bool, @@ -441,7 +441,7 @@ async fn handle_file( ) -> fastn_core::Result<()> { let start = std::time::Instant::now(); print!("Processing {} ... ", document.get_id_with_package()); - + let package_name = config.package.name.to_string(); let process_status = handle_file_( document, config, @@ -454,23 +454,13 @@ async fn handle_file( .await; if process_status.is_ok() { fastn_core::utils::print_end( - format!( - "Processed {}/{}", - config.package.name.as_str(), - document.get_id() - ) - .as_str(), + format!("Processed {}/{}", package_name.as_str(), document.get_id()).as_str(), start, ); } if process_status.is_err() { fastn_core::utils::print_error( - format!( - "Failed {}/{}", - config.package.name.as_str(), - document.get_id() - ) - .as_str(), + format!("Failed {}/{}", package_name.as_str(), document.get_id()).as_str(), start, ); return process_status; @@ -570,16 +560,13 @@ fn remove_extension(id: &str) -> String { #[tracing::instrument(skip(document, config, cache))] async fn handle_file_( document: &fastn_core::File, - config: &mut fastn_core::Config, + config: &fastn_core::Config, base_url: &str, ignore_failed: bool, test: bool, build_static_files: bool, cache: Option<&mut cache::Cache>, ) -> fastn_core::Result<()> { - config.current_document = Some(document.get_id().to_string()); - config.dependencies_during_render = vec![]; - match document { fastn_core::File::Ftd(doc) => { let file_path = if doc.id.eq("404.ftd") { @@ -606,23 +593,44 @@ async fn handle_file_( return Ok(()); } - let resp = fastn_core::package::package_doc::process_ftd( - config, - doc, - base_url, - build_static_files, - test, - file_path.as_str(), - ) - .await; + let resp = { + let req = fastn_core::http::Request::default(); + let mut req_config = + fastn_core::RequestConfig::new(config, &req, doc.id.as_str(), base_url); + req_config.current_document = Some(document.get_id().to_string()); + + let resp = fastn_core::package::package_doc::process_ftd( + &mut req_config, + doc, + base_url, + build_static_files, + test, + file_path.as_str(), + ) + .await; + + config.all_packages.borrow_mut().extend( + req_config + .config + .all_packages + .borrow() + .iter() + .map(|(k, v)| (k.clone(), v.clone())), + ); + resp + }; + match (resp, ignore_failed) { (Ok(r), _) => { + // TODO: what to do with dependencies? + // let dependencies = req_config.dependencies_during_render; + let dependencies = vec![]; if let Some(cache) = cache { cache.documents.insert( remove_extension(doc.id.as_str()), cache::Document { html_checksum: r.checksum(), - dependencies: config.dependencies_during_render.clone(), + dependencies, }, ); cache.file_checksum.insert( @@ -732,7 +740,7 @@ pub async fn default_build_files( #[tracing::instrument(skip(config))] async fn get_documents_for_current_package( - config: &mut fastn_core::Config, + config: &fastn_core::Config, ) -> fastn_core::Result> { let mut documents = std::collections::BTreeMap::from_iter( config @@ -743,13 +751,12 @@ async fn get_documents_for_current_package( ); if let Some(ref sitemap) = config.package.sitemap { - let new_config = config.clone(); let get_all_locations = sitemap.get_all_locations(); let mut files: std::collections::HashMap = Default::default(); for (doc_path, _, url) in get_all_locations { let file = { let package_name = if let Some(ref url) = url { - new_config.find_package_by_id(url).await?.1.name + config.find_package_by_id(url).await?.1.name } else { config.package.name.to_string() }; @@ -770,10 +777,6 @@ async fn get_documents_for_current_package( files.insert(file.get_id().to_string(), file); } - config - .all_packages - .borrow_mut() - .extend(new_config.all_packages.into_inner()); documents.extend(files); } diff --git a/fastn-core/src/commands/clone.rs b/fastn-core/src/commands/clone.rs index 4e9b63348b..cb7912bf33 100644 --- a/fastn-core/src/commands/clone.rs +++ b/fastn-core/src/commands/clone.rs @@ -14,7 +14,7 @@ pub async fn clone(source: &str) -> fastn_core::Result<()> { })) .await; - let config = fastn_core::Config::read(Some(root.as_str().to_string()), false, None).await?; + let config = fastn_core::Config::read(Some(root.as_str().to_string()), false).await?; config.create_clone_workspace().await?; config .write_clone_available_cr(clone_response.reserved_crs.as_slice()) diff --git a/fastn-core/src/commands/serve.rs b/fastn-core/src/commands/serve.rs index 0bbf40fc35..8c7aa25673 100644 --- a/fastn-core/src/commands/serve.rs +++ b/fastn-core/src/commands/serve.rs @@ -3,7 +3,7 @@ static LOCK: once_cell::sync::Lazy> = #[tracing::instrument(skip_all)] fn handle_redirect( - config: &mut fastn_core::Config, + config: &fastn_core::Config, path: &camino::Utf8Path, ) -> Option { config @@ -19,10 +19,10 @@ fn handle_redirect( /// #[tracing::instrument(skip_all)] async fn serve_file( - config: &mut fastn_core::Config, + config: &mut fastn_core::RequestConfig, path: &camino::Utf8Path, ) -> fastn_core::http::Response { - if let Some(r) = handle_redirect(config, path) { + if let Some(r) = handle_redirect(&config.config, path) { return r; } @@ -42,13 +42,7 @@ async fn serve_file( // Auth Stuff if !f.is_static() { - let req = if let Some(ref r) = config.request { - r - } else { - return fastn_core::server_error!("request not set"); - }; - - match config.can_read(req, path.as_str(), true).await { + match config.can_read(path.as_str(), true).await { Ok(can_read) => { if !can_read { tracing::error!( @@ -130,13 +124,13 @@ async fn serve_file( } async fn serve_cr_file( - req: &fastn_core::http::Request, - config: &mut fastn_core::Config, + req_config: &mut fastn_core::RequestConfig, path: &camino::Utf8Path, cr_number: usize, ) -> fastn_core::http::Response { let _lock = LOCK.read().await; - let f = match config + let f = match req_config + .config .get_file_and_package_by_cr_id(path.as_str(), cr_number) .await { @@ -148,7 +142,7 @@ async fn serve_cr_file( // Auth Stuff if !f.is_static() { - match config.can_read(req, path.as_str(), true).await { + match req_config.can_read(path.as_str(), true).await { Ok(can_read) => { if !can_read { return fastn_core::unauthorised!("You are unauthorized to access: {}", path); @@ -160,11 +154,11 @@ async fn serve_cr_file( } } - config.current_document = Some(f.get_id().to_string()); + req_config.current_document = Some(f.get_id().to_string()); match f { fastn_core::File::Ftd(main_document) => { match fastn_core::package::package_doc::read_ftd( - config, + req_config, &main_document, "/", false, @@ -240,32 +234,21 @@ async fn static_file(file_path: camino::Utf8PathBuf) -> fastn_core::http::Respon #[tracing::instrument(skip_all)] pub async fn serve( + config: &fastn_core::Config, req: fastn_core::http::Request, - edition: Option, - external_js: Vec, - inline_js: Vec, - external_css: Vec, - inline_css: Vec, ) -> fastn_core::Result { let _lock = LOCK.read().await; - // TODO: remove unwrap - let path: camino::Utf8PathBuf = req.path().replacen('/', "", 1).parse().unwrap(); - let mut config = fastn_core::Config::read(None, false, Some(&req)) - .await - .unwrap() - .add_edition(edition)? - .add_external_js(external_js) - .add_inline_js(inline_js) - .add_external_css(external_css) - .add_inline_css(inline_css); + let mut req_config = fastn_core::RequestConfig::new(config, &req, "", "/"); + + let path: camino::Utf8PathBuf = req.path().replacen('/', "", 1).parse()?; Ok(if path.eq(&camino::Utf8PathBuf::new().join("FASTN.ftd")) { - serve_fastn_file(&config).await + serve_fastn_file(config).await } else if path.eq(&camino::Utf8PathBuf::new().join("")) { - serve_file(&mut config, &path.join("/")).await + serve_file(&mut req_config, &path.join("/")).await } else if let Some(cr_number) = fastn_core::cr::get_cr_path_from_url(path.as_str()) { - serve_cr_file(&req, &mut config, &path, cr_number).await + serve_cr_file(&mut req_config, &path, cr_number).await } else { // url is present in config or not // If not present than proxy pass it @@ -319,7 +302,9 @@ pub async fn serve( // if request goes with mount-point /todos/api/add-todo/ // so it should say not found and pass it to proxy - let file_response = serve_file(&mut config, path.as_path()).await; + let cookies = req_config.request.cookies().clone(); + + let file_response = serve_file(&mut req_config, path.as_path()).await; // If path is not present in sitemap then pass it to proxy // TODO: Need to handle other package URL as well, and that will start from `-` // and all the static files starts with `-` @@ -337,7 +322,7 @@ pub async fn serve( // Already checked in the above method serve_file tracing::info!("executing proxy: path: {}", &path); let (package_name, url, mut conf) = - fastn_core::config::utils::get_clean_url(&config, path.as_str())?; + fastn_core::config::utils::get_clean_url(config, path.as_str())?; let package_name = package_name.unwrap_or_else(|| config.package.name.to_string()); let host = if let Some(port) = url.port() { @@ -345,12 +330,6 @@ pub async fn serve( } else { format!("{}://{}", url.scheme(), url.host_str().unwrap()) }; - let req = if let Some(r) = config.request { - r - } else { - tracing::error!(msg = "request not set"); - return Ok(fastn_core::server_error!("request not set")); - }; // TODO: read app config and send them to service as header // Adjust x-fastn header from based on the platform and the requested field @@ -360,7 +339,7 @@ pub async fn serve( if let Some(user_data) = fastn_core::auth::get_user_data_from_cookies( platform, requested_field, - req.cookies(), + &cookies, ) .await? { @@ -404,9 +383,9 @@ pub async fn serve( }) } -pub(crate) async fn download_init_package(url: Option) -> std::io::Result<()> { +pub(crate) async fn download_init_package(url: &Option) -> std::io::Result<()> { let mut package = fastn_core::Package::new("unknown-package"); - package.download_base_url = url; + package.download_base_url = url.to_owned(); package .http_download_by_id( "FASTN.ftd", @@ -421,6 +400,7 @@ pub(crate) async fn download_init_package(url: Option) -> std::io::Resul } pub async fn clear_cache( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { fn is_login(req: &fastn_core::http::Request) -> bool { @@ -437,7 +417,7 @@ pub async fn clear_cache( let from = actix_web::web::Query::::from_query(req.query_string())?; if from.from.eq(&Some("temp-github".to_string())) { let _lock = LOCK.write().await; - return Ok(fastn_core::apis::cache::clear(&req).await); + return Ok(fastn_core::apis::cache::clear(config, &req).await); } // TODO: Remove After Demo, till here @@ -451,7 +431,7 @@ pub async fn clear_cache( } let _lock = LOCK.write().await; - fastn_core::apis::cache::clear(&req).await; + fastn_core::apis::cache::clear(config, &req).await; // TODO: Redirect to Referrer uri return Ok(actix_web::HttpResponse::Found() .append_header((actix_web::http::header::LOCATION, "/".to_string())) @@ -459,79 +439,90 @@ pub async fn clear_cache( } // TODO: Move them to routes folder -async fn sync(req: fastn_core::http::Request) -> fastn_core::Result { +async fn sync( + config: &fastn_core::Config, + req: fastn_core::http::Request, +) -> fastn_core::Result { let _lock = LOCK.write().await; - fastn_core::apis::sync(&req, req.json()?).await + fastn_core::apis::sync(config, req.json()?).await } -async fn sync2(req: fastn_core::http::Request) -> fastn_core::Result { +async fn sync2( + config: &fastn_core::Config, + req: fastn_core::http::Request, +) -> fastn_core::Result { let _lock = LOCK.write().await; - fastn_core::apis::sync2(&req, req.json()?).await + fastn_core::apis::sync2(config, req.json()?).await } -pub async fn clone( - req: fastn_core::http::Request, -) -> fastn_core::Result { +pub async fn clone(config: &fastn_core::Config) -> fastn_core::Result { let _lock = LOCK.read().await; - fastn_core::apis::clone(req).await + fastn_core::apis::clone(config).await } pub(crate) async fn view_source( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { let _lock = LOCK.read().await; - Ok(fastn_core::apis::view_source(&req).await) + Ok(fastn_core::apis::view_source(config, &req).await) } pub(crate) async fn edit_source( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { let _lock = LOCK.read().await; - Ok(fastn_core::apis::edit_source(&req).await) + Ok(fastn_core::apis::edit_source(config, &req).await) } pub async fn edit( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { let _lock = LOCK.write().await; - fastn_core::apis::edit(&req, req.json()?).await + fastn_core::apis::edit(config, &req, req.json()?).await } pub async fn revert( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { let _lock = LOCK.write().await; - fastn_core::apis::edit::revert(&req, req.json()?).await + fastn_core::apis::edit::revert(config, req.json()?).await } pub async fn editor_sync( - req: fastn_core::http::Request, + config: &fastn_core::Config, ) -> fastn_core::Result { let _lock = LOCK.write().await; - fastn_core::apis::edit::sync(req).await + fastn_core::apis::edit::sync(config).await } pub async fn create_cr( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { let _lock = LOCK.write().await; - fastn_core::apis::cr::create_cr(&req, req.json()?).await + fastn_core::apis::cr::create_cr(config, req.json()?).await } pub async fn create_cr_page( + config: &fastn_core::Config, req: fastn_core::http::Request, ) -> fastn_core::Result { let _lock = LOCK.read().await; - fastn_core::apis::cr::create_cr_page(req).await + fastn_core::apis::cr::create_cr_page(config, req).await } -struct AppData { - edition: Option, - external_js: Vec, - inline_js: Vec, - external_css: Vec, - inline_css: Vec, - package_name: String, +#[derive(serde::Deserialize, Default, Clone)] +pub(crate) struct AppData { + pub(crate) edition: Option, + pub(crate) external_js: Vec, + pub(crate) inline_js: Vec, + pub(crate) external_css: Vec, + pub(crate) inline_css: Vec, + pub(crate) package_name: String, } fn handle_default_route( @@ -592,7 +583,7 @@ fn handle_default_route( let theme_css = ftd::theme_css(); return theme_css.get(theme).cloned().map(|theme| { actix_web::HttpResponse::Ok() - .content_type(mime_guess::mime::TEXT_JAVASCRIPT) + .content_type(mime_guess::mime::TEXT_CSS) .body(theme) }); } else if req.path().ends_with(fastn_core::utils::hashed_prism_js()) { @@ -604,7 +595,7 @@ fn handle_default_route( } else if req.path().ends_with(fastn_core::utils::hashed_prism_css()) { return Some( actix_web::HttpResponse::Ok() - .content_type(mime_guess::mime::TEXT_JAVASCRIPT) + .content_type(mime_guess::mime::TEXT_CSS) .body(ftd::prism_css()), ); } @@ -625,53 +616,54 @@ async fn test() -> fastn_core::Result { } #[tracing::instrument(skip_all)] -async fn route( +async fn actual_route( + config: &fastn_core::Config, req: actix_web::HttpRequest, body: actix_web::web::Bytes, - app_data: actix_web::web::Data, + package_name: &str, ) -> fastn_core::Result { tracing::info!(method = req.method().as_str(), uri = req.path()); tracing::info!(tutor_mode = fastn_core::tutor::is_tutor()); - let package_name = &app_data.package_name; - - if let Some(default_response) = handle_default_route(&req, package_name.as_str()) { + if let Some(default_response) = handle_default_route(&req, package_name) { return Ok(default_response); } let req = fastn_core::http::Request::from_actix(req, body); match (req.method().to_lowercase().as_str(), req.path()) { - ("post", "/-/sync/") if cfg!(feature = "remote") => sync(req).await, - ("post", "/-/sync2/") if cfg!(feature = "remote") => sync2(req).await, - ("get", "/-/clone/") if cfg!(feature = "remote") => clone(req).await, - ("get", t) if t.starts_with("/-/view-src/") => view_source(req).await, - ("get", t) if t.starts_with("/-/edit-src/") => edit_source(req).await, + ("post", "/-/sync/") if cfg!(feature = "remote") => sync(config, req).await, + ("post", "/-/sync2/") if cfg!(feature = "remote") => sync2(config, req).await, + ("get", "/-/clone/") if cfg!(feature = "remote") => clone(config).await, + ("get", t) if t.starts_with("/-/view-src/") => view_source(config, req).await, + ("get", t) if t.starts_with("/-/edit-src/") => edit_source(config, req).await, ("get", t) if t.starts_with("/-/auth/") => fastn_core::auth::routes::handle_auth(req).await, - ("post", "/-/edit/") => edit(req).await, - ("post", "/-/revert/") => revert(req).await, - ("get", "/-/editor-sync/") => editor_sync(req).await, - ("post", "/-/create-cr/") => create_cr(req).await, - ("get", "/-/create-cr-page/") => create_cr_page(req).await, - ("get", "/-/clear-cache/") => clear_cache(req).await, + ("post", "/-/edit/") => edit(config, req).await, + ("post", "/-/revert/") => revert(config, req).await, + ("get", "/-/editor-sync/") => editor_sync(config).await, + ("post", "/-/create-cr/") => create_cr(config, req).await, + ("get", "/-/create-cr-page/") => create_cr_page(config, req).await, + ("get", "/-/clear-cache/") => clear_cache(config, req).await, ("get", "/-/poll/") => fastn_core::watcher::poll().await, ("get", "/favicon.ico") => favicon().await, ("get", "/test/") => test().await, ("get", "/-/pwd/") => fastn_core::tutor::pwd().await, - ("get", "/-/shutdown/") => fastn_core::tutor::shutdown().await, - (_, _) => { - serve( - req, - app_data.edition.clone(), - app_data.external_js.clone(), - app_data.inline_js.clone(), - app_data.external_css.clone(), - app_data.inline_css.clone(), - ) - .await - } + ("get", "/-/tutor.js") => fastn_core::tutor::js().await, + ("post", "/-/tutor/start/") => fastn_core::tutor::start(req.json()?).await, + ("get", "/-/tutor/stop/") => fastn_core::tutor::stop().await, + (_, _) => serve(config, req).await, } } +#[tracing::instrument(skip_all)] +async fn route( + req: actix_web::HttpRequest, + body: actix_web::web::Bytes, + app_data: actix_web::web::Data, +) -> fastn_core::Result { + let (config, package_name) = fastn_core::tutor::config(&app_data).await?; + actual_route(&config, req, body, package_name.as_str()).await +} + //noinspection HttpUrlsUsage #[allow(clippy::too_many_arguments)] pub async fn listen( @@ -689,7 +681,7 @@ pub async fn listen( env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); if package_download_base_url.is_some() { - download_init_package(package_download_base_url).await?; + download_init_package(&package_download_base_url).await?; } if cfg!(feature = "controller") { @@ -736,7 +728,7 @@ You can try without providing port, it will automatically pick unused port."#, inline_css: inline_css.clone(), package_name: package_name.clone(), })) - .wrap(actix_web_lab::middleware::CatchPanic::default()) + .wrap(fastn_core::catch_panic::CatchPanic::default()) .wrap( actix_web::middleware::Logger::new( r#""%r" %Ts %s %b %a "%{Referer}i" "%{User-Agent}i""#, diff --git a/fastn-core/src/commands/stop_tracking.rs b/fastn-core/src/commands/stop_tracking.rs index 64480f2230..5c06580c46 100644 --- a/fastn-core/src/commands/stop_tracking.rs +++ b/fastn-core/src/commands/stop_tracking.rs @@ -22,7 +22,7 @@ pub async fn handle_command(matches: &clap::ArgMatches) -> fastn_core::Result<() use fastn_core::utils::ValueOf; stop_tracking( - &fastn_core::Config::read(None, true, None).await?, + &fastn_core::Config::read(None, true).await?, matches.value_of_("source").unwrap(), matches.value_of_("target"), ) diff --git a/fastn-core/src/commands/sync_status.rs b/fastn-core/src/commands/sync_status.rs index d5de737a74..062f46de3e 100644 --- a/fastn-core/src/commands/sync_status.rs +++ b/fastn-core/src/commands/sync_status.rs @@ -11,7 +11,7 @@ pub async fn handle_command(matches: &clap::ArgMatches) -> fastn_core::Result<() use fastn_core::utils::ValueOf; sync_status( - &fastn_core::Config::read(None, true, None).await?, + &fastn_core::Config::read(None, true).await?, matches.value_of_("file"), // TODO: handle multiple files ) .await diff --git a/fastn-core/src/commands/update.rs b/fastn-core/src/commands/update.rs index 66093dad08..6b0363fe77 100644 --- a/fastn-core/src/commands/update.rs +++ b/fastn-core/src/commands/update.rs @@ -6,7 +6,7 @@ pub async fn update(config: &fastn_core::Config) -> fastn_core::Result<()> { } }; - let c = fastn_core::Config::read(None, false, None).await?; + let c = fastn_core::Config::read(None, false).await?; if c.package.dependencies.is_empty() { println!("No dependencies to update.") } else if c.package.dependencies.len() == 1 { diff --git a/fastn-core/src/config/mod.rs b/fastn-core/src/config/mod.rs index 6b3a309cde..d674494afe 100644 --- a/fastn-core/src/config/mod.rs +++ b/fastn-core/src/config/mod.rs @@ -34,13 +34,7 @@ pub struct Config { pub packages_root: camino::Utf8PathBuf, pub original_directory: camino::Utf8PathBuf, pub all_packages: std::cell::RefCell>, - pub downloaded_assets: std::collections::BTreeMap, pub global_ids: std::collections::HashMap, - pub named_parameters: Vec<(String, ftd::Value)>, - pub extra_data: std::collections::BTreeMap, - pub current_document: Option, - pub dependencies_during_render: Vec, - pub request: Option, // TODO: It should only contain reference pub ftd_edition: FTDEdition, pub ftd_external_js: Vec, pub ftd_inline_js: Vec, @@ -48,6 +42,249 @@ pub struct Config { pub ftd_inline_css: Vec, } +#[derive(Debug, Clone)] +pub struct RequestConfig { + pub named_parameters: Vec<(String, ftd::Value)>, + pub extra_data: std::collections::BTreeMap, + pub downloaded_assets: std::collections::BTreeMap, + pub current_document: Option, + pub dependencies_during_render: Vec, + pub request: fastn_core::http::Request, + pub config: Config, + /// If the current module being parsed is a markdown file, `.markdown` contains the name and + /// content of that file + pub markdown: Option<(String, String)>, + pub document_id: String, + pub translated_data: fastn_core::TranslationData, + pub base_url: String, + pub module_package_map: std::collections::BTreeMap, +} + +impl RequestConfig { + pub fn new( + config: &Config, + request: &fastn_core::http::Request, + document_id: &str, + base_url: &str, + ) -> Self { + RequestConfig { + named_parameters: vec![], + extra_data: Default::default(), + downloaded_assets: Default::default(), + current_document: None, + dependencies_during_render: vec![], + request: request.clone(), + config: config.clone(), + markdown: None, + document_id: document_id.to_string(), + translated_data: Default::default(), + base_url: base_url.to_string(), + module_package_map: Default::default(), + } + } + + pub fn doc_id(&self) -> Option { + self.current_document + .clone() + .map(|v| fastn_core::utils::id_to_path(v.as_str())) + .map(|v| v.trim().replace(std::path::MAIN_SEPARATOR, "/")) + } + + /// document_name_with_default("index.ftd") -> / + /// document_name_with_default("foo/index.ftd") -> /foo/ + /// document_name_with_default("foo/abc") -> /foo/abc/ + /// document_name_with_default("/foo/abc.ftd") -> /foo/abc/ + pub(crate) fn document_name_with_default(&self, document_path: &str) -> String { + let name = self + .doc_id() + .unwrap_or_else(|| document_path.to_string()) + .trim_matches('/') + .to_string(); + if name.is_empty() { + "/".to_string() + } else { + format!("/{}/", name) + } + } + + // -/kameri-app.herokuapp.com/ + // .packages/kameri-app.heroku.com/index.ftd + #[tracing::instrument(skip_all)] + pub async fn get_file_and_package_by_id( + &mut self, + path: &str, + ) -> fastn_core::Result { + tracing::info!(path = path); + // This function will return file and package by given path + // path can be mounted(mount-point) with other dependencies + // + // Sanitize the mountpoint request. + // Get the package and sanitized path + let package1; + + // TODO: The shitty code written by me ever + let (path_with_package_name, document, path_params, extra_data) = + if !fastn_core::file::is_static(path)? { + let (path_with_package_name, sanitized_package, sanitized_path) = match self + .config + .get_mountpoint_sanitized_path(&self.config.package, path) + { + Some((new_path, package, remaining_path, _)) => { + // Update the sitemap of the package, if it does not contain the sitemap information + if package.name != self.config.package.name { + package1 = self.config.update_sitemap(package).await?; + (new_path, &package1, remaining_path) + } else { + (new_path, package, remaining_path) + } + } + None => (path.to_string(), &self.config.package, path.to_string()), + }; + + // Getting `document` with dynamic parameters, if exists + // It will first resolve in sitemap + // Then it will resolve in the dynamic urls + let (document, path_params, extra_data) = + fastn_core::sitemap::resolve(sanitized_package, &sanitized_path)?; + + // document with package-name prefix + let document = document.map(|doc| { + format!( + "-/{}/{}", + sanitized_package.name.trim_matches('/'), + doc.trim_matches('/') + ) + }); + (path_with_package_name, document, path_params, extra_data) + } else { + (path.to_string(), None, vec![], Default::default()) + }; + + let path = path_with_package_name.as_str(); + + if let Some(id) = document { + let file_name = self.config.get_file_path_and_resolve(id.as_str()).await?; + let package = self.config.find_package_by_id(id.as_str()).await?.1; + let file = fastn_core::get_file( + package.name.to_string(), + &self.config.root.join(file_name), + &self.config.get_root_for_package(&package), + ) + .await?; + self.current_document = Some(path.to_string()); + self.named_parameters = path_params; + self.extra_data = extra_data; + Ok(file) + } else { + // -/fifthtry.github.io/todos/add-todo/ + // -/fifthtry.github.io/doc-site/add-todo/ + let file_name = self.config.get_file_path_and_resolve(path).await?; + // .packages/todos/add-todo.ftd + // .packages/fifthtry.github.io/doc-site/add-todo.ftd + + let package = self.config.find_package_by_id(path).await?.1; + let mut file = fastn_core::get_file( + package.name.to_string(), + &self.config.root.join(file_name.trim_start_matches('/')), + &self.config.get_root_for_package(&package), + ) + .await?; + + if path.contains("-/") { + let url = path.trim_end_matches("/index.html").trim_matches('/'); + let extension = if matches!(file, fastn_core::File::Markdown(_)) { + "/index.md".to_string() + } else if matches!(file, fastn_core::File::Ftd(_)) { + "/index.ftd".to_string() + } else { + "".to_string() + }; + file.set_id(format!("{}{}", url, extension).as_str()); + } + self.current_document = Some(file.get_id().to_string()); + Ok(file) + } + } + #[tracing::instrument(skip(self))] + pub(crate) async fn can_read( + &self, + document_path: &str, + with_confidential: bool, // can read should use confidential property or not + ) -> fastn_core::Result { + // Function Docs + // If user can read the document based on readers, user will have read access to page + // If user cannot read the document based on readers, and if confidential is false so user + // can access the page, and if confidential is true user will not be able to access the + // document + + // can_read: true, confidential: true => true (can access) + // can_read: true, confidential: false => true (can access) + // can_read: false, confidential: true => false (cannot access) + // can_read: false, confidential: false => true (can access) + + use itertools::Itertools; + let document_name = self.document_name_with_default(document_path); + if let Some(sitemap) = &self.config.package.sitemap { + // TODO: This can be buggy in case of: if groups are used directly in sitemap are foreign groups + let (document_readers, confidential) = + sitemap.readers(document_name.as_str(), &self.config.package.groups); + + // TODO: Need to check the confidential logic, if readers are not defined in the sitemap + if document_readers.is_empty() { + return Ok(true); + } + let access_identities = fastn_core::user_group::access_identities( + &self.config, + &self.request, + &document_name, + true, + ) + .await?; + + let belongs_to = fastn_core::user_group::belongs_to( + &self.config, + document_readers.as_slice(), + access_identities.iter().collect_vec().as_slice(), + )?; + + if with_confidential { + if belongs_to { + return Ok(true); + } + return Ok(!confidential); + } + return Ok(belongs_to); + } + Ok(true) + } + + #[tracing::instrument(skip(self))] + pub(crate) async fn can_write(&self, document_path: &str) -> fastn_core::Result { + use itertools::Itertools; + let document_name = self.document_name_with_default(document_path); + if let Some(sitemap) = &self.config.package.sitemap { + // TODO: This can be buggy in case of: if groups are used directly in sitemap are foreign groups + let document_writers = + sitemap.writers(document_name.as_str(), &self.config.package.groups); + let access_identities = fastn_core::user_group::access_identities( + &self.config, + &self.request, + &document_name, + false, + ) + .await?; + + return fastn_core::user_group::belongs_to( + &self.config, + document_writers.as_slice(), + access_identities.iter().collect_vec().as_slice(), + ); + } + + Ok(false) + } +} + impl Config { /// `build_dir` is where the static built files are stored. `fastn build` command creates this /// folder and stores its output here. @@ -148,23 +385,6 @@ impl Config { self.remote_history_dir().join(id_with_timestamp_extension) } - /// document_name_with_default("index.ftd") -> / - /// document_name_with_default("foo/index.ftd") -> /foo/ - /// document_name_with_default("foo/abc") -> /foo/abc/ - /// document_name_with_default("/foo/abc.ftd") -> /foo/abc/ - pub(crate) fn document_name_with_default(&self, document_path: &str) -> String { - let name = self - .doc_id() - .unwrap_or_else(|| document_path.to_string()) - .trim_matches('/') - .to_string(); - if name.is_empty() { - "/".to_string() - } else { - format!("/{}/", name) - } - } - /// history of a fastn package is stored in `.history` folder. /// /// Current design is wrong, we should move this helper to `fastn_core::Package` maybe. @@ -566,7 +786,7 @@ impl Config { } pub(crate) async fn get_file_and_package_by_cr_id( - &mut self, + &self, id: &str, cr_number: usize, ) -> fastn_core::Result { @@ -706,110 +926,6 @@ impl Config { Ok(package) } - // -/kameri-app.herokuapp.com/ - // .packages/kameri-app.heroku.com/index.ftd - #[tracing::instrument(skip_all)] - pub async fn get_file_and_package_by_id( - &mut self, - path: &str, - ) -> fastn_core::Result { - tracing::info!(path = path); - // This function will return file and package by given path - // path can be mounted(mount-point) with other dependencies - // - // Sanitize the mountpoint request. - // Get the package and sanitized path - let package1; - - // TODO: The shitty code written by me ever - let (path_with_package_name, document, path_params, extra_data) = - if !fastn_core::file::is_static(path)? { - let (path_with_package_name, sanitized_package, sanitized_path) = - match self.get_mountpoint_sanitized_path(&self.package, path) { - Some((new_path, package, remaining_path, _)) => { - // Update the sitemap of the package, if it does not contain the sitemap information - if package.name != self.package.name { - package1 = self.update_sitemap(package).await?; - (new_path, &package1, remaining_path) - } else { - (new_path, package, remaining_path) - } - } - None => (path.to_string(), &self.package, path.to_string()), - }; - - // Getting `document` with dynamic parameters, if exists - // It will first resolve in sitemap - // Then it will resolve in the dynamic urls - let (document, path_params, extra_data) = - fastn_core::sitemap::resolve(sanitized_package, &sanitized_path)?; - - // document with package-name prefix - let document = document.map(|doc| { - format!( - "-/{}/{}", - sanitized_package.name.trim_matches('/'), - doc.trim_matches('/') - ) - }); - (path_with_package_name, document, path_params, extra_data) - } else { - (path.to_string(), None, vec![], Default::default()) - }; - - let path = path_with_package_name.as_str(); - - if let Some(id) = document { - let file_name = self.get_file_path_and_resolve(id.as_str()).await?; - let package = self.find_package_by_id(id.as_str()).await?.1; - let file = fastn_core::get_file( - package.name.to_string(), - &self.root.join(file_name), - &self.get_root_for_package(&package), - ) - .await?; - self.current_document = Some(path.to_string()); - self.named_parameters = path_params; - self.extra_data = extra_data; - Ok(file) - } else { - // -/fifthtry.github.io/todos/add-todo/ - // -/fifthtry.github.io/doc-site/add-todo/ - let file_name = self.get_file_path_and_resolve(path).await?; - // .packages/todos/add-todo.ftd - // .packages/fifthtry.github.io/doc-site/add-todo.ftd - - let package = self.find_package_by_id(path).await?.1; - let mut file = fastn_core::get_file( - package.name.to_string(), - &self.root.join(file_name.trim_start_matches('/')), - &self.get_root_for_package(&package), - ) - .await?; - - if path.contains("-/") { - let url = path.trim_end_matches("/index.html").trim_matches('/'); - let extension = if matches!(file, fastn_core::File::Markdown(_)) { - "/index.md".to_string() - } else if matches!(file, fastn_core::File::Ftd(_)) { - "/index.ftd".to_string() - } else { - "".to_string() - }; - file.set_id(format!("{}{}", url, extension).as_str()); - } - self.current_document = Some(file.get_id().to_string()); - Ok(file) - } - } - - pub fn doc_id(&self) -> Option { - self.current_document - .clone() - .map(|v| fastn_core::utils::id_to_path(v.as_str())) - .map(|v| v.trim().replace(std::path::MAIN_SEPARATOR, "/")) - } - pub async fn get_file_path(&self, id: &str) -> fastn_core::Result { let (package_name, package) = self.find_package_by_id(id).await?; let mut id = id.to_string(); @@ -1251,7 +1367,6 @@ impl Config { pub async fn read( root: Option, resolve_sitemap: bool, - req: Option<&fastn_core::http::Request>, ) -> fastn_core::Result { let (root, original_directory) = match root { Some(r) => { @@ -1280,19 +1395,13 @@ impl Config { packages_root: root.clone().join(".packages"), root, original_directory, - current_document: None, all_packages: Default::default(), - downloaded_assets: Default::default(), - extra_data: Default::default(), global_ids: Default::default(), - request: req.map(ToOwned::to_owned), - named_parameters: vec![], ftd_edition: FTDEdition::default(), ftd_external_js: Default::default(), ftd_inline_js: Default::default(), ftd_external_css: Default::default(), ftd_inline_css: Default::default(), - dependencies_during_render: Default::default(), }; // Update global_ids map from the current package files @@ -1351,11 +1460,6 @@ impl Config { Ok(config) } - pub fn set_request(mut self, req: fastn_core::http::Request) -> Self { - self.request = Some(req); - self - } - pub(crate) async fn resolve_package( &self, package: &fastn_core::Package, @@ -1418,77 +1522,4 @@ impl Config { (value - (number_of_crs_to_reserve as i32))..value, )) } - - #[tracing::instrument(skip(req, self))] - pub(crate) async fn can_read( - &self, - req: &fastn_core::http::Request, - document_path: &str, - with_confidential: bool, // can read should use confidential property or not - ) -> fastn_core::Result { - // Function Docs - // If user can read the document based on readers, user will have read access to page - // If user cannot read the document based on readers, and if confidential is false so user - // can access the page, and if confidential is true user will not be able to access the - // document - - // can_read: true, confidential: true => true (can access) - // can_read: true, confidential: false => true (can access) - // can_read: false, confidential: true => false (cannot access) - // can_read: false, confidential: false => true (can access) - - use itertools::Itertools; - let document_name = self.document_name_with_default(document_path); - if let Some(sitemap) = &self.package.sitemap { - // TODO: This can be buggy in case of: if groups are used directly in sitemap are foreign groups - let (document_readers, confidential) = - sitemap.readers(document_name.as_str(), &self.package.groups); - - // TODO: Need to check the confidential logic, if readers are not defined in the sitemap - if document_readers.is_empty() { - return Ok(true); - } - let access_identities = - fastn_core::user_group::access_identities(self, req, &document_name, true).await?; - - let belongs_to = fastn_core::user_group::belongs_to( - self, - document_readers.as_slice(), - access_identities.iter().collect_vec().as_slice(), - )?; - - if with_confidential { - if belongs_to { - return Ok(true); - } - return Ok(!confidential); - } - return Ok(belongs_to); - } - Ok(true) - } - - #[tracing::instrument(skip(req, self))] - pub(crate) async fn can_write( - &self, - req: &fastn_core::http::Request, - document_path: &str, - ) -> fastn_core::Result { - use itertools::Itertools; - let document_name = self.document_name_with_default(document_path); - if let Some(sitemap) = &self.package.sitemap { - // TODO: This can be buggy in case of: if groups are used directly in sitemap are foreign groups - let document_writers = sitemap.writers(document_name.as_str(), &self.package.groups); - let access_identities = - fastn_core::user_group::access_identities(self, req, &document_name, false).await?; - - return fastn_core::user_group::belongs_to( - self, - document_writers.as_slice(), - access_identities.iter().collect_vec().as_slice(), - ); - } - - Ok(false) - } } diff --git a/fastn-core/src/controller.rs b/fastn-core/src/controller.rs index a39ed203f9..64bdedd650 100644 --- a/fastn-core/src/controller.rs +++ b/fastn-core/src/controller.rs @@ -78,7 +78,7 @@ pub async fn resolve_dependencies( ); // Resolve dependencies by reading the FASTN.ftd using config.read() // Assuming package_name and repo name are identical - fastn_core::Config::read(None, false, None).await?; + fastn_core::Config::read(None, false).await?; } else { return Err(fastn_core::Error::APIResponseError(format!( "Package {} Cloning failed: {}", diff --git a/fastn-core/src/doc.rs b/fastn-core/src/doc.rs index 2d3b988118..dd6fd4853a 100644 --- a/fastn-core/src/doc.rs +++ b/fastn-core/src/doc.rs @@ -26,10 +26,10 @@ fn cached_parse( } #[tracing::instrument(skip_all)] -pub async fn interpret_helper<'a>( +pub async fn interpret_helper( name: &str, source: &str, - lib: &'a mut fastn_core::Library2022, + lib: &mut fastn_core::Library2022, base_url: &str, download_assets: bool, line_number: usize, @@ -56,7 +56,7 @@ pub async fn interpret_helper<'a>( let (source, path, foreign_variable, foreign_function, ignore_line_numbers) = resolve_import_2022(lib, &mut st, module.as_str(), caller_module.as_str()) .await?; - lib.config.dependencies_during_render.push(path); + lib.dependencies_during_render.push(path); let doc = cached_parse(module.as_str(), source.as_str(), ignore_line_numbers)?; s = st.continue_after_import( module.as_str(), @@ -112,8 +112,8 @@ pub async fn interpret_helper<'a>( Ok(document) } -pub async fn resolve_import<'a>( - lib: &'a mut fastn_core::Library2, +pub async fn resolve_import( + lib: &mut fastn_core::Library2, state: &mut ftd::ftd2021::InterpreterState, module: &str, ) -> ftd::ftd2021::p1::Result { @@ -138,6 +138,7 @@ pub async fn resolve_import<'a>( if module.starts_with(alias) { lib.push_package_under_process(package).await?; font_ftd = lib + .config .config .all_packages .borrow() @@ -158,8 +159,8 @@ pub async fn resolve_import<'a>( } // source, foreign_variable, foreign_function -pub async fn resolve_import_2022<'a>( - lib: &'a mut fastn_core::Library2022, +pub async fn resolve_import_2022( + lib: &mut fastn_core::Library2022, _state: &mut ftd::interpreter::InterpreterState, module: &str, caller_module: &str, @@ -202,6 +203,7 @@ pub async fn resolve_import_2022<'a>( "is-reader".to_string(), "sql".to_string(), "package-query".to_string(), + "tutor".to_string(), "pg".to_string(), "package-tree".to_string(), "fetch-file".to_string(), @@ -254,6 +256,7 @@ pub async fn resolve_import_2022<'a>( "http".to_string(), "sql".to_string(), "package-query".to_string(), + "tutor".to_string(), "pg".to_string(), "toc".to_string(), "include".to_string(), @@ -350,7 +353,7 @@ pub async fn resolve_foreign_variable2022( module: &str, package: &fastn_core::Package, files: &str, - lib: &mut fastn_core::Library2022, + lib: &mut fastn_core::RequestConfig, base_url: &str, download_assets: bool, // true: in case of `fastn build` ) -> ftd::ftd2021::p1::Result { @@ -390,7 +393,6 @@ pub async fn resolve_foreign_variable2022( let light_path = format!("{}.{}", file.replace('.', "/"), ext); if download_assets && !lib - .config .downloaded_assets .contains_key(&format!("{}/{}", package.name, light_path)) { @@ -415,7 +417,7 @@ pub async fn resolve_foreign_variable2022( doc_id: lib.document_id.to_string(), line_number: 0, })?; - lib.config.downloaded_assets.insert( + lib.downloaded_assets.insert( format!("{}/{}", package.name, light_path), light_mode.to_string(), ); @@ -448,7 +450,6 @@ pub async fn resolve_foreign_variable2022( if download_assets && !file.ends_with("-dark") { let start = std::time::Instant::now(); if let Some(dark) = lib - .config .downloaded_assets .get(&format!("{}/{}", package.name, dark_path)) { @@ -478,7 +479,7 @@ pub async fn resolve_foreign_variable2022( } else { dark_mode = light_mode.clone(); } - lib.config.downloaded_assets.insert( + lib.downloaded_assets.insert( format!("{}/{}", package.name, dark_path), dark_mode.to_string(), ); @@ -543,7 +544,6 @@ async fn download( ) -> ftd::ftd2021::p1::Result<()> { if download_assets && !lib - .config .downloaded_assets .contains_key(&format!("{}/{}", package.name, path)) { @@ -568,7 +568,7 @@ async fn download( doc_id: lib.document_id.to_string(), line_number: 0, })?; - lib.config.downloaded_assets.insert( + lib.downloaded_assets.insert( format!("{}/{}", package.name, path), format!("-/{}/{}", package.name, path), ); @@ -680,7 +680,11 @@ pub async fn resolve_foreign_variable2( })?; print!("Processing {}/{} ... ", package.name.as_str(), light_path); fastn_core::utils::write( - &lib.config.build_dir().join("-").join(package.name.as_str()), + &lib.config + .config + .build_dir() + .join("-") + .join(package.name.as_str()), light_path.as_str(), light.as_slice(), ) @@ -735,7 +739,11 @@ pub async fn resolve_foreign_variable2( { print!("Processing {}/{} ... ", package.name.as_str(), dark_path); fastn_core::utils::write( - &lib.config.build_dir().join("-").join(package.name.as_str()), + &lib.config + .config + .build_dir() + .join("-") + .join(package.name.as_str()), dark_path.as_str(), dark.as_slice(), ) diff --git a/fastn-core/src/error.rs b/fastn-core/src/error.rs index 8fd75af171..ffe119e823 100644 --- a/fastn-core/src/error.rs +++ b/fastn-core/src/error.rs @@ -90,6 +90,12 @@ pub enum Error { TokioMPSCError2(#[from] tokio::sync::mpsc::error::SendError), } +impl From for Error { + fn from(_: std::convert::Infallible) -> Self { + unreachable!() + } +} + impl Error { pub fn generic + ToString>(error: T) -> Self { Self::GenericError(error.to_string()) diff --git a/fastn-core/src/http.rs b/fastn-core/src/http.rs index 6dbb9131c7..40af4beb04 100644 --- a/fastn-core/src/http.rs +++ b/fastn-core/src/http.rs @@ -73,7 +73,7 @@ pub fn ok_with_content_type( .body(data) } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Request { method: String, uri: String, diff --git a/fastn-core/src/lib.rs b/fastn-core/src/lib.rs index 696d5f9baf..51bdd263bc 100644 --- a/fastn-core/src/lib.rs +++ b/fastn-core/src/lib.rs @@ -14,7 +14,7 @@ mod file; mod font; mod history; mod package; -pub(crate) mod tutor; +pub mod tutor; pub(crate) mod watcher; #[macro_use] mod http; @@ -32,6 +32,7 @@ mod tracker; mod translation; mod version; // mod wasm; +pub(crate) mod catch_panic; mod library2022; mod workspace; @@ -44,7 +45,7 @@ pub use commands::{ start_tracking::start_tracking, status::status, sync2::sync2, translation_status::translation_status, update::update, }; -pub use config::{Config, FTDEdition}; +pub use config::{Config, FTDEdition, RequestConfig}; pub use error::Error; pub use file::File; pub(crate) use file::{get_file, paths_to_files, Document, Static}; @@ -57,7 +58,7 @@ pub(crate) use package::Package; pub(crate) use snapshot::Snapshot; pub(crate) use tracker::Track; pub(crate) use translation::{TranslatedDocument, TranslationData}; -pub(crate) use utils::{copy_dir_all, time, timestamp_nanosecond}; +pub(crate) use utils::{copy_dir_all, timestamp_nanosecond}; pub(crate) use version::Version; pub use {doc::resolve_foreign_variable2, doc::resolve_import}; diff --git a/fastn-core/src/library/document.rs b/fastn-core/src/library/document.rs index 9679c9d811..a74c07dbbc 100644 --- a/fastn-core/src/library/document.rs +++ b/fastn-core/src/library/document.rs @@ -44,13 +44,13 @@ pub fn convert_to_document_id(doc_name: &str) -> String { } pub fn document_full_id( - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, doc: &ftd::ftd2021::p2::TDoc, ) -> ftd::ftd2021::p1::Result { - let full_document_id = config.doc_id().unwrap_or_else(|| { + let full_document_id = req_config.doc_id().unwrap_or_else(|| { doc.name .to_string() - .replace(config.package.name.as_str(), "") + .replace(req_config.config.package.name.as_str(), "") }); if full_document_id.trim_matches('/').is_empty() { @@ -60,93 +60,93 @@ pub fn document_full_id( Ok(format!("/{}/", full_document_id.trim_matches('/'))) } -#[allow(dead_code)] -pub mod processor { - pub fn document_id( - _section: &ftd::ftd2021::p1::Section, - doc: &ftd::ftd2021::p2::TDoc, - config: &fastn_core::Config, - ) -> ftd::ftd2021::p1::Result { - let doc_id = config.doc_id().unwrap_or_else(|| { - doc.name - .to_string() - .replace(config.package.name.as_str(), "") - }); - - let document_id = doc_id - .split_once("/-/") - .map(|x| x.0) - .unwrap_or_else(|| &doc_id) - .trim_matches('/'); - - Ok(ftd::Value::String { - text: format!("/{}/", document_id), - source: ftd::TextSource::Default, - }) - } - pub fn document_full_id( - _section: &ftd::ftd2021::p1::Section, - doc: &ftd::ftd2021::p2::TDoc, - config: &fastn_core::Config, - ) -> ftd::ftd2021::p1::Result { - Ok(ftd::Value::String { - text: super::document_full_id(config, doc)?, - source: ftd::TextSource::Default, - }) - } - - pub async fn document_name<'a>( - section: &ftd::ftd2021::p1::Section, - doc: &ftd::ftd2021::p2::TDoc<'a>, - config: &fastn_core::Config, - ) -> ftd::ftd2021::p1::Result { - let doc_id = config.doc_id().unwrap_or_else(|| { - doc.name - .to_string() - .replace(config.package.name.as_str(), "") - }); - - let file_path = config.get_file_path(&doc_id).await.map_err(|e| { - ftd::ftd2021::p1::Error::ParseError { - message: e.to_string(), - doc_id: doc.name.to_string(), - line_number: section.line_number, - } - })?; - - Ok(ftd::Value::String { - text: file_path.trim().to_string(), - source: ftd::TextSource::Default, - }) - } - - pub fn document_suffix( - _section: &ftd::ftd2021::p1::Section, - doc: &ftd::ftd2021::p2::TDoc, - config: &fastn_core::Config, - ) -> ftd::ftd2021::p1::Result { - let doc_id = config.doc_id().unwrap_or_else(|| { - doc.name - .to_string() - .replace(config.package.name.as_str(), "") - }); - - let value = doc_id - .split_once("/-/") - .map(|(_, y)| y.trim().to_string()) - .map(|suffix| ftd::Value::String { - text: suffix, - source: ftd::TextSource::Default, - }); - - Ok(ftd::Value::Optional { - data: Box::new(value), - kind: ftd::ftd2021::p2::Kind::String { - caption: false, - body: false, - default: None, - is_reference: false, - }, - }) - } -} +// #[allow(dead_code)] +// pub mod processor { +// pub fn document_id( +// _section: &ftd::ftd2021::p1::Section, +// doc: &ftd::ftd2021::p2::TDoc, +// config: &fastn_core::Config, +// ) -> ftd::ftd2021::p1::Result { +// let doc_id = config.doc_id().unwrap_or_else(|| { +// doc.name +// .to_string() +// .replace(config.package.name.as_str(), "") +// }); +// +// let document_id = doc_id +// .split_once("/-/") +// .map(|x| x.0) +// .unwrap_or_else(|| &doc_id) +// .trim_matches('/'); +// +// Ok(ftd::Value::String { +// text: format!("/{}/", document_id), +// source: ftd::TextSource::Default, +// }) +// } +// pub fn document_full_id( +// _section: &ftd::ftd2021::p1::Section, +// doc: &ftd::ftd2021::p2::TDoc, +// config: &fastn_core::Config, +// ) -> ftd::ftd2021::p1::Result { +// Ok(ftd::Value::String { +// text: super::document_full_id(config, doc)?, +// source: ftd::TextSource::Default, +// }) +// } +// +// pub async fn document_name<'a>( +// section: &ftd::ftd2021::p1::Section, +// doc: &ftd::ftd2021::p2::TDoc<'a>, +// config: &fastn_core::Config, +// ) -> ftd::ftd2021::p1::Result { +// let doc_id = config.doc_id().unwrap_or_else(|| { +// doc.name +// .to_string() +// .replace(config.package.name.as_str(), "") +// }); +// +// let file_path = config.get_file_path(&doc_id).await.map_err(|e| { +// ftd::ftd2021::p1::Error::ParseError { +// message: e.to_string(), +// doc_id: doc.name.to_string(), +// line_number: section.line_number, +// } +// })?; +// +// Ok(ftd::Value::String { +// text: file_path.trim().to_string(), +// source: ftd::TextSource::Default, +// }) +// } +// +// pub fn document_suffix( +// _section: &ftd::ftd2021::p1::Section, +// doc: &ftd::ftd2021::p2::TDoc, +// req_config: &fastn_core::RequestConfig, +// ) -> ftd::ftd2021::p1::Result { +// let doc_id = req_config.config.doc_id().unwrap_or_else(|| { +// doc.name +// .to_string() +// .replace(config.package.name.as_str(), "") +// }); +// +// let value = doc_id +// .split_once("/-/") +// .map(|(_, y)| y.trim().to_string()) +// .map(|suffix| ftd::Value::String { +// text: suffix, +// source: ftd::TextSource::Default, +// }); +// +// Ok(ftd::Value::Optional { +// data: Box::new(value), +// kind: ftd::ftd2021::p2::Kind::String { +// caption: false, +// body: false, +// default: None, +// is_reference: false, +// }, +// }) +// } +// } diff --git a/fastn-core/src/library/fastn_dot_ftd.rs b/fastn-core/src/library/fastn_dot_ftd.rs index 716674b3fa..1085ec864b 100644 --- a/fastn-core/src/library/fastn_dot_ftd.rs +++ b/fastn-core/src/library/fastn_dot_ftd.rs @@ -1,14 +1,14 @@ use crate::utils::HasElements; async fn i18n_data(lib: &fastn_core::Library) -> String { - let lang = match lib.config.package.language { + let lang = match lib.config.config.package.language { Some(ref lang) => { realm_lang::Language::from_2_letter_code(lang).unwrap_or(realm_lang::Language::English) } None => realm_lang::Language::English, }; - let primary_lang = match lib.config.package.translation_of.as_ref() { + let primary_lang = match lib.config.config.package.translation_of.as_ref() { Some(ref package) => match package.language { Some(ref lang) => realm_lang::Language::from_2_letter_code(lang) .unwrap_or(realm_lang::Language::English), @@ -19,7 +19,7 @@ async fn i18n_data(lib: &fastn_core::Library) -> String { let current_document_last_modified_on = fastn_core::utils::get_current_document_last_modified_on( - &lib.config, + &lib.config.config, lib.document_id.as_str(), ) .await; @@ -261,14 +261,14 @@ pub(crate) async fn get2022_(lib: &fastn_core::Library) -> String { capital_fastn = capital_fastn(lib), build_info = construct_fastn_cli_variables(lib), document_id = lib.document_id, - title = lib.config.package.name, - package_name = lib.config.package.name, - home_url = format!("https://{}", lib.config.package.name), + title = lib.config.config.package.name, + package_name = lib.config.config.package.name, + home_url = format!("https://{}", lib.config.config.package.name), ); - if let Ok(number_of_documents) = - futures::executor::block_on(fastn_core::utils::get_number_of_documents(&lib.config)) - { + if let Ok(number_of_documents) = futures::executor::block_on( + fastn_core::utils::get_number_of_documents(&lib.config.config), + ) { fastn_base = format!( indoc::indoc! {" {fastn_base} @@ -323,12 +323,12 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { i18n_data = i18n_data(lib).await, build_info = construct_fastn_cli_variables(lib), document_id = lib.document_id, - title = lib.config.package.name, - package_name = lib.config.package.name, - home_url = format!("https://{}", lib.config.package.name), + title = lib.config.config.package.name, + package_name = lib.config.config.package.name, + home_url = format!("https://{}", lib.config.config.package.name), ); - if lib.config.package.translation_of.is_some() { + if lib.config.config.package.translation_of.is_some() { fastn_base = format!( indoc::indoc! {" {fastn_base} @@ -339,7 +339,7 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { ); } - if lib.config.package.translations.has_elements() { + if lib.config.config.package.translations.has_elements() { fastn_base = format!( indoc::indoc! {" {fastn_base} @@ -350,7 +350,7 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { ); } - if let Some(ref zip) = lib.config.package.zip { + if let Some(ref zip) = lib.config.config.package.zip { fastn_base = format!( indoc::indoc! {" {fastn_base} @@ -390,7 +390,8 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { ); } - if lib.config.package.translation_of.is_some() || lib.config.package.translations.has_elements() + if lib.config.config.package.translation_of.is_some() + || lib.config.config.package.translations.has_elements() { fastn_base = format!( indoc::indoc! {" @@ -400,13 +401,13 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { "}, fastn_base = fastn_base, - package_name = lib.config.package.name, + package_name = lib.config.config.package.name, ); } - if let Ok(number_of_documents) = - futures::executor::block_on(fastn_core::utils::get_number_of_documents(&lib.config)) - { + if let Ok(number_of_documents) = futures::executor::block_on( + fastn_core::utils::get_number_of_documents(&lib.config.config), + ) { fastn_base = format!( indoc::indoc! {" {fastn_base} @@ -418,9 +419,9 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { ); } - if let Some(last_modified_on) = - futures::executor::block_on(fastn_core::utils::get_last_modified_on(&lib.config.root)) - { + if let Some(last_modified_on) = futures::executor::block_on( + fastn_core::utils::get_last_modified_on(&lib.config.config.root), + ) { fastn_base = format!( indoc::indoc! {" {fastn_base} @@ -434,7 +435,7 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { if let Some(last_modified_on) = futures::executor::block_on(fastn_core::utils::get_current_document_last_modified_on( - &lib.config, + &lib.config.config, lib.document_id.as_str(), )) { @@ -449,7 +450,7 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { ); } - if let Some(ref language) = lib.config.package.language { + if let Some(ref language) = lib.config.config.package.language { fastn_base = format!( indoc::indoc! {" {fastn_base} @@ -519,7 +520,7 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { ); } - if let Ok(original_path) = lib.config.original_path() { + if let Ok(original_path) = lib.config.config.original_path() { let base_url = lib .base_url .as_str() @@ -537,7 +538,7 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { if let Ok(translation_status) = fastn_core::commands::translation_status::get_translation_status( &original_snapshots, - &lib.config.root, + &lib.config.config.root, ) { let mut never_marked_files = "".to_string(); @@ -681,9 +682,9 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { } } - if lib.config.package.translations.has_elements() { + if lib.config.config.package.translations.has_elements() { let mut translation_status_list = "".to_string(); - for translation in lib.config.package.translations.iter() { + for translation in lib.config.config.package.translations.iter() { if let Some(ref status) = translation.translation_status_summary { if let Some(ref language) = translation.language { let url = format!("https://{}/-/translation-status/", translation.name); @@ -742,7 +743,7 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { } let other_language_packages = - if let Some(translation_of) = lib.config.package.translation_of.as_ref() { + if let Some(translation_of) = lib.config.config.package.translation_of.as_ref() { let mut other_language_packages = translation_of .translations .iter() @@ -751,6 +752,7 @@ pub(crate) async fn get(lib: &fastn_core::Library) -> String { other_language_packages } else { lib.config + .config .package .translations .iter() @@ -824,7 +826,7 @@ pub(crate) async fn get2(lib: &fastn_core::Library2) -> String { pub(crate) async fn get2022(lib: &fastn_core::Library2022) -> String { let lib = fastn_core::Library { - config: lib.config.clone(), + config: lib.clone(), markdown: lib.markdown.clone(), document_id: lib.document_id.clone(), translated_data: lib.translated_data.clone(), @@ -839,14 +841,14 @@ fn capital_fastn(lib: &fastn_core::Library) -> String { indoc::indoc! {" -- package-data package: {package_name} "}, - package_name = lib.config.package.name, + package_name = lib.config.config.package.name, ); - if let Some(ref zip) = lib.config.package.zip { + if let Some(ref zip) = lib.config.config.package.zip { s.push_str(format!("zip: {}", zip).as_str()); } - if let Some(ref favicon) = lib.config.package.favicon { + if let Some(ref favicon) = lib.config.config.package.favicon { s.push_str(format!("\nfavicon: {}", favicon).as_str()); } diff --git a/fastn-core/src/library/mod.rs b/fastn-core/src/library/mod.rs index 42df90e8fa..2e172386e7 100644 --- a/fastn-core/src/library/mod.rs +++ b/fastn-core/src/library/mod.rs @@ -7,7 +7,7 @@ pub use fastn_core::Library2022; #[derive(Debug)] pub struct Library { - pub config: fastn_core::Config, + pub config: fastn_core::RequestConfig, /// If the current module being parsed is a markdown file, `.markdown` contains the name and /// content of that file pub markdown: Option<(String, String)>, @@ -58,7 +58,7 @@ impl Library { for (alias, package) in package.to_owned().aliases() { if name.starts_with(alias) { - let package = lib.config.resolve_package(package).await.ok()?; + let package = lib.config.config.resolve_package(package).await.ok()?; if let Some(r) = get_data_from_package( name.replacen(alias, &package.name, 1).as_str(), &package, @@ -122,8 +122,8 @@ impl Library { package: &fastn_core::Package, lib: &Library, ) -> Option { - let path = lib.config.get_root_for_package(package); - fastn_core::Config::download_required_file(&lib.config.root, name, package) + let path = lib.config.config.get_root_for_package(package); + fastn_core::Config::download_required_file(&lib.config.config.root, name, package) .await .ok()?; // Explicit check for the current package. @@ -148,7 +148,7 @@ impl Library { #[derive(Debug)] pub struct Library2 { - pub config: fastn_core::Config, + pub config: fastn_core::RequestConfig, /// If the current module being parsed is a markdown file, `.markdown` contains the name and /// content of that file pub markdown: Option<(String, String)>, @@ -165,6 +165,7 @@ impl Library2 { ) -> ftd::ftd2021::p1::Result<()> { self.packages_under_process.push(package.name.to_string()); if self + .config .config .all_packages .borrow() @@ -173,15 +174,19 @@ impl Library2 { return Ok(()); } - let package = self.config.resolve_package(package).await.map_err(|_| { - ftd::ftd2021::p1::Error::ParseError { + let package = self + .config + .config + .resolve_package(package) + .await + .map_err(|_| ftd::ftd2021::p1::Error::ParseError { message: format!("Cannot resolve the package: {}", package.name), doc_id: self.document_id.to_string(), line_number: 0, - } - })?; + })?; self.config + .config .all_packages .borrow_mut() .insert(package.name.to_string(), package); @@ -198,6 +203,7 @@ impl Library2 { })?; self.config + .config .all_packages .borrow() .get(current_package_name) @@ -288,7 +294,7 @@ impl Library2 { lib: &mut Library2, ) -> Option { lib.push_package_under_process(package).await.ok()?; - let packages = lib.config.all_packages.borrow(); + let packages = lib.config.config.all_packages.borrow(); let package = packages.get(package.name.as_str()).unwrap_or(package); // Explicit check for the current package. if !name.starts_with(package.name.as_str()) { @@ -296,7 +302,11 @@ impl Library2 { } let new_name = name.replacen(package.name.as_str(), "", 1); let (file_path, data) = package - .resolve_by_id(new_name.as_str(), None, lib.config.package.name.as_str()) + .resolve_by_id( + new_name.as_str(), + None, + lib.config.config.package.name.as_str(), + ) .await .ok()?; if !file_path.ends_with(".ftd") { diff --git a/fastn-core/src/library2022/mod.rs b/fastn-core/src/library2022/mod.rs index f1647820a2..d866c69f71 100644 --- a/fastn-core/src/library2022/mod.rs +++ b/fastn-core/src/library2022/mod.rs @@ -13,17 +13,7 @@ impl KeyValueData { } } -#[derive(Debug)] -pub struct Library2022 { - pub config: fastn_core::Config, - /// If the current module being parsed is a markdown file, `.markdown` contains the name and - /// content of that file - pub markdown: Option<(String, String)>, - pub document_id: String, - pub translated_data: fastn_core::TranslationData, - pub base_url: String, - pub module_package_map: std::collections::BTreeMap, -} +pub type Library2022 = fastn_core::RequestConfig; impl Library2022 { pub async fn get_with_result( @@ -228,83 +218,49 @@ impl Library2022 { "figma-typo-token" => { processor::figma_typography_tokens::process_typography_tokens(value, kind, doc) } - "figma-cs-token" => { - processor::figma_tokens::process_figma_tokens(value, kind, doc, &self.config) - } + "figma-cs-token" => processor::figma_tokens::process_figma_tokens(value, kind, doc), "figma-cs-token-old" => { - processor::figma_tokens::process_figma_tokens_old(value, kind, doc, &self.config) + processor::figma_tokens::process_figma_tokens_old(value, kind, doc) } - "http" => processor::http::process(value, kind, doc, &self.config).await, - "tutor" => fastn_core::tutor::process(value, kind, doc).await, - "toc" => processor::toc::process(value, kind, doc, &self.config), - "get-data" => processor::get_data::process(value, kind, doc, &self.config), - "sitemap" => processor::sitemap::process(value, kind, doc, &self.config), - "full-sitemap" => { - processor::sitemap::full_sitemap_process(value, kind, doc, &self.config) - } - "request-data" => processor::request_data::process(value, kind, doc, &self.config), + "http" => processor::http::process(value, kind, doc, self).await, + "tutor-data" => fastn_core::tutor::process(value, kind, doc).await, + "toc" => processor::toc::process(value, kind, doc), + "get-data" => processor::get_data::process(value, kind, doc, self), + "sitemap" => processor::sitemap::process(value, kind, doc, self), + "full-sitemap" => processor::sitemap::full_sitemap_process(value, kind, doc, self), + "request-data" => processor::request_data::process(value, kind, doc, self), "document-readers" => processor::document::process_readers( value, kind, doc, - &self.config, + self, self.document_id.as_str(), ), "document-writers" => processor::document::process_writers( value, kind, doc, - &self.config, + self, self.document_id.as_str(), ), - "user-groups" => processor::user_group::process(value, kind, doc, &self.config), - "user-group-by-id" => { - processor::user_group::process_by_id(value, kind, doc, &self.config) - } - "get-identities" => { - processor::user_group::get_identities(value, kind, doc, &self.config) - } - "document-id" => processor::document::document_id(value, kind, doc, &self.config), - "document-full-id" => { - processor::document::document_full_id(value, kind, doc, &self.config) - } - "document-suffix" => { - processor::document::document_suffix(value, kind, doc, &self.config) - } - "document-name" => { - processor::document::document_name(value, kind, doc, &self.config).await - } - "fetch-file" => { - processor::fetch_file::fetch_files(value, kind, doc, &self.config).await - } - "user-details" => processor::user_details::process(value, kind, doc, &self.config), - "fastn-apps" => processor::apps::process(value, kind, doc, &self.config), - "is-reader" => processor::user_group::is_reader(value, kind, doc, &self.config).await, - "sql" => processor::sql::process(value, kind, doc, &self.config).await, - "package-query" => { - processor::sqlite::process( - value, - kind, - doc, - &self.config, - &fastn_core::library2022::processor::sql::get_db_config()?, - ) - .await - } + "user-groups" => processor::user_group::process(value, kind, doc, self), + "user-group-by-id" => processor::user_group::process_by_id(value, kind, doc, self), + "get-identities" => processor::user_group::get_identities(value, kind, doc, self), + "document-id" => processor::document::document_id(value, kind, doc, self), + "document-full-id" => processor::document::document_full_id(value, kind, doc, self), + "document-suffix" => processor::document::document_suffix(value, kind, doc, self), + "document-name" => processor::document::document_name(value, kind, doc, self).await, + "fetch-file" => processor::fetch_file::fetch_files(value, kind, doc, self).await, + "user-details" => processor::user_details::process(value, kind, doc, self), + "fastn-apps" => processor::apps::process(value, kind, doc, self), + "is-reader" => processor::user_group::is_reader(value, kind, doc, self).await, + "sql" => processor::sql::process(value, kind, doc, self).await, + "package-query" => processor::package_query::process(value, kind, doc, self).await, "pg" => processor::pg::process(value, kind, doc).await, "package-tree" => { processor::package_tree::process(value, kind, doc, &self.config).await } - "query" => { - processor::query::process( - value, - kind, - doc, - &mut self.config, - self.document_id.as_str(), - ) - .await - } + "query" => processor::query::process(value, kind, doc, self).await, t => Err(ftd::interpreter::Error::ParseError { doc_id: self.document_id.to_string(), line_number, diff --git a/fastn-core/src/library2022/processor/apps.rs b/fastn-core/src/library2022/processor/apps.rs index b56b9a2456..d82c52d877 100644 --- a/fastn-core/src/library2022/processor/apps.rs +++ b/fastn-core/src/library2022/processor/apps.rs @@ -2,7 +2,7 @@ pub fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { use itertools::Itertools; #[derive(Debug, serde::Serialize)] @@ -14,7 +14,8 @@ pub fn process( icon: Option, } - let apps = config + let apps = req_config + .config .package .apps .iter() diff --git a/fastn-core/src/library2022/processor/document.rs b/fastn-core/src/library2022/processor/document.rs index e28b83ae68..6ceb04c8c7 100644 --- a/fastn-core/src/library2022/processor/document.rs +++ b/fastn-core/src/library2022/processor/document.rs @@ -2,7 +2,7 @@ pub fn process_readers( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, document_id: &str, ) -> ftd::interpreter::Result { use itertools::Itertools; @@ -17,11 +17,11 @@ pub fn process_readers( .get_optional_string_by_key("document", doc.name, value.line_number())? .unwrap_or_else(|| document_id.to_string()); - let document_name = config.document_name_with_default(document.as_str()); + let document_name = req_config.document_name_with_default(document.as_str()); - let readers = match config.package.sitemap.as_ref() { + let readers = match req_config.config.package.sitemap.as_ref() { Some(s) => s - .readers(document_name.as_str(), &config.package.groups) + .readers(document_name.as_str(), &req_config.config.package.groups) .0 .into_iter() .map(|g| g.to_group_compat()) @@ -36,7 +36,7 @@ pub fn process_writers( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, document_id: &str, ) -> ftd::interpreter::Result { use itertools::Itertools; @@ -52,10 +52,10 @@ pub fn process_writers( .get_optional_string_by_key("document", doc.name, value.line_number())? .unwrap_or_else(|| document_id.to_string()); - let document_name = config.document_name_with_default(document.as_str()); - let writers = match config.package.sitemap.as_ref() { + let document_name = req_config.document_name_with_default(document.as_str()); + let writers = match req_config.config.package.sitemap.as_ref() { Some(s) => s - .writers(document_name.as_str(), &config.package.groups) + .writers(document_name.as_str(), &req_config.config.package.groups) .into_iter() .map(|g| g.to_group_compat()) .collect_vec(), @@ -69,12 +69,12 @@ pub fn document_id( _value: ftd::ast::VariableValue, _kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { - let doc_id = config.doc_id().unwrap_or_else(|| { + let doc_id = req_config.doc_id().unwrap_or_else(|| { doc.name .to_string() - .replace(config.package.name.as_str(), "") + .replace(req_config.config.package.name.as_str(), "") }); let document_id = doc_id @@ -98,10 +98,10 @@ pub fn document_full_id( _value: ftd::ast::VariableValue, _kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { Ok(ftd::interpreter::Value::String { - text: fastn_core::library2022::utils::document_full_id(config, doc)?, + text: fastn_core::library2022::utils::document_full_id(req_config, doc)?, }) } @@ -109,12 +109,12 @@ pub fn document_suffix( _value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { - let doc_id = config.doc_id().unwrap_or_else(|| { + let doc_id = req_config.doc_id().unwrap_or_else(|| { doc.name .to_string() - .replace(config.package.name.as_str(), "") + .replace(req_config.config.package.name.as_str(), "") }); let value = doc_id @@ -136,23 +136,23 @@ pub async fn document_name<'a>( value: ftd::ast::VariableValue, _kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc<'a>, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { - let doc_id = config.doc_id().unwrap_or_else(|| { + let doc_id = req_config.doc_id().unwrap_or_else(|| { doc.name .to_string() - .replace(config.package.name.as_str(), "") + .replace(req_config.config.package.name.as_str(), "") }); - let file_path = - config - .get_file_path(&doc_id) - .await - .map_err(|e| ftd::ftd2021::p1::Error::ParseError { - message: e.to_string(), - doc_id: doc.name.to_string(), - line_number: value.line_number(), - })?; + let file_path = req_config + .config + .get_file_path(&doc_id) + .await + .map_err(|e| ftd::ftd2021::p1::Error::ParseError { + message: e.to_string(), + doc_id: doc.name.to_string(), + line_number: value.line_number(), + })?; Ok(ftd::interpreter::Value::String { text: file_path.trim().to_string(), diff --git a/fastn-core/src/library2022/processor/fetch_file.rs b/fastn-core/src/library2022/processor/fetch_file.rs index 216511cbcc..74d8251104 100644 --- a/fastn-core/src/library2022/processor/fetch_file.rs +++ b/fastn-core/src/library2022/processor/fetch_file.rs @@ -2,7 +2,7 @@ pub async fn fetch_files( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc<'_>, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { if !kind.is_string() { return ftd::interpreter::utils::e2( @@ -24,7 +24,7 @@ pub async fn fetch_files( })?; Ok(ftd::interpreter::Value::String { - text: tokio::fs::read_to_string(config.root.join(path)) + text: tokio::fs::read_to_string(req_config.config.root.join(path)) .await .map_err(|v| ftd::interpreter::Error::ParseError { message: v.to_string(), diff --git a/fastn-core/src/library2022/processor/figma_tokens.rs b/fastn-core/src/library2022/processor/figma_tokens.rs index c1669874f9..1403396cc1 100644 --- a/fastn-core/src/library2022/processor/figma_tokens.rs +++ b/fastn-core/src/library2022/processor/figma_tokens.rs @@ -4,7 +4,6 @@ pub fn process_figma_tokens( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &mut ftd::interpreter::TDoc, - _config: &fastn_core::Config, ) -> ftd::interpreter::Result { let line_number = value.line_number(); let mut variable_name: Option = None; @@ -47,7 +46,6 @@ pub fn process_figma_tokens_old( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &mut ftd::interpreter::TDoc, - _config: &fastn_core::Config, ) -> ftd::interpreter::Result { let line_number = value.line_number(); let mut variable_name: Option = None; diff --git a/fastn-core/src/library2022/processor/get_data.rs b/fastn-core/src/library2022/processor/get_data.rs index 0e83251ba6..b00845230c 100644 --- a/fastn-core/src/library2022/processor/get_data.rs +++ b/fastn-core/src/library2022/processor/get_data.rs @@ -2,7 +2,7 @@ pub fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { let (section_name, headers, body, line_number) = match value.get_record(doc.name) { Ok(val) => ( @@ -30,7 +30,7 @@ pub fn process( }); } - if let Some(data) = config.extra_data.get(key.as_str()) { + if let Some(data) = req_config.extra_data.get(key.as_str()) { return match kind { ftd::interpreter::Kind::Integer => { let value2 = diff --git a/fastn-core/src/library2022/processor/http.rs b/fastn-core/src/library2022/processor/http.rs index 20237911fb..5e5c6fb245 100644 --- a/fastn-core/src/library2022/processor/http.rs +++ b/fastn-core/src/library2022/processor/http.rs @@ -2,7 +2,7 @@ pub async fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc<'_>, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { let (headers, line_number) = if let Ok(val) = value.get_record(doc.name) { (val.2.to_owned(), val.5.to_owned()) @@ -57,12 +57,14 @@ pub async fn process( } }; - let (_, mut url, conf) = fastn_core::config::utils::get_clean_url(config, url.as_str()) - .map_err(|e| ftd::interpreter::Error::ParseError { - message: format!("invalid url: {:?}", e), - doc_id: doc.name.to_string(), - line_number, - })?; + let (_, mut url, conf) = + fastn_core::config::utils::get_clean_url(&req_config.config, url.as_str()).map_err( + |e| ftd::interpreter::Error::ParseError { + message: format!("invalid url: {:?}", e), + doc_id: doc.name.to_string(), + line_number, + }, + )?; let mut body = vec![]; for header in headers.0 { @@ -104,7 +106,7 @@ pub async fn process( let response = if method.as_str().eq("post") { fastn_core::http::http_post_with_cookie( url.as_str(), - config.request.as_ref().and_then(|v| v.cookies_string()), + req_config.request.cookies_string(), &conf, dbg!(format!("{{{}}}", body.join(","))).as_str(), ) @@ -112,7 +114,7 @@ pub async fn process( } else { fastn_core::http::http_get_with_cookie( url.as_str(), - config.request.as_ref().and_then(|v| v.cookies_string()), + req_config.request.cookies_string(), &conf, ) .await diff --git a/fastn-core/src/library2022/processor/mod.rs b/fastn-core/src/library2022/processor/mod.rs index d9e21caeed..2f4fdd08bc 100644 --- a/fastn-core/src/library2022/processor/mod.rs +++ b/fastn-core/src/library2022/processor/mod.rs @@ -5,12 +5,13 @@ pub(crate) mod figma_tokens; pub(crate) mod figma_typography_tokens; pub(crate) mod get_data; pub(crate) mod http; +pub(crate) mod package_query; pub(crate) mod package_tree; pub(crate) mod pg; pub(crate) mod query; pub(crate) mod request_data; pub(crate) mod sitemap; -pub mod sql; +pub(crate) mod sql; pub(crate) mod sqlite; pub(crate) mod toc; pub(crate) mod user_details; diff --git a/fastn-core/src/library2022/processor/package_query.rs b/fastn-core/src/library2022/processor/package_query.rs new file mode 100644 index 0000000000..537b499fd8 --- /dev/null +++ b/fastn-core/src/library2022/processor/package_query.rs @@ -0,0 +1,61 @@ +pub async fn process( + value: ftd::ast::VariableValue, + kind: ftd::interpreter::Kind, + doc: &ftd::interpreter::TDoc<'_>, + req_config: &fastn_core::RequestConfig, +) -> ftd::interpreter::Result { + let (headers, query) = + fastn_core::library2022::processor::sqlite::get_p1_data("package-data", &value, doc.name)?; + + fastn_core::library2022::utils::log_deprecation_warning( + "`package-query` has been deprecated, use `sql` processor instead.", + ); + + let sqlite_database = + match headers.get_optional_string_by_key("db", doc.name, value.line_number())? { + Some(k) => k, + None => { + return ftd::interpreter::utils::e2( + "`db` is not specified".to_string(), + doc.name, + value.line_number(), + ) + } + }; + + let sqlite_database_path = req_config.config.root.join(sqlite_database.as_str()); + + if !sqlite_database_path.exists() { + return ftd::interpreter::utils::e2( + "`db` does not exists for package-query processor".to_string(), + doc.name, + value.line_number(), + ); + } + + let query_response = fastn_core::library2022::processor::sqlite::execute_query( + &sqlite_database_path, + query.as_str(), + doc, + headers, + value.line_number(), + ) + .await; + + match query_response { + Ok(result) => fastn_core::library2022::processor::sqlite::result_to_value( + Ok(result), + kind, + doc, + &value, + super::sql::STATUS_OK, + ), + Err(e) => fastn_core::library2022::processor::sqlite::result_to_value( + Err(e.to_string()), + kind, + doc, + &value, + super::sql::STATUS_ERROR, + ), + } +} diff --git a/fastn-core/src/library2022/processor/query.rs b/fastn-core/src/library2022/processor/query.rs index a3a07ef93a..e4b168b27d 100644 --- a/fastn-core/src/library2022/processor/query.rs +++ b/fastn-core/src/library2022/processor/query.rs @@ -2,8 +2,7 @@ pub async fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc<'_>, - config: &mut fastn_core::Config, - document_id: &str, + req_config: &mut fastn_core::RequestConfig, ) -> ftd::interpreter::Result { // TODO: document key should be optional @@ -14,25 +13,25 @@ pub async fn process( let path = headers .get_optional_string_by_key("file", doc.name, value.line_number())? - .unwrap_or_else(|| document_id.to_string()); + .unwrap_or_else(|| req_config.document_id.to_string()); let stage = headers .get_optional_string_by_key("stage", doc.name, value.line_number())? .unwrap_or_else(|| "ast".to_string()); - let file = config + let file = req_config .get_file_and_package_by_id(path.as_str()) .await .map_err(|e| ftd::interpreter::Error::ParseError { message: format!("Cannot get path: {} {:?}", path.as_str(), e), - doc_id: document_id.to_string(), + doc_id: req_config.document_id.to_string(), line_number: value.line_number(), })?; doc.from_json( &fastn_core::commands::query::get_ftd_json(&file, stage.as_str()).map_err(|e| { ftd::interpreter::Error::ParseError { message: format!("Cannot resolve json for path: {} {:?}", path.as_str(), e), - doc_id: document_id.to_string(), + doc_id: req_config.document_id.to_string(), line_number: value.line_number(), } })?, diff --git a/fastn-core/src/library2022/processor/request_data.rs b/fastn-core/src/library2022/processor/request_data.rs index b581f94a31..1df3663eef 100644 --- a/fastn-core/src/library2022/processor/request_data.rs +++ b/fastn-core/src/library2022/processor/request_data.rs @@ -2,27 +2,11 @@ pub fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { - let req = match config.request.as_ref() { - Some(v) => v, - None if kind.is_optional() => { - return Ok(ftd::interpreter::Value::Optional { - data: Box::new(None), - kind: kind.into_kind_data(), - }); - } - None => { - return ftd::interpreter::utils::e2( - "config does not contain http-request object", - doc.name, - value.line_number(), - ) - } - }; - let mut data = req.query().clone(); + let mut data = req_config.request.query().clone(); - for (name, param_value) in config.named_parameters.iter() { + for (name, param_value) in req_config.named_parameters.iter() { let json_value = param_value .to_serde_value() @@ -34,7 +18,7 @@ pub fn process( data.insert(name.to_string(), json_value); } - match req.body_as_json() { + match req_config.request.body_as_json() { Ok(Some(b)) => { data.extend(b); } @@ -49,7 +33,7 @@ pub fn process( } data.extend( - config + req_config .extra_data .iter() .map(|(k, v)| (k.to_string(), serde_json::Value::String(v.to_string()))), diff --git a/fastn-core/src/library2022/processor/sitemap.rs b/fastn-core/src/library2022/processor/sitemap.rs index f4edd4409e..60dc09bd6e 100644 --- a/fastn-core/src/library2022/processor/sitemap.rs +++ b/fastn-core/src/library2022/processor/sitemap.rs @@ -2,17 +2,17 @@ pub fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { - if let Some(ref sitemap) = config.package.sitemap { - let doc_id = config + if let Some(ref sitemap) = req_config.config.package.sitemap { + let doc_id = req_config .current_document .clone() .map(|v| fastn_core::utils::id_to_path(v.as_str())) .unwrap_or_else(|| { doc.name .to_string() - .replace(config.package.name.as_str(), "") + .replace(req_config.config.package.name.as_str(), "") }) .trim() .replace(std::path::MAIN_SEPARATOR, "/"); @@ -32,17 +32,17 @@ pub fn full_sitemap_process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { - if let Some(ref sitemap) = config.package.sitemap { - let doc_id = config + if let Some(ref sitemap) = req_config.config.package.sitemap { + let doc_id = req_config .current_document .clone() .map(|v| fastn_core::utils::id_to_path(v.as_str())) .unwrap_or_else(|| { doc.name .to_string() - .replace(config.package.name.as_str(), "") + .replace(req_config.config.package.name.as_str(), "") }) .trim() .replace(std::path::MAIN_SEPARATOR, "/"); diff --git a/fastn-core/src/library2022/processor/sql.rs b/fastn-core/src/library2022/processor/sql.rs index 3bdcd7fbcb..f1a3eca3bd 100644 --- a/fastn-core/src/library2022/processor/sql.rs +++ b/fastn-core/src/library2022/processor/sql.rs @@ -23,7 +23,7 @@ pub async fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc<'_>, - config: &fastn_core::Config, + config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { let db_config = fastn_core::library2022::processor::sql::get_db_config()?; let db_type = db_config.db_type.as_str(); diff --git a/fastn-core/src/library2022/processor/sqlite.rs b/fastn-core/src/library2022/processor/sqlite.rs index 7cd593d0a3..a7723aa96e 100644 --- a/fastn-core/src/library2022/processor/sqlite.rs +++ b/fastn-core/src/library2022/processor/sqlite.rs @@ -28,10 +28,11 @@ pub async fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc<'_>, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, db_config: &fastn_core::library2022::processor::sql::DatabaseConfig, ) -> ftd::interpreter::Result { let (headers, query) = get_p1_data("package-data", &value, doc.name)?; + let sqlite_database_path = req_config.config.root.join(&db_config.db_url); // need the query params // question is they can be multiple @@ -41,9 +42,14 @@ pub async fn process( // for now they wil be ordered // select * from users where - let db_path = config.root.join(&db_config.db_url); - let query_response = - execute_query(&db_path, query.as_str(), doc, headers, value.line_number()).await; + let query_response = execute_query( + &sqlite_database_path, + query.as_str(), + doc, + headers, + value.line_number(), + ) + .await; match query_response { Ok(result) => result_to_value(Ok(result), kind, doc, &value, super::sql::STATUS_OK), @@ -286,7 +292,7 @@ fn extract_named_parameters( Ok(params) } -async fn execute_query( +pub(crate) async fn execute_query( database_path: &camino::Utf8PathBuf, query: &str, doc: &ftd::interpreter::TDoc<'_>, diff --git a/fastn-core/src/library2022/processor/toc.rs b/fastn-core/src/library2022/processor/toc.rs index ae2daad439..de794359b5 100644 --- a/fastn-core/src/library2022/processor/toc.rs +++ b/fastn-core/src/library2022/processor/toc.rs @@ -2,7 +2,6 @@ pub fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - _config: &fastn_core::Config, ) -> ftd::interpreter::Result { let (body, line_number) = if let Ok(val) = value.get_record(doc.name) { (val.3.to_owned(), val.5.to_owned()) diff --git a/fastn-core/src/library2022/processor/user_details.rs b/fastn-core/src/library2022/processor/user_details.rs index 4860cb91d5..58f12877ae 100644 --- a/fastn-core/src/library2022/processor/user_details.rs +++ b/fastn-core/src/library2022/processor/user_details.rs @@ -2,20 +2,17 @@ pub fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { let mut found_cookie = false; - let is_login = match &config.request { - Some(req) => { - for auth_provider in fastn_core::auth::AuthProviders::AUTH_ITER.iter() { - if req.cookie(auth_provider.as_str()).is_some() { - found_cookie = true; - break; - } + let is_login = { + for auth_provider in fastn_core::auth::AuthProviders::AUTH_ITER.iter() { + if req_config.request.cookie(auth_provider.as_str()).is_some() { + found_cookie = true; + break; } - found_cookie } - None => false, + found_cookie }; #[derive(Debug, serde::Serialize)] diff --git a/fastn-core/src/library2022/processor/user_group.rs b/fastn-core/src/library2022/processor/user_group.rs index 548cc850d0..9ba9b06d9f 100644 --- a/fastn-core/src/library2022/processor/user_group.rs +++ b/fastn-core/src/library2022/processor/user_group.rs @@ -2,10 +2,11 @@ pub fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { use itertools::Itertools; - let g = config + let g = req_config + .config .package .groups .values() @@ -19,7 +20,7 @@ pub fn process_by_id( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { let headers = match value.get_record(doc.name) { Ok(val) => val.2.to_owned(), @@ -37,7 +38,8 @@ pub fn process_by_id( } }; - let g = config + let g = req_config + .config .package .groups .get(group_id.as_str()) @@ -56,18 +58,20 @@ pub fn get_identities( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { use itertools::Itertools; - let doc_id = fastn_core::library2022::utils::document_full_id(config, doc)?; + let doc_id = fastn_core::library2022::utils::document_full_id(req_config, doc)?; - let identities = fastn_core::user_group::get_identities(config, doc_id.as_str(), true) - .map_err(|e| ftd::ftd2021::p1::Error::ParseError { - message: e.to_string(), - doc_id, - line_number: value.line_number(), - })?; + let identities = + fastn_core::user_group::get_identities(&req_config.config, doc_id.as_str(), true).map_err( + |e| ftd::ftd2021::p1::Error::ParseError { + message: e.to_string(), + doc_id, + line_number: value.line_number(), + }, + )?; Ok(ftd::interpreter::Value::List { data: identities @@ -93,17 +97,16 @@ pub async fn is_reader<'a>( value: ftd::ast::VariableValue, _kind: ftd::interpreter::Kind, doc: &ftd::interpreter::TDoc<'a>, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::interpreter::Result { - let doc_id = fastn_core::library2022::utils::document_full_id(config, doc)?; - let is_reader = config - .can_read(config.request.as_ref().unwrap(), &doc_id, false) - .await - .map_err(|e| ftd::ftd2021::p1::Error::ParseError { + let doc_id = fastn_core::library2022::utils::document_full_id(req_config, doc)?; + let is_reader = req_config.can_read(&doc_id, false).await.map_err(|e| { + ftd::ftd2021::p1::Error::ParseError { message: e.to_string(), doc_id, line_number: value.line_number(), - })?; + } + })?; Ok(ftd::interpreter::Value::Boolean { value: is_reader }) } diff --git a/fastn-core/src/library2022/utils.rs b/fastn-core/src/library2022/utils.rs index 2ee2ba5927..21f9872ff1 100644 --- a/fastn-core/src/library2022/utils.rs +++ b/fastn-core/src/library2022/utils.rs @@ -1,11 +1,11 @@ pub fn document_full_id( - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, doc: &ftd::interpreter::TDoc, ) -> ftd::ftd2021::p1::Result { - let full_document_id = config.doc_id().unwrap_or_else(|| { + let full_document_id = req_config.doc_id().unwrap_or_else(|| { doc.name .to_string() - .replace(config.package.name.as_str(), "") + .replace(req_config.config.package.name.as_str(), "") }); if full_document_id.trim_matches('/').is_empty() { @@ -14,3 +14,9 @@ pub fn document_full_id( Ok(format!("/{}/", full_document_id.trim_matches('/'))) } + +pub fn log_deprecation_warning(message: &str) { + use colored::Colorize; + + println!("{}", format!("Warning: {}", message).bright_yellow()); +} diff --git a/fastn-core/src/package/app.rs b/fastn-core/src/package/app.rs index 3759801b58..d349f08ae2 100644 --- a/fastn-core/src/package/app.rs +++ b/fastn-core/src/package/app.rs @@ -94,11 +94,12 @@ impl AppTemp { } // Takes the path /-/// or /mount-point// -pub async fn can_read(config: &fastn_core::Config, path: &str) -> fastn_core::Result { +pub async fn can_read(config: &fastn_core::RequestConfig, path: &str) -> fastn_core::Result { use itertools::Itertools; // first get the app - let readers_groups = if let Some((_, _, _, Some(app))) = - config.get_mountpoint_sanitized_path(&config.package, path) + let readers_groups = if let Some((_, _, _, Some(app))) = config + .config + .get_mountpoint_sanitized_path(&config.config.package, path) { app.readers.clone() } else { @@ -110,6 +111,7 @@ pub async fn can_read(config: &fastn_core::Config, path: &str) -> fastn_core::Re } let user_groups = config + .config .package .groups .iter() @@ -124,17 +126,15 @@ pub async fn can_read(config: &fastn_core::Config, path: &str) -> fastn_core::Re let mut app_identities = vec![]; for ug in user_groups.iter() { - app_identities.extend(ug.get_identities(config)?) + app_identities.extend(ug.get_identities(&config.config)?) } - let auth_identities = fastn_core::auth::get_auth_identities( - config.request.as_ref().unwrap().cookies(), - app_identities.as_slice(), - ) - .await?; + let auth_identities = + fastn_core::auth::get_auth_identities(config.request.cookies(), app_identities.as_slice()) + .await?; return fastn_core::user_group::belongs_to( - config, + &config.config, user_groups.as_slice(), auth_identities.iter().collect_vec().as_slice(), ); diff --git a/fastn-core/src/package/package_doc.rs b/fastn-core/src/package/package_doc.rs index f7786720db..184adc2203 100644 --- a/fastn-core/src/package/package_doc.rs +++ b/fastn-core/src/package/package_doc.rs @@ -364,14 +364,14 @@ impl From for fastn_core::http::Response { #[tracing::instrument(skip_all)] pub(crate) async fn read_ftd( - config: &mut fastn_core::Config, + config: &mut fastn_core::RequestConfig, main: &fastn_core::Document, base_url: &str, download_assets: bool, test: bool, ) -> fastn_core::Result { tracing::info!(document = main.id); - match config.ftd_edition { + match config.config.ftd_edition { fastn_core::FTDEdition::FTD2021 => { unimplemented!() } @@ -386,26 +386,25 @@ pub(crate) async fn read_ftd( #[tracing::instrument(name = "read_ftd_2022", skip_all)] pub(crate) async fn read_ftd_2022( - config: &mut fastn_core::Config, + config: &mut fastn_core::RequestConfig, main: &fastn_core::Document, base_url: &str, download_assets: bool, test: bool, ) -> fastn_core::Result { - let lib_config = config.clone(); - let mut all_packages = config.all_packages.borrow_mut(); - let current_package = all_packages + let font_style = config.config.get_font_style(); + let c = &config.config.clone(); + + let current_package = config + .config + .all_packages + .borrow() .get(main.package_name.as_str()) - .unwrap_or(&config.package); - - let mut lib = fastn_core::Library2022 { - config: lib_config, - markdown: None, - document_id: main.id.clone(), - translated_data: Default::default(), - base_url: base_url.to_string(), - module_package_map: Default::default(), - }; + .unwrap_or(&config.config.package) + .to_owned(); + + config.document_id = main.id.clone(); + config.base_url = base_url.to_string(); // Get Prefix Body => [AutoImports + Actual Doc content] let mut doc_content = @@ -417,7 +416,7 @@ pub(crate) async fn read_ftd_2022( let main_ftd_doc = match fastn_core::doc::interpret_helper( main.id_with_package().as_str(), doc_content.as_str(), - &mut lib, + config, base_url, download_assets, line_number, @@ -432,26 +431,19 @@ pub(crate) async fn read_ftd_2022( }); } }; - config.dependencies_during_render = lib.config.dependencies_during_render; + if let Some((url, code)) = main_ftd_doc.get_redirect()? { return Ok(FTDResult::Redirect { url, code }); } + let executor = ftd::executor::ExecuteDoc::from_interpreter(main_ftd_doc)?; let node = ftd::node::NodeData::from_rt(executor); let html_ui = ftd::html::HtmlUI::from_node_data(node, "main", test)?; - config - .downloaded_assets - .extend(lib.config.downloaded_assets); - - all_packages.extend(lib.config.all_packages.into_inner()); - drop(all_packages); - - let font_style = config.get_font_style(); let file_content = fastn_core::utils::replace_markers_2022( fastn_core::ftd_html(), html_ui, - config, + c, main.id_to_path().as_str(), font_style.as_str(), base_url, @@ -463,25 +455,24 @@ pub(crate) async fn read_ftd_2022( #[allow(clippy::await_holding_refcell_ref)] #[tracing::instrument(name = "read_ftd_2023", skip_all)] pub(crate) async fn read_ftd_2023( - config: &mut fastn_core::Config, + config: &mut fastn_core::RequestConfig, main: &fastn_core::Document, base_url: &str, download_assets: bool, ) -> fastn_core::Result { - let lib_config = config.clone(); - let mut all_packages = config.all_packages.borrow_mut(); - let current_package = all_packages + let package_name = config.config.package.name.to_string(); + let c = &config.config.clone(); + + let current_package = config + .config + .all_packages + .borrow() .get(main.package_name.as_str()) - .unwrap_or(&config.package); - - let mut lib = fastn_core::Library2022 { - config: lib_config, - markdown: None, - document_id: main.id.clone(), - translated_data: Default::default(), - base_url: base_url.to_string(), - module_package_map: Default::default(), - }; + .unwrap_or(&config.config.package) + .to_owned(); + + config.document_id = main.id.clone(); + config.base_url = base_url.to_string(); // Get Prefix Body => [AutoImports + Actual Doc content] let mut doc_content = @@ -493,7 +484,7 @@ pub(crate) async fn read_ftd_2023( let main_ftd_doc = match fastn_core::doc::interpret_helper( main.id_with_package().as_str(), doc_content.as_str(), - &mut lib, + config, base_url, download_assets, line_number, @@ -508,55 +499,46 @@ pub(crate) async fn read_ftd_2023( }); } }; - config.dependencies_during_render = lib.config.dependencies_during_render; if let Some((url, code)) = main_ftd_doc.get_redirect()? { return Ok(FTDResult::Redirect { url, code }); } let js_ast_data = ftd::js::document_into_js_ast(main_ftd_doc); - let js_document_script = - fastn_js::to_js(js_ast_data.asts.as_slice(), config.package.name.as_str()); + let js_document_script = fastn_js::to_js(js_ast_data.asts.as_slice(), package_name.as_str()); let js_ftd_script = fastn_js::to_js( ftd::js::default_bag_into_js_ast().as_slice(), - config.package.name.as_str(), + package_name.as_str(), ); let ssr_body = fastn_js::ssr_with_js_string( - &config.package.name, + &package_name, format!("{js_ftd_script}\n{js_document_script}").as_str(), ); - all_packages.extend(lib.config.all_packages.into_inner()); - drop(all_packages); - - config - .downloaded_assets - .extend(lib.config.downloaded_assets); - - let font_style = config.get_font_style(); let file_content = fastn_core::utils::replace_markers_2023( ftd::ftd_js_html(), js_document_script.as_str(), js_ast_data.scripts.join("").as_str(), ssr_body.as_str(), - font_style.as_str(), + config.config.get_font_style().as_str(), ftd::ftd_js_css(), base_url, - config, + c, ); Ok(FTDResult::Html(file_content.into())) } pub(crate) async fn process_ftd( - config: &mut fastn_core::Config, + config: &mut fastn_core::RequestConfig, main: &fastn_core::Document, base_url: &str, build_static_files: bool, test: bool, file_path: &str, ) -> fastn_core::Result { + let build_dir = config.config.build_dir(); let response = read_ftd(config, main, base_url, build_static_files, test).await?; - fastn_core::utils::overwrite(&config.build_dir(), file_path, &response.html()).await?; + fastn_core::utils::overwrite(&build_dir, file_path, &response.html()).await?; Ok(response) } diff --git a/fastn-core/src/package/user_group.rs b/fastn-core/src/package/user_group.rs index de73ca3096..6824c4b5f5 100644 --- a/fastn-core/src/package/user_group.rs +++ b/fastn-core/src/package/user_group.rs @@ -603,16 +603,17 @@ pub mod processor { pub fn get_identities( section: &ftd::ftd2021::p1::Section, doc: &ftd::ftd2021::p2::TDoc, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::ftd2021::p1::Result { - let doc_id = fastn_core::library::document::document_full_id(config, doc)?; - let identities = super::get_identities(config, doc_id.as_str(), true).map_err(|e| { - ftd::ftd2021::p1::Error::ParseError { - message: e.to_string(), - doc_id, - line_number: section.line_number, - } - })?; + let doc_id = fastn_core::library::document::document_full_id(req_config, doc)?; + let identities = + super::get_identities(&req_config.config, doc_id.as_str(), true).map_err(|e| { + ftd::ftd2021::p1::Error::ParseError { + message: e.to_string(), + doc_id, + line_number: section.line_number, + } + })?; Ok(ftd::Value::List { data: identities @@ -641,17 +642,16 @@ pub mod processor { pub async fn is_reader<'a>( section: &ftd::ftd2021::p1::Section, doc: &'a ftd::ftd2021::p2::TDoc<'_>, - config: &fastn_core::Config, + req_config: &fastn_core::RequestConfig, ) -> ftd::ftd2021::p1::Result { - let doc_id = fastn_core::library::document::document_full_id(config, doc)?; - let is_reader = config - .can_read(config.request.as_ref().unwrap(), &doc_id, false) - .await - .map_err(|e| ftd::ftd2021::p1::Error::ParseError { + let doc_id = fastn_core::library::document::document_full_id(req_config, doc)?; + let is_reader = req_config.can_read(&doc_id, false).await.map_err(|e| { + ftd::ftd2021::p1::Error::ParseError { message: e.to_string(), doc_id, line_number: section.line_number, - })?; + } + })?; Ok(ftd::Value::Boolean { value: is_reader }) } diff --git a/fastn-core/src/tutor.rs b/fastn-core/src/tutor.rs index 65c3229a01..2501cf07aa 100644 --- a/fastn-core/src/tutor.rs +++ b/fastn-core/src/tutor.rs @@ -1,3 +1,20 @@ +pub async fn main() -> fastn_core::Result<()> { + println!("starting TUTOR mode"); + std::env::set_current_dir(std::env::current_dir()?.join(".tutor"))?; + fastn_core::listen( + "127.0.0.1", + Some(2000), + None, + Some("2023".to_string()), + vec![], + vec![], + vec![], + vec![], + "the-tutor".to_string(), + ) + .await +} + pub async fn pwd() -> fastn_core::Result { if !is_tutor() { return Ok(fastn_core::not_found!("this only works in tutor mode")); @@ -6,15 +23,57 @@ pub async fn pwd() -> fastn_core::Result { fastn_core::http::api_ok(std::env::current_dir()?.to_string_lossy()) } -pub async fn shutdown() -> fastn_core::Result { +pub async fn js() -> fastn_core::Result { + Ok(actix_web::HttpResponse::Ok().body(include_bytes!("../tutor.js").to_vec())) +} + +async fn set_tutorial(t: Option) -> fastn_core::Result { if !is_tutor() { return Ok(fastn_core::not_found!("this only works in tutor mode")); } - println!("/-/shutdown/ called, shutting down"); - std::process::exit(0); + *CURRENT_TUTORIAL.write().await = t; + fastn_core::http::api_ok("done") +} + +pub async fn start(t: Tutorial) -> fastn_core::Result { + set_tutorial(Some(t)).await +} + +pub async fn stop() -> fastn_core::Result { + set_tutorial(None).await } +static CURRENT_TUTORIAL: once_cell::sync::Lazy>> = + once_cell::sync::Lazy::new(|| async_lock::RwLock::new(None)); + +#[derive(serde::Deserialize)] +pub struct Tutorial { + id: String, + data: fastn_core::commands::serve::AppData, +} + +pub(crate) async fn config( + app_data: &fastn_core::commands::serve::AppData, +) -> fastn_core::Result<(fastn_core::Config, String)> { + let (root, app_data) = match CURRENT_TUTORIAL.read().await.as_ref() { + Some(context) => (Some(context.id.clone()), context.data.clone()), + None => (None, app_data.clone()), + }; + + let config = fastn_core::Config::read(root, false) + .await + .unwrap() + .add_edition(app_data.edition)? + .add_external_js(app_data.external_js) + .add_inline_js(app_data.inline_js) + .add_external_css(app_data.external_css) + .add_inline_css(app_data.inline_css); + + Ok((config, app_data.package_name)) +} + +/// tutor-data $processor$ pub async fn process( value: ftd::ast::VariableValue, kind: ftd::interpreter::Kind, @@ -26,212 +85,42 @@ pub async fn process( )); } - let state = + let fs_state: TutorStateFS = match tokio::fs::read(dirs::home_dir().unwrap().join(".fastn").join("tutor.json")).await { Ok(v) => serde_json::from_slice(&v)?, - Err(e) => match e.kind() { - std::io::ErrorKind::NotFound => TutorStateFS::default(), - _ => return Err(e.into()), + Err(e) => match dbg!(e.kind()) { + std::io::ErrorKind::NotFound => { + println!("not found, using default"); + TutorStateFS::default() + } + _ => { + println!("error: {:?}, {:?}", e, e.kind()); + return Err(e.into()); + } }, - } - .to_state(std::env::current_dir()?)?; + }; - doc.from_json(&state, &kind, &value) -} + let state = TutorState { + done: fs_state.done, + current: CURRENT_TUTORIAL.read().await.as_ref().map(|t| t.id.clone()), + }; -#[derive(Debug, Default, serde::Deserialize)] -struct TutorStateFS { - done: Vec, - current: String, + doc.from_json(&state, &kind, &value) } -#[derive(Debug, serde::Serialize, PartialEq)] +#[derive(Debug, Default, serde::Serialize)] struct TutorState { - workshops: Vec, -} - -impl TutorStateFS { - fn to_state>( - self: TutorStateFS, - path: T, - ) -> ftd::interpreter::Result { - use itertools::Itertools; - - let mut workshops = vec![]; - static RE: once_cell::sync::Lazy = - once_cell::sync::Lazy::new(|| regex::Regex::new(r"^[a-zA-Z]-[a-zA-Z]+.*$").unwrap()); - - for entry in std::fs::read_dir(path)?.sorted_by(sort_path) { - let entry = entry?; - let path = entry.path(); - - if !path.is_dir() { - continue; - } - if !RE.is_match(&path.file_name().unwrap().to_string_lossy()) { - continue; - } - - workshops.push(Workshop::load(&path, &self)?); - } - - Ok(TutorState { workshops }) - } -} - -fn sort_path( - a: &std::io::Result, - b: &std::io::Result, -) -> std::cmp::Ordering { - a.as_ref().unwrap().path().cmp(&b.as_ref().unwrap().path()) -} - -#[derive(Debug, serde::Serialize, PartialEq)] -struct Workshop { - title: String, - url: String, - done: bool, - current: bool, - tutorials: Vec, -} - -impl Workshop { - fn load(path: &std::path::Path, state: &TutorStateFS) -> ftd::interpreter::Result { - use itertools::Itertools; - - let mut tutorials = vec![]; - let id = path.file_name().unwrap().to_string_lossy(); - - static RE: once_cell::sync::Lazy = - once_cell::sync::Lazy::new(|| regex::Regex::new(r"^[0-9][0-9]-[a-zA-Z]+.*$").unwrap()); - - for entry in std::fs::read_dir(path)?.sorted_by(sort_path) { - let entry = entry?; - let path = entry.path(); - - if !path.is_dir() { - continue; - } - if !RE.is_match(&path.file_name().unwrap().to_string_lossy()) { - continue; - } - - tutorials.push(Tutorial::load(&id, &path, state)?); - } - - Ok(Workshop { - title: title_from_readme(path)?, - url: format!("/{id}/"), - done: !tutorials.iter().any(|t| !t.done), - current: tutorials.iter().any(|t| t.current), - tutorials, - }) - } -} - -fn title_from_readme(folder: &std::path::Path) -> ftd::interpreter::Result { - let content = std::fs::read_to_string(folder.join("README.md"))?; - let (title, _about) = match content.split_once("\n\n") { - Some(v) => v, - None => { - return Err(ftd::interpreter::Error::OtherError( - "invalid README.md".into(), - )) - } - }; - Ok(title.replacen("# ", "", 1)) -} - -#[derive(Debug, serde::Serialize, PartialEq)] -struct Tutorial { - id: String, - url: String, - title: String, - done: bool, - current: bool, + done: Vec, + current: Option, } -impl Tutorial { - fn load( - parent: &str, - path: &std::path::Path, - state: &TutorStateFS, - ) -> ftd::interpreter::Result { - let id = format!("{parent}/{}", path.file_name().unwrap().to_string_lossy()); - - Ok(Tutorial { - title: title_from_readme(path)?, - done: state.done.contains(&id), - current: state.current == id, - url: format!("/{id}/"), - id, - }) - } +#[derive(Debug, Default, serde::Serialize, serde::Deserialize)] +struct TutorStateFS { + done: Vec, } pub fn is_tutor() -> bool { // https://github.com/orgs/fastn-stack/discussions/1414 // with either of these are passed we allow APIs like /-/shutdown/, `/-/start/` etc - std::env::args().any(|e| e == "tutor" || e == "--tutor") -} - -#[cfg(test)] -mod test { - use pretty_assertions::assert_eq; - - #[test] - fn test() { - let mut ts = super::TutorState { - workshops: vec![ - super::Workshop { - title: "Build Websites Using `fastn`".to_string(), - url: "/a-website/".to_string(), - done: false, - current: false, - tutorials: vec![super::Tutorial { - id: "a-website/01-hello-world".to_string(), - url: "/a-website/01-hello-world/".to_string(), - title: "Install and start using `fastn`".to_string(), - done: false, - current: false, - }], - }, - super::Workshop { - title: "Build User Interfaces Using `fastn`".to_string(), - url: "/b-ui/".to_string(), - done: false, - current: false, - tutorials: vec![super::Tutorial { - id: "b-ui/01-hello-world".to_string(), - url: "/b-ui/01-hello-world/".to_string(), - title: "Install and start using `fastn`".to_string(), - done: false, - current: false, - }], - }, - ], - }; - - assert_eq!( - super::TutorStateFS::default() - .to_state("tutor-tests/one") - .unwrap(), - ts, - ); - - ts.workshops[0].tutorials[0].done = true; - ts.workshops[0].done = true; - ts.workshops[1].current = true; - ts.workshops[1].tutorials[0].current = true; - - assert_eq!( - super::TutorStateFS { - done: vec!["a-website/01-hello-world".to_string()], - current: "b-ui/01-hello-world".to_string(), - } - .to_state("tutor-tests/one") - .unwrap(), - ts, - ); - } + std::env::args().any(|e| e == "tutor") } diff --git a/fastn-core/src/utils.rs b/fastn-core/src/utils.rs index 2a237d35dc..95eedeaab7 100644 --- a/fastn-core/src/utils.rs +++ b/fastn-core/src/utils.rs @@ -656,7 +656,7 @@ fn get_extra_css(external_css: &[String], inline_css: &[String], css: &str) -> S pub fn replace_markers_2022( s: &str, html_ui: ftd::html::HtmlUI, - config: &mut fastn_core::Config, + config: &fastn_core::Config, main_id: &str, font_style: &str, base_url: &str, @@ -750,7 +750,7 @@ pub fn replace_markers_2023( font_style: &str, default_css: &str, base_url: &str, - config: &mut fastn_core::Config, + config: &fastn_core::Config, ) -> String { ftd::html::utils::trim_all_lines( s.replace( @@ -793,6 +793,16 @@ pub fn replace_markers_2023( ) .as_str(), ) + .replace( + "__extra_js__", + get_extra_js( + config.ftd_external_js.as_slice(), + config.ftd_inline_js.as_slice(), + "", + "", + ) + .as_str(), + ) .replace("__default_css__", default_css) .replace("__base_url__", base_url) .as_str(), diff --git a/fastn-core/tutor-tests/one/a-website/01-hello-world/README.md b/fastn-core/tutor-tests/one/a-website/01-hello-world/README.md deleted file mode 100644 index 11d9765222..0000000000 --- a/fastn-core/tutor-tests/one/a-website/01-hello-world/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Install and start using `fastn` - -In this exercise we will install fastn and create a basic hello world program. \ No newline at end of file diff --git a/fastn-core/tutor-tests/one/a-website/README.md b/fastn-core/tutor-tests/one/a-website/README.md deleted file mode 100644 index cfd5187ce7..0000000000 --- a/fastn-core/tutor-tests/one/a-website/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build Websites Using `fastn` - -This workshop teaches you how to build websites using `fastn`. \ No newline at end of file diff --git a/fastn-core/tutor-tests/one/b-ui/01-hello-world/README.md b/fastn-core/tutor-tests/one/b-ui/01-hello-world/README.md deleted file mode 100644 index 11d9765222..0000000000 --- a/fastn-core/tutor-tests/one/b-ui/01-hello-world/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Install and start using `fastn` - -In this exercise we will install fastn and create a basic hello world program. \ No newline at end of file diff --git a/fastn-core/tutor-tests/one/b-ui/README.md b/fastn-core/tutor-tests/one/b-ui/README.md deleted file mode 100644 index 594b45e2af..0000000000 --- a/fastn-core/tutor-tests/one/b-ui/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build User Interfaces Using `fastn` - -This workshop teaches you how to build user interfaces using `fastn`. \ No newline at end of file diff --git a/fastn-core/tutor.js b/fastn-core/tutor.js new file mode 100644 index 0000000000..8f039b651a --- /dev/null +++ b/fastn-core/tutor.js @@ -0,0 +1,26 @@ +(function() { + document.addEventListener("DOMContentLoaded", function() { + let sidebarWidth = "300px"; + + let iframe = document.createElement('iframe'); + // iframe.src = "/-/tutor/"; + iframe.src = "https://fastn.com/"; + iframe.style.position = "fixed"; + iframe.style.top = "0"; + iframe.style.left = "0"; + iframe.style.width = sidebarWidth; + iframe.style.height = "100vh"; + + document.body.style.paddingLeft = sidebarWidth; + document.body.insertBefore(iframe, document.body.firstChild); + }); + + window.onmessage = function(e) { + if (e.kind === 'navigate') { + document.location.href = e.url; + return; + } + + console.warn('Unknown message', e); + }; +})(); \ No newline at end of file diff --git a/fastn-js/js/dom.js b/fastn-js/js/dom.js index d1f78713f9..e75dbe2595 100644 --- a/fastn-js/js/dom.js +++ b/fastn-js/js/dom.js @@ -1566,6 +1566,11 @@ class Node2 { } } else if (kind === fastn_dom.PropertyKind.Id) { this.#node.id = staticValue; + } else if (kind === fastn_dom.PropertyKind.BreakpointWidth) { + if (fastn_utils.isNull(staticValue)) { + return; + } + ftd.breakpoint_width.set(fastn_utils.getStaticValue(staticValue)); } else if (kind === fastn_dom.PropertyKind.Css) { let css_list = staticValue.map(obj => fastn_utils.getStaticValue(obj.item)); css_list.forEach((css) => { diff --git a/fastn-js/js/fastn.js b/fastn-js/js/fastn.js index f3d3c6ea44..9efd19228f 100644 --- a/fastn-js/js/fastn.js +++ b/fastn-js/js/fastn.js @@ -360,8 +360,7 @@ class RecordInstance { } this.#fields = fields; - } - if (this.#fields[key] === undefined) { + }else if (this.#fields[key] === undefined) { this.#fields[key] = fastn.mutable(null); this.#fields[key].setWithoutUpdate(value); } else { diff --git a/fastn-js/js/virtual.js b/fastn-js/js/virtual.js index 167cd35ea4..8ff4bb3b6b 100644 --- a/fastn-js/js/virtual.js +++ b/fastn-js/js/virtual.js @@ -147,9 +147,22 @@ class Document2 { fastn_virtual.document = new Document2(); +function addClosureToBreakpointWidth() { + let closure = fastn.closureWithoutExecute(function() { + let current = ftd.get_device(); + let lastDevice = ftd.device.get(); + if (current === lastDevice) { + return; + } + console.log("last_device", lastDevice, "current_device", current); + ftd.device.set(current); + }); + ftd.breakpoint_width.addClosure(closure); +} fastn_virtual.hydrate = function(main) { + addClosureToBreakpointWidth(); let current_device = ftd.get_device(); let found_device = ftd.device.get(); if (current_device !== found_device) { diff --git a/fastn-js/src/property.rs b/fastn-js/src/property.rs index 4018fb2613..d7c76361d5 100644 --- a/fastn-js/src/property.rs +++ b/fastn-js/src/property.rs @@ -307,6 +307,7 @@ impl Value { #[derive(Debug)] pub enum PropertyKind { + BreakpointWidth, Children, StringValue, IntegerValue, @@ -433,6 +434,7 @@ pub enum PropertyKind { impl PropertyKind { pub(crate) fn to_js(&self) -> &'static str { match self { + PropertyKind::BreakpointWidth => "fastn_dom.PropertyKind.BreakpointWidth", PropertyKind::Children => "fastn_dom.PropertyKind.Children", PropertyKind::Id => "fastn_dom.PropertyKind.Id", PropertyKind::Css => "fastn_dom.PropertyKind.Css", diff --git a/fastn/src/main.rs b/fastn/src/main.rs index df12f1d6eb..a4f982fedf 100644 --- a/fastn/src/main.rs +++ b/fastn/src/main.rs @@ -80,25 +80,13 @@ async fn fastn_core_commands(matches: &clap::ArgMatches) -> fastn_core::Result<( return fastn_core::clone(clone.value_of_("source").unwrap()).await; } - let mut config = fastn_core::Config::read(None, true, None).await?; - let package_name = config.package.name.clone(); - if let Some(_tutor) = matches.subcommand_matches("tutor") { - println!("starting TUTOR mode"); - return fastn_core::listen( - "127.0.0.1", - Some(2000), - None, - Some("2023".to_string()), - vec![], - vec![], - vec![], - vec![], - package_name, - ) - .await; + return fastn_core::tutor::main().await; } + let mut config = fastn_core::Config::read(None, true).await?; + let package_name = config.package.name.clone(); + if let Some(serve) = matches.subcommand_matches("serve") { let port = serve.value_of_("port").map(|p| match p.parse::() { Ok(v) => v, @@ -181,7 +169,7 @@ async fn fastn_core_commands(matches: &clap::ArgMatches) -> fastn_core::Result<( .add_inline_css(inline_css); return fastn_core::build( - &mut config, + &config, build.value_of_("file"), // TODO: handle more than one files build.value_of_("base").unwrap_or("/"), build.get_flag("ignore-failed"), @@ -518,7 +506,6 @@ mod sub_command { .action(clap::ArgAction::Append)) .arg(clap::arg!(--"css" "CSS text added in ftd files") .action(clap::ArgAction::Append)) - .arg(clap::arg!(--"tutor" "Start the server in tutor mode").hide(true)) .arg(clap::arg!(--"download-base-url" "If running without files locally, download needed files from here")); if cfg!(feature = "remote") { serve diff --git a/foo/Cargo.lock b/foo/Cargo.lock new file mode 100644 index 0000000000..0e5399e665 --- /dev/null +++ b/foo/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "foo" +version = "0.1.0" diff --git a/foo/Cargo.toml b/foo/Cargo.toml new file mode 100644 index 0000000000..5a9b78bdf5 --- /dev/null +++ b/foo/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "foo" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio = { version = "1.27.0", features = ["full"] } diff --git a/foo/src/main.rs b/foo/src/main.rs new file mode 100644 index 0000000000..24c7704086 --- /dev/null +++ b/foo/src/main.rs @@ -0,0 +1,37 @@ +fn main() { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(outer_main()) +} + +async fn outer_main() { + let mut i = P { x: 10 }; + + yo(&mut i).await; + + let mut q = Q { p: &mut i }; + bo(&mut q).await; + + println!("Hello, world: {}", q.p.x); +} + +struct P { + x: i32, +} + +struct Q<'a> { + p: &'a mut P, +} + +async fn yo(i: &mut P) { + i.x = 20; + println!("yo: {}", i.x); +} + +async fn bo(q: &mut Q<'_>) { + // q.p = &mut P { x: 30 }; + q.p.x = 30; + println!("bo: {}", q.p.x); +} diff --git a/ftd/ftd-js.html b/ftd/ftd-js.html index 8113699d14..d9cad7d961 100644 --- a/ftd/ftd-js.html +++ b/ftd/ftd-js.html @@ -1,3 +1,4 @@ + @@ -9,7 +10,7 @@ __fastn_package__ - __script_file__ + __script_file____extra_js__ -
undefined Tuesday
undefined Wednesday
undefined Thursday
undefined Friday
undefined Saturday
@@ -33,10 +34,10 @@ return (fastn_utils.getter(index) >= 2); }, function (root) { let rooti0 = fastn_dom.createKernel(root, fastn_dom.ElementKind.Text); - rooti0.setProperty(fastn_dom.PropertyKind.StringValue, fastn.formula([global.foo__key, + rooti0.setProperty(fastn_dom.PropertyKind.StringValue, fastn.formula([index, item], function () { return foo__join({ - a: global.foo__key, + a: index, b: item, }, rooti0); }), inherited); diff --git a/ftd/t/js/28-mutable-component-arguments.html b/ftd/t/js/28-mutable-component-arguments.html index 0b37dfeb34..4a0c413094 100644 --- a/ftd/t/js/28-mutable-component-arguments.html +++ b/ftd/t/js/28-mutable-component-arguments.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/28-web-component.html b/ftd/t/js/28-web-component.html index 51bd4c0582..1d9a9dea8a 100644 --- a/ftd/t/js/28-web-component.html +++ b/ftd/t/js/28-web-component.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/29-dom-list.html b/ftd/t/js/29-dom-list.html index 404f405050..417e1033c4 100644 --- a/ftd/t/js/29-dom-list.html +++ b/ftd/t/js/29-dom-list.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/30-web-component.html b/ftd/t/js/30-web-component.html index 0aaa11417a..848c585116 100644 --- a/ftd/t/js/30-web-component.html +++ b/ftd/t/js/30-web-component.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/31-advance-list.html b/ftd/t/js/31-advance-list.html index 16fa8a21f2..c5f4e4f972 100644 --- a/ftd/t/js/31-advance-list.html +++ b/ftd/t/js/31-advance-list.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/31-ftd-len.html b/ftd/t/js/31-ftd-len.html index 138062e2c5..4d2e532852 100644 --- a/ftd/t/js/31-ftd-len.html +++ b/ftd/t/js/31-ftd-len.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/32-ftd-len.html b/ftd/t/js/32-ftd-len.html index 0c377f2531..5206899c8e 100644 --- a/ftd/t/js/32-ftd-len.html +++ b/ftd/t/js/32-ftd-len.html @@ -1,3 +1,4 @@ + @@ -68,8 +69,8 @@ fastn_utils.getter(global.foo__months).forLoop(root, function (root, item, index) { let rooti0 = fastn_dom.createKernel(root, fastn_dom.ElementKind.Text); rooti0.setProperty(fastn_dom.PropertyKind.StringValue, item, inherited); - rooti0.setProperty(fastn_dom.PropertyKind.Color, fastn.formula([global.foo__index, - global.foo__index], function () { + rooti0.setProperty(fastn_dom.PropertyKind.Color, fastn.formula([index, + index], function () { if (function () { return (fastn_utils.getter(index) % 3 == 1); }()) { diff --git a/ftd/t/js/33-list-indexing.html b/ftd/t/js/33-list-indexing.html index dcfb5c7cac..2718f39a3b 100644 --- a/ftd/t/js/33-list-indexing.html +++ b/ftd/t/js/33-list-indexing.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/34-ftd-ui.html b/ftd/t/js/34-ftd-ui.html index 4f4fe27d34..82e70de293 100644 --- a/ftd/t/js/34-ftd-ui.html +++ b/ftd/t/js/34-ftd-ui.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/36-single-ui.html b/ftd/t/js/36-single-ui.html index ec1ea6a6bf..534a0e9849 100644 --- a/ftd/t/js/36-single-ui.html +++ b/ftd/t/js/36-single-ui.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/37-expander.html b/ftd/t/js/37-expander.html index 67b4e371b0..52b120bc48 100644 --- a/ftd/t/js/37-expander.html +++ b/ftd/t/js/37-expander.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/38-background-image-properties.html b/ftd/t/js/38-background-image-properties.html index 72cd66cd35..099dec159d 100644 --- a/ftd/t/js/38-background-image-properties.html +++ b/ftd/t/js/38-background-image-properties.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/40-code-themes.html b/ftd/t/js/40-code-themes.html index 815c6c8a3f..c88d1d4117 100644 --- a/ftd/t/js/40-code-themes.html +++ b/ftd/t/js/40-code-themes.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/41-document-favicon.html b/ftd/t/js/41-document-favicon.html index aca8eaab1b..60ef9936a7 100644 --- a/ftd/t/js/41-document-favicon.html +++ b/ftd/t/js/41-document-favicon.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/42-links.html b/ftd/t/js/42-links.html index d14885e336..fabf6a47ab 100644 --- a/ftd/t/js/42-links.html +++ b/ftd/t/js/42-links.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/43-image-object-fit.html b/ftd/t/js/43-image-object-fit.html index 7e84848e09..792a7f9d3b 100644 --- a/ftd/t/js/43-image-object-fit.html +++ b/ftd/t/js/43-image-object-fit.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/44-local-storage.html b/ftd/t/js/44-local-storage.html index 5faa06089f..7ee99d8d27 100644 --- a/ftd/t/js/44-local-storage.html +++ b/ftd/t/js/44-local-storage.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/44-module.html b/ftd/t/js/44-module.html index a2743a18ec..77f902a972 100644 --- a/ftd/t/js/44-module.html +++ b/ftd/t/js/44-module.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/45-re-module.html b/ftd/t/js/45-re-module.html index 911159a75e..6bfeaf264a 100644 --- a/ftd/t/js/45-re-module.html +++ b/ftd/t/js/45-re-module.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/45-re-re-module.html b/ftd/t/js/45-re-re-module.html index 59a6a4aa56..0c5d306aa4 100644 --- a/ftd/t/js/45-re-re-module.html +++ b/ftd/t/js/45-re-re-module.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/46-code-languages.html b/ftd/t/js/46-code-languages.html index a58532063d..8e0540c626 100644 --- a/ftd/t/js/46-code-languages.html +++ b/ftd/t/js/46-code-languages.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/47-ftd-code-syntax.html b/ftd/t/js/47-ftd-code-syntax.html index a988b16f82..736ff5a620 100644 --- a/ftd/t/js/47-ftd-code-syntax.html +++ b/ftd/t/js/47-ftd-code-syntax.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/48-video.html b/ftd/t/js/48-video.html index f369a18ba1..658d97b277 100644 --- a/ftd/t/js/48-video.html +++ b/ftd/t/js/48-video.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/49-align-content.html b/ftd/t/js/49-align-content.html index c68bb2118f..be2ee5a441 100644 --- a/ftd/t/js/49-align-content.html +++ b/ftd/t/js/49-align-content.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/50-iframe-fullscreen.html b/ftd/t/js/50-iframe-fullscreen.html index 548e976c36..41dfa9bbb6 100644 --- a/ftd/t/js/50-iframe-fullscreen.html +++ b/ftd/t/js/50-iframe-fullscreen.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/51-markdown-table.html b/ftd/t/js/51-markdown-table.html index c94c24adba..199e3833d7 100644 --- a/ftd/t/js/51-markdown-table.html +++ b/ftd/t/js/51-markdown-table.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/52-events.html b/ftd/t/js/52-events.html index 8983db0826..5e10cc36b3 100644 --- a/ftd/t/js/52-events.html +++ b/ftd/t/js/52-events.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/53-link-color.html b/ftd/t/js/53-link-color.html index ae875faa86..c2d68c587b 100644 --- a/ftd/t/js/53-link-color.html +++ b/ftd/t/js/53-link-color.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/54-class-fix.html b/ftd/t/js/54-class-fix.html index 04b80f70da..f63a67cdf9 100644 --- a/ftd/t/js/54-class-fix.html +++ b/ftd/t/js/54-class-fix.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/56-title-fix.html b/ftd/t/js/56-title-fix.html index 93eb211fa7..9762741fe0 100644 --- a/ftd/t/js/56-title-fix.html +++ b/ftd/t/js/56-title-fix.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/57-code-dark-mode.html b/ftd/t/js/57-code-dark-mode.html index c8d3329344..2269cd535f 100644 --- a/ftd/t/js/57-code-dark-mode.html +++ b/ftd/t/js/57-code-dark-mode.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/59-text-shadow.html b/ftd/t/js/59-text-shadow.html index 1c145f4b56..23cc119eff 100644 --- a/ftd/t/js/59-text-shadow.html +++ b/ftd/t/js/59-text-shadow.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/60-conditional-module-headers.html b/ftd/t/js/60-conditional-module-headers.html index b764cf16a4..494ee2d7c5 100644 --- a/ftd/t/js/60-conditional-module-headers.html +++ b/ftd/t/js/60-conditional-module-headers.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/61-functions.html b/ftd/t/js/61-functions.html index 92fd34d3c3..5ad1b43532 100644 --- a/ftd/t/js/61-functions.html +++ b/ftd/t/js/61-functions.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/62-fallback-fonts.html b/ftd/t/js/62-fallback-fonts.html index b6194da9fe..7b63caa087 100644 --- a/ftd/t/js/62-fallback-fonts.html +++ b/ftd/t/js/62-fallback-fonts.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/63-external-js.html b/ftd/t/js/63-external-js.html index 4596553fb7..fc3d9e4942 100644 --- a/ftd/t/js/63-external-js.html +++ b/ftd/t/js/63-external-js.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/64-selectable.html b/ftd/t/js/64-selectable.html index 3d58f28f96..360544a2d4 100644 --- a/ftd/t/js/64-selectable.html +++ b/ftd/t/js/64-selectable.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/65-legacy.html b/ftd/t/js/65-legacy.html index 49e0b7e3a1..a95b895d8a 100644 --- a/ftd/t/js/65-legacy.html +++ b/ftd/t/js/65-legacy.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/66-backdrop-filter.html b/ftd/t/js/66-backdrop-filter.html index 158e8b5f00..a3c902b5cf 100644 --- a/ftd/t/js/66-backdrop-filter.html +++ b/ftd/t/js/66-backdrop-filter.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/67-counter.html b/ftd/t/js/67-counter.html index 63f4bb0dae..43c01a8c6b 100644 --- a/ftd/t/js/67-counter.html +++ b/ftd/t/js/67-counter.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/68-mask.html b/ftd/t/js/68-mask.html index 32fb620c9c..ffb9eca430 100644 --- a/ftd/t/js/68-mask.html +++ b/ftd/t/js/68-mask.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/69-chained-dot-value-in-functions.html b/ftd/t/js/69-chained-dot-value-in-functions.html index bd5811e428..8bacdcdcf2 100644 --- a/ftd/t/js/69-chained-dot-value-in-functions.html +++ b/ftd/t/js/69-chained-dot-value-in-functions.html @@ -1,3 +1,4 @@ + diff --git a/ftd/t/js/72-document-breakpoint.ftd b/ftd/t/js/72-document-breakpoint.ftd new file mode 100644 index 0000000000..8cab35565e --- /dev/null +++ b/ftd/t/js/72-document-breakpoint.ftd @@ -0,0 +1,9 @@ +-- ftd.document: +breakpoint: 800 + +-- ftd.text: +color: red +text if { ftd.device == "mobile" }: Mobile text +text if { ftd.device == "desktop" }: Desktop text + +-- end: ftd.document diff --git a/ftd/t/js/72-document-breakpoint.html b/ftd/t/js/72-document-breakpoint.html new file mode 100644 index 0000000000..9dd93d1504 --- /dev/null +++ b/ftd/t/js/72-document-breakpoint.html @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + +
Mobile text
+ + diff --git a/ftd/t/js/loop.html b/ftd/t/js/loop.html index 639d2e112e..19a5223f2f 100644 --- a/ftd/t/js/loop.html +++ b/ftd/t/js/loop.html @@ -1,3 +1,4 @@ +