1use serde::Deserialize;
2use topcoat_core::context::Cx;
3use topcoat_router::{
4 Body, Method, Methods, Path, PathBuf, Route, RouteFuture, RouteId,
5 content::Json,
6 error::rewrite,
7 request::{FromRequest, uri},
8};
9
10use crate::SignalValues;
11
12pub(crate) const PAGE_ROUTE_PREFIX: &str = "/_topcoat/runtime/pages";
15
16#[derive(Debug, Deserialize)]
19struct PageRerunRequest {
20 #[serde(default)]
21 signals: SignalValues,
22}
23
24pub struct PageRerunRoute {
35 id: RouteId,
36 path: PathBuf,
37}
38
39impl PageRerunRoute {
40 #[must_use]
42 pub fn root() -> Self {
43 Self {
44 id: RouteId::new(),
45 path: Path::new(PAGE_ROUTE_PREFIX).to_owned(),
46 }
47 }
48
49 #[must_use]
51 pub fn nested() -> Self {
52 Self {
53 id: RouteId::new(),
54 path: Path::new(&format!("{PAGE_ROUTE_PREFIX}/{{*page}}")).to_owned(),
55 }
56 }
57}
58
59impl Route for PageRerunRoute {
60 fn id(&self) -> RouteId {
61 self.id
62 }
63
64 fn methods(&self) -> Methods<'_> {
65 Methods::Only(&[Method::POST])
67 }
68
69 fn path(&self) -> &Path {
70 &self.path
71 }
72
73 fn handle<'cx>(&'cx self, cx: &'cx Cx, body: Body) -> RouteFuture<'cx> {
74 Box::pin(async move {
75 let Json(request) = Json::<PageRerunRequest>::from_request(cx, body).await?;
76
77 let uri = uri(cx);
80 let mut target = match uri.path().strip_prefix(PAGE_ROUTE_PREFIX) {
81 Some(path) if !path.is_empty() => path.to_owned(),
82 _ => String::from("/"),
83 };
84 if let Some(query) = uri.query() {
85 target.push('?');
86 target.push_str(query);
87 }
88
89 Err(rewrite(target, Body::empty())
90 .method(Method::GET)
91 .cx(cx.with(request.signals))
92 .into())
93 })
94 }
95}