Compare commits
17 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c04aced9a | |||
| 3275bb99a9 | |||
| f381cc60b4 | |||
| d5232b1145 | |||
| 9e65f42763 | |||
| 399235aeff | |||
| d21cc36330 | |||
| 5f8da4efdc | |||
| 24d94389cd | |||
| 26e7119768 | |||
| 1e950b9efc | |||
| bfd62fa4ef | |||
| 3fdd22c079 | |||
| 02ff3ad96f | |||
| e73f506daf | |||
| 573b1a7270 | |||
| 2c827c6608 |
14 changed files with 480 additions and 207 deletions
|
|
@ -38,4 +38,16 @@ jobs:
|
|||
with:
|
||||
push: true
|
||||
file: "Dockerfile.rich"
|
||||
tags: "forge.cptlobster.dev/cptlobster/stargate:dev-rich"
|
||||
tags: "forge.cptlobster.dev/cptlobster/stargate:dev-rich"
|
||||
|
||||
trivy:
|
||||
runs-on: docker
|
||||
container:
|
||||
image: aquasec/trivy:latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- name: "Scan Image (Minimal)"
|
||||
run: "trivy image forge.cptlobster.dev/cptlobster/stargate:dev"
|
||||
- name: "Scan Image (Rich Output)"
|
||||
run: "trivy image forge.cptlobster.dev/cptlobster/stargate:dev-rich"
|
||||
23
CHANGELOG.md
23
CHANGELOG.md
|
|
@ -2,5 +2,28 @@
|
|||
|
||||
## Unreleased Changes
|
||||
|
||||
## v0.1.4 (2026-01-30)
|
||||
- Update dependencies
|
||||
- `regex` from `1.11.1` → `1.12.2`
|
||||
- `tokio` from `1.45.1` → `1.49.0`
|
||||
- `log` from `0.4.27` → `0.4.29`
|
||||
- `tera` from `1.20.0` → `1.20.1`
|
||||
- [docker] Update base image to Alpine 3.23.
|
||||
- [docker] Images now have security scanning on build using Trivy.
|
||||
- Add support for hiding individual routes from route list.
|
||||
- Add command-line flag and environment variable for specifying the config file path.
|
||||
|
||||
## v0.1.3 (2025-09-09)
|
||||
- Add support for having an array of paths match a single endpoint.
|
||||
|
||||
## v0.1.2 (2025-09-05)
|
||||
- Allow for using slashes in paths.
|
||||
- Improve error handling slightly.
|
||||
- [rich] Tweak styles and add viewport scaling.
|
||||
|
||||
## v0.1.1 (2025-08-22)
|
||||
- [rich] Fix docker image missing templates
|
||||
- [rich] Add light mode to routes and error pages
|
||||
|
||||
## v0.1.0 (2025-08-22)
|
||||
- Initial release.
|
||||
321
Cargo.lock
generated
321
Cargo.lock
generated
|
|
@ -2,21 +2,6 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
|
|
@ -41,6 +26,56 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
|
|
@ -95,21 +130,6 @@ version = "1.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "binascii"
|
||||
version = "0.1.4"
|
||||
|
|
@ -189,7 +209,7 @@ dependencies = [
|
|||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -214,6 +234,52 @@ dependencies = [
|
|||
"phf_codegen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.18.1"
|
||||
|
|
@ -531,12 +597,6 @@ dependencies = [
|
|||
"wasi 0.14.2+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.2"
|
||||
|
|
@ -552,7 +612,7 @@ dependencies = [
|
|||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-automata 0.4.13",
|
||||
"regex-syntax 0.8.5",
|
||||
]
|
||||
|
||||
|
|
@ -592,6 +652,12 @@ version = "0.15.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
|
|
@ -675,7 +741,7 @@ dependencies = [
|
|||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"socket2 0.5.10",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
|
@ -716,7 +782,7 @@ dependencies = [
|
|||
"globset",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-automata 0.4.13",
|
||||
"same-file",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
|
|
@ -770,6 +836,12 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
|
|
@ -853,9 +925,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
|
|
@ -893,15 +965,6 @@ version = "0.3.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.11"
|
||||
|
|
@ -1007,21 +1070,18 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
|
|
@ -1296,13 +1356,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
version = "1.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-automata 0.4.13",
|
||||
"regex-syntax 0.8.5",
|
||||
]
|
||||
|
||||
|
|
@ -1317,9 +1377,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
|
@ -1432,12 +1492,6 @@ dependencies = [
|
|||
"uncased",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.7"
|
||||
|
|
@ -1601,6 +1655,16 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
|
|
@ -1618,8 +1682,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "stargate"
|
||||
version = "0.1.0"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"log",
|
||||
"regex",
|
||||
"rocket",
|
||||
|
|
@ -1638,6 +1703,12 @@ dependencies = [
|
|||
"loom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
|
|
@ -1664,9 +1735,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tera"
|
||||
version = "1.20.0"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee"
|
||||
checksum = "e8004bca281f2d32df3bacd59bc67b312cb4c70cea46cbd79dbe8ac5ed206722"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
|
|
@ -1681,7 +1752,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"slug",
|
||||
"unic-segment",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1747,26 +1818,25 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.45.1"
|
||||
version = "1.49.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
||||
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio 1.0.4",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"socket2 0.6.2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1942,68 +2012,30 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-property"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
|
||||
dependencies = [
|
||||
"unic-char-range",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-range"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
|
||||
|
||||
[[package]]
|
||||
name = "unic-common"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
|
||||
|
||||
[[package]]
|
||||
name = "unic-segment"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23"
|
||||
dependencies = [
|
||||
"unic-ucd-segment",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-ucd-segment"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700"
|
||||
dependencies = [
|
||||
"unic-char-property",
|
||||
"unic-char-range",
|
||||
"unic-ucd-version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-ucd-version"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
|
||||
dependencies = [
|
||||
"unic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
|
|
@ -2142,7 +2174,7 @@ version = "0.1.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2168,7 +2200,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
|||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
|
@ -2201,13 +2233,19 @@ version = "0.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2216,7 +2254,7 @@ version = "0.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2255,6 +2293,15 @@ dependencies = [
|
|||
"windows-targets 0.53.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
|
|
@ -2292,7 +2339,7 @@ version = "0.53.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
|
|
|
|||
11
Cargo.toml
11
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "stargate"
|
||||
version = "0.1.0"
|
||||
version = "0.1.4"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
|
|
@ -8,9 +8,10 @@ rich = [ "dep:tera", "dep:rocket_dyn_templates" ]
|
|||
|
||||
[dependencies]
|
||||
rocket = "0.5.1"
|
||||
regex = "1.11.1"
|
||||
regex = "1.12.2"
|
||||
clap = { version = "4.5.56", features = ["derive", "env"] }
|
||||
watchfile = { version = "0.1.1", default-features = false, features = ["toml"] }
|
||||
tokio = { version = "1.45.1", features = ["sync"] }
|
||||
log = "0.4.27"
|
||||
tera = { version = "1.20.0", optional = true, default-features = false }
|
||||
tokio = { version = "1.49.0", features = ["sync"] }
|
||||
log = "0.4.29"
|
||||
tera = { version = "1.20.1", optional = true, default-features = false }
|
||||
rocket_dyn_templates = { version = "0.2.0", optional = true, features = ["tera"] }
|
||||
11
Dockerfile
11
Dockerfile
|
|
@ -1,15 +1,20 @@
|
|||
FROM rust:alpine AS builder
|
||||
# build the executable in its own stage. rust is big
|
||||
FROM rust:alpine3.23 AS builder
|
||||
WORKDIR /usr/src/stargate
|
||||
|
||||
# install build dependencies
|
||||
RUN apk add musl-dev
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN cargo install --path .
|
||||
|
||||
FROM alpine:3.22
|
||||
# final image
|
||||
FROM alpine:3.23
|
||||
# copy executable from builder image
|
||||
COPY --from=builder /usr/local/cargo/bin/stargate /usr/local/bin/stargate
|
||||
|
||||
# set working directory to /etc/stargate, config file should be included here
|
||||
WORKDIR /etc/stargate
|
||||
|
||||
CMD ["stargate"]
|
||||
CMD ["stargate"]
|
||||
|
|
|
|||
|
|
@ -1,15 +1,23 @@
|
|||
FROM rust:alpine AS builder
|
||||
# build the executable in its own stage. rust is big
|
||||
FROM rust:alpine3.23 AS builder
|
||||
WORKDIR /usr/src/stargate
|
||||
|
||||
# install build dependencies
|
||||
RUN apk add musl-dev
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN cargo install --features rich --path .
|
||||
|
||||
FROM alpine:3.22
|
||||
# final image
|
||||
FROM alpine:3.23
|
||||
# copy executable from builder image
|
||||
COPY --from=builder /usr/local/cargo/bin/stargate /usr/local/bin/stargate
|
||||
|
||||
# set working directory to /etc/stargate, config file should be included here
|
||||
WORKDIR /etc/stargate
|
||||
|
||||
CMD ["stargate"]
|
||||
# include tera templates. TODO: figure out how to include at compile time
|
||||
COPY templates templates
|
||||
|
||||
CMD ["stargate"]
|
||||
|
|
|
|||
13
sg1.toml
13
sg1.toml
|
|
@ -4,11 +4,7 @@ from = "a"
|
|||
to = "https://cptlobster.dev"
|
||||
|
||||
[[routes]]
|
||||
from = "b"
|
||||
to = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
|
||||
[[routes]]
|
||||
from = "d"
|
||||
from = ["b", "d"]
|
||||
to = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
|
||||
# This is a simple regex matcher. It will match any string that ends in "ic".
|
||||
|
|
@ -21,4 +17,9 @@ using = "regex"
|
|||
from = "dod([fs][0-9]{2})e([0-9]{3})"
|
||||
# Capture groups can be replaced using numbered capture groups (`$1`, `$2`, ...)
|
||||
to = "https://dod.cptlobster.dev/episodes/$1/$2"
|
||||
using = "regex"
|
||||
using = "regex"
|
||||
hidden = true
|
||||
|
||||
[[routes]]
|
||||
from = "sub/path"
|
||||
to = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
use std::path::PathBuf;
|
||||
// Copyright (C) 2025 Dustin Thomas <io@cptlobster.dev>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under the terms of the
|
||||
|
|
@ -11,6 +10,7 @@ use std::path::PathBuf;
|
|||
//
|
||||
// You should have received a copy of the GNU General Public License along with this program. If
|
||||
// not, see <https://www.gnu.org/licenses/>.
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::time::Duration;
|
||||
use watchfile::WatchFile;
|
||||
|
|
@ -32,6 +32,10 @@ impl Default for ConfigManager {
|
|||
}
|
||||
|
||||
impl ConfigManager {
|
||||
pub fn from_file(file: PathBuf) -> Self {
|
||||
ConfigManager { file: file.clone(), watcher: Config::watch_file(file, Duration::from_secs(5)), content: Arc::new(RwLock::new(None)) }
|
||||
}
|
||||
|
||||
pub async fn get(&self) -> Config {
|
||||
log::info!("File changed: {}", self.watcher.has_changed().unwrap());
|
||||
if self.watcher.has_changed().unwrap() || self.content.read().unwrap().is_none() {
|
||||
|
|
@ -57,35 +61,71 @@ pub struct Config {
|
|||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Route {
|
||||
from: String,
|
||||
to: String,
|
||||
pub from: Multiable<String>,
|
||||
pub to: String,
|
||||
#[serde(default)]
|
||||
using: MatcherType
|
||||
pub using: MatcherType,
|
||||
#[serde(default)]
|
||||
pub hidden: bool
|
||||
}
|
||||
|
||||
/// Something that can either be a single item or multiple items.
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[serde(crate = "rocket::serde", untagged)]
|
||||
pub enum Multiable<T> {
|
||||
Single(T),
|
||||
Multi(Vec<T>)
|
||||
}
|
||||
|
||||
impl Route {
|
||||
pub fn matches(&self, input: &str) -> bool {
|
||||
match self.using {
|
||||
MatcherType::Regex => {
|
||||
let re = Regex::new(format!("^{}$", self.from).as_str()).unwrap();
|
||||
match &self.from {
|
||||
Multiable::Single(from) => match self.using {
|
||||
MatcherType::Regex => {
|
||||
let re = Regex::new(format ! ("^{}$", from).as_str()).unwrap();
|
||||
re.is_match(input)
|
||||
},
|
||||
_ => self.from == input.to_string()
|
||||
},
|
||||
_ => *from == input.to_string()
|
||||
}
|
||||
Multiable::Multi(from_vec) => match self.using {
|
||||
MatcherType::Regex => {
|
||||
from_vec.into_iter().find(|from| {
|
||||
let re = Regex::new(format ! ("^{}$", from).as_str()).unwrap();
|
||||
re.is_match(input)
|
||||
}).is_some()
|
||||
},
|
||||
_ => from_vec.into_iter().find(|from| **from == input.to_string()).is_some()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn src(&self) -> String {
|
||||
self.from.clone()
|
||||
pub fn src(&self) -> Vec<String> {
|
||||
match &self.from {
|
||||
Multiable::Single(from) => vec![from.clone()],
|
||||
Multiable::Multi(from_vec) => from_vec.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dest(&self, input: &str) -> String {
|
||||
match self.using {
|
||||
MatcherType::Regex => {
|
||||
let re = Regex::new(format!("^{}$", self.from).as_str()).unwrap();
|
||||
match &self.from {
|
||||
Multiable::Single(from) => match self.using {
|
||||
MatcherType::Regex => {
|
||||
let re = Regex::new(format ! ("^{}$", from).as_str()).unwrap();
|
||||
let result = re.replace_all(input, self.to.clone());
|
||||
result.clone().parse().unwrap()
|
||||
},
|
||||
_ => self.to.clone()
|
||||
},
|
||||
_ => self.to.clone()
|
||||
Multiable::Multi(from_vec) => match self.using {
|
||||
MatcherType::Regex => {
|
||||
from_vec.into_iter().find(|from| {
|
||||
let re = Regex::new(format!("^{}$", from).as_str()).unwrap();
|
||||
let result = re.replace_all(input, self.to.clone());
|
||||
result.clone().parse().unwrap()
|
||||
}).unwrap().clone()
|
||||
},
|
||||
_ => self.to.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
114
src/main.rs
114
src/main.rs
|
|
@ -14,9 +14,12 @@
|
|||
|
||||
mod config;
|
||||
|
||||
use rocket::{State, Request};
|
||||
use std::path::{PathBuf};
|
||||
use clap::Parser;
|
||||
use rocket::{State, Request, Error};
|
||||
use rocket::http::Status;
|
||||
use rocket::response::Redirect;
|
||||
use rocket::response::status::{NoContent, NotFound};
|
||||
use rocket::response::status::{BadRequest, NoContent, NotFound};
|
||||
use crate::config::{ConfigManager, Route};
|
||||
#[cfg(feature = "rich")]
|
||||
use rocket_dyn_templates::{Template, tera::Tera, context};
|
||||
|
|
@ -27,7 +30,7 @@ use rocket_dyn_templates::{Template, tera::Tera, context};
|
|||
async fn list_paths(cm: &State<ConfigManager>) -> Result<String, NoContent> {
|
||||
let config = cm.get().await;
|
||||
if config.hide_routes { return Err(NoContent) }
|
||||
let all_routes = config.routes.iter().map(|r: &Route| r.src()).collect::<Vec<String>>();
|
||||
let all_routes = config.routes.iter().filter(|r| !r.hidden).flat_map(|r: &Route| r.src()).collect::<Vec<String>>();
|
||||
if all_routes.is_empty() { Err(NoContent) } else {
|
||||
Ok(all_routes.into_iter().map(|a| format!("/{}", a)).collect::<Vec<String>>().join("\n"))
|
||||
}
|
||||
|
|
@ -45,50 +48,119 @@ async fn list_paths(cm: &State<ConfigManager>) -> Template {
|
|||
|
||||
/// Try to redirect the specified path; If successful, return a See Other (HTTP 303) to the
|
||||
/// configured destination. If it fails to match a path, return a Not Found (HTTP 404).
|
||||
#[get("/<path>")]
|
||||
#[get("/<path..>")]
|
||||
#[cfg(not(feature = "rich"))]
|
||||
async fn redirect_path(cm: &State<ConfigManager>, path: &str) -> Result<Redirect, NotFound<String>> {
|
||||
async fn redirect_path(cm: &State<ConfigManager>, path: PathBuf) -> Result<Redirect, Status> {
|
||||
let config = cm.get().await;
|
||||
match config.find(path) {
|
||||
Some(p) => Ok(Redirect::to(p)),
|
||||
None => {
|
||||
Err(NotFound(format!("No matching route found: {}", path)))
|
||||
if let Some(p) = path.to_str() {
|
||||
debug!("Path string: {}", p);
|
||||
match config.find(p) {
|
||||
Some(p) => Ok(Redirect::to(p)),
|
||||
None => {
|
||||
Err(Status::NotFound)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(Status::BadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to redirect the specified path; If successful, return a See Other (HTTP 303) to the
|
||||
/// configured destination. If it fails to match a path, return a Not Found (HTTP 404).
|
||||
#[get("/<path>")]
|
||||
#[get("/<path..>")]
|
||||
#[cfg(feature = "rich")]
|
||||
async fn redirect_path(cm: &State<ConfigManager>, path: &str) -> Result<Redirect, NotFound<Template>> {
|
||||
async fn redirect_path(cm: &State<ConfigManager>, path: PathBuf) -> Result<Redirect, Status> {
|
||||
let config = cm.get().await;
|
||||
match config.find(path) {
|
||||
Some(p) => Ok(Redirect::to(p)),
|
||||
None => {
|
||||
Err(NotFound(Template::render("notfound", context!{
|
||||
title: "Not Found",
|
||||
path: path,
|
||||
config: &config
|
||||
})))
|
||||
if let Some(p) = path.to_str() {
|
||||
debug!("Path string: {}", p);
|
||||
match config.find(p) {
|
||||
Some(p) => Ok(Redirect::to(p)),
|
||||
None => {
|
||||
Err(Status::NotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Err(Status::BadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
#[catch(400)]
|
||||
#[cfg(feature = "rich")]
|
||||
fn bad_request() -> BadRequest<Template> {
|
||||
BadRequest(Template::render("errors/badrequest", context! {
|
||||
title: "Bad Request"
|
||||
}))
|
||||
}
|
||||
|
||||
#[catch(404)]
|
||||
#[cfg(feature = "rich")]
|
||||
fn not_found(req: &Request) -> NotFound<Template> {
|
||||
NotFound(Template::render("errors/notfound", context! {
|
||||
title: "Not Found",
|
||||
path: req.uri()
|
||||
}))
|
||||
}
|
||||
|
||||
#[catch(500)]
|
||||
#[cfg(feature = "rich")]
|
||||
fn internal_error() -> Template {
|
||||
Template::render("errors/servererror", context! {
|
||||
title: "Internal Server Error"
|
||||
})
|
||||
}
|
||||
|
||||
#[catch(400)]
|
||||
#[cfg(not(feature = "rich"))]
|
||||
fn bad_request() -> BadRequest<&'static str> {
|
||||
BadRequest("Malformed request")
|
||||
}
|
||||
|
||||
#[catch(404)]
|
||||
#[cfg(not(feature = "rich"))]
|
||||
fn not_found(req: &Request) -> NotFound<String> {
|
||||
NotFound(format!("No matching route found: {}", req.uri()))
|
||||
}
|
||||
|
||||
#[catch(500)]
|
||||
#[cfg(not(feature = "rich"))]
|
||||
fn internal_error() -> &'static str {
|
||||
"Internal server error occurred. Please try again later."
|
||||
}
|
||||
|
||||
/// Stargate is a minimal URL shortener service.
|
||||
#[derive(Parser)]
|
||||
struct Cli {
|
||||
/// The path to the configuration file to watch.
|
||||
#[arg(short, long, env = "SG1_CONFIG_FILE", default_value = "./sg1.toml")]
|
||||
config_file: PathBuf
|
||||
}
|
||||
|
||||
/// Read the configuration file and start the server.
|
||||
#[launch]
|
||||
#[cfg(feature = "rich")]
|
||||
async fn rocket() -> _ {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let cm = ConfigManager::from_file(cli.config_file);
|
||||
|
||||
rocket::build()
|
||||
.manage(ConfigManager::default())
|
||||
.manage(cm)
|
||||
.mount("/", routes![list_paths, redirect_path])
|
||||
.register("/", catchers![internal_error, not_found, bad_request])
|
||||
.attach(Template::fairing())
|
||||
}
|
||||
|
||||
/// Read the configuration file and start the server.
|
||||
#[launch]
|
||||
#[cfg(not(feature = "rich"))]
|
||||
async fn rocket() -> _ {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let cm = ConfigManager::from_file(cli.config_file);
|
||||
|
||||
rocket::build()
|
||||
.manage(ConfigManager::default())
|
||||
.manage(cm)
|
||||
.mount("/", routes![list_paths, redirect_path])
|
||||
.register("/", catchers![internal_error, not_found, bad_request])
|
||||
}
|
||||
|
|
@ -7,16 +7,63 @@
|
|||
{% else %}
|
||||
<title>stargate</title>
|
||||
{% endif %}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
* {
|
||||
transition: all 0.25s ease-in-out;
|
||||
}
|
||||
|
||||
:root {
|
||||
--fg: hsl(240, 60%, 85%);
|
||||
--fg-header: hsl(240, 60%, 100%);
|
||||
--bg: hsl(240, 30%, 20%);
|
||||
--link: hsl(240, 100%, 75%);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--fg: hsl(240, 60%, 15%);
|
||||
--fg-header: hsl(240, 60%, 0%);
|
||||
--bg: hsl(240, 30%, 85%);
|
||||
--link: hsl(240, 100%, 35%);
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: hsl(240, 20%, 15%);
|
||||
color: hsl(240, 40%, 80%);
|
||||
margin: 5rem;
|
||||
background-color: var(--bg);
|
||||
color: var(--fg);
|
||||
margin: 4rem 5vw;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
color: hsl(240, 100%, 80%);
|
||||
color: var(--link);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--fg-header);
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
color: var(--fg-header);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
ul {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
main {
|
||||
|
|
@ -24,7 +71,7 @@
|
|||
}
|
||||
|
||||
footer {
|
||||
border-top: 1px solid hsl(240, 20%, 50%);
|
||||
border-top: 1px solid hsla(240, 20%, 50%, 40%);
|
||||
margin-top: 4rem;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -37,9 +84,7 @@
|
|||
<h2>stargate</h2>
|
||||
<p>
|
||||
stargate is a minimal URL shortener service. For more information and how to deploy this yourself, visit
|
||||
<a href="https://forge.cptlobster.dev/cptlobster/stargate">the repository</a>.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://forge.cptlobster.dev/cptlobster/stargate">the repository</a>.<br />
|
||||
stargate is licensed using <a href="https://www.gnu.org/licenses/gpl-3.0.html">the GNU General Public License,
|
||||
Version 3</a>.
|
||||
</p>
|
||||
|
|
|
|||
7
templates/errors/badrequest.html.tera
Normal file
7
templates/errors/badrequest.html.tera
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{% extends "base" %}
|
||||
{% block content %}
|
||||
<h1>Bad Request</h1>
|
||||
<p>
|
||||
Please check for any spelling mistakes.
|
||||
</p>
|
||||
{% endblock content %}
|
||||
|
|
@ -2,11 +2,6 @@
|
|||
{% block content %}
|
||||
<h1>{{ path }}: Not Found</h1>
|
||||
<p>
|
||||
Could not find a matching route. Please check for any spelling mistakes
|
||||
{%- if config.hide_routes -%}
|
||||
.
|
||||
{%- else -%}
|
||||
, or <a href="/">view the list of available routes</a>.
|
||||
{%- endif %}
|
||||
Could not find a matching route. Please check for any spelling mistakes.
|
||||
</p>
|
||||
{% endblock content %}
|
||||
7
templates/errors/servererror.html.tera
Normal file
7
templates/errors/servererror.html.tera
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{% extends "base" %}
|
||||
{% block content %}
|
||||
<h1>Internal Server Error</h1>
|
||||
<p>
|
||||
Please try again later. If you are an administrator, please check the application logs.
|
||||
</p>
|
||||
{% endblock content %}
|
||||
|
|
@ -10,14 +10,24 @@
|
|||
</p>
|
||||
<ul>
|
||||
{%- for route in config.routes %}
|
||||
{%- if not route.hidden %}
|
||||
<li>
|
||||
{%- if route.using == "regex" %}
|
||||
<code>/{{ route.from }}</code>
|
||||
{% if route.from is iterable %}
|
||||
{% for r in route.from %}<code>/{{ r }}</code>{% if not loop.last %}, {% endif %}{% endfor %}
|
||||
{% else %}
|
||||
<code>/{{ route.from }}</code>
|
||||
{% endif %}
|
||||
{%- else %}
|
||||
<a href="/{{ route.from }}">/{{ route.from }}</a>
|
||||
{% if route.from is iterable %}
|
||||
{% for r in route.from %}<a href="/{{ r }}">/{{ r }}</a>{% if not loop.last %}, {% endif %}{% endfor %}
|
||||
{% else %}
|
||||
<a href="/{{ route.from }}">/{{ route.from }}</a>
|
||||
{% endif %}
|
||||
{%- endif %}
|
||||
({{ route.using }})
|
||||
</li>
|
||||
{%- endif %}
|
||||
{%- else %}
|
||||
<li>No routes configured.</li>
|
||||
{%- endfor %}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue