presolve_compiler/
metaframework_handoff.rs1use std::collections::BTreeMap;
4
5use serde::Serialize;
6
7use crate::platform::Digest;
8use crate::RouteManifestV1;
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
11pub struct StaticRequestHandoffV1 {
12 pub schema_version: u32,
13 pub routes: Vec<StaticRequestRouteV1>,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
17pub struct StaticRequestRouteV1 {
18 pub method: String,
19 pub path: String,
20 pub artifact: String,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
24pub struct DeployableReleaseManifestV1 {
25 pub schema_version: u32,
26 pub release_id: String,
27 pub route_manifest_digest: String,
28 pub artifacts: Vec<DeployableArtifactV1>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
32pub struct DeployableArtifactV1 {
33 pub path: String,
34 pub digest: String,
35 pub size: u64,
36}
37
38#[must_use]
41pub fn build_static_request_handoff_v1(routes: &RouteManifestV1) -> StaticRequestHandoffV1 {
42 StaticRequestHandoffV1 {
43 schema_version: 1,
44 routes: routes
45 .routes
46 .iter()
47 .map(|route| StaticRequestRouteV1 {
48 method: "GET".into(),
49 path: route.path.clone(),
50 artifact: format!("{}/index.html", route.artifact_root),
51 })
52 .collect(),
53 }
54}
55
56#[must_use]
58pub fn build_deployable_release_manifest_v1(
59 routes: &RouteManifestV1,
60 artifacts: &BTreeMap<std::path::PathBuf, Vec<u8>>,
61) -> DeployableReleaseManifestV1 {
62 let inventory = artifacts
63 .iter()
64 .map(|(path, bytes)| DeployableArtifactV1 {
65 path: path.to_string_lossy().replace('\\', "/"),
66 digest: Digest::sha256(bytes).to_string(),
67 size: u64::try_from(bytes.len()).expect("artifact size exceeds u64"),
68 })
69 .collect::<Vec<_>>();
70 let route_manifest = serde_json::to_vec(routes).expect("route manifest serializes");
71 let route_manifest_digest = Digest::sha256(&route_manifest).to_string();
72 let release_id = Digest::sha256(
73 inventory
74 .iter()
75 .map(|artifact| format!("{}:{}:{}\n", artifact.path, artifact.digest, artifact.size))
76 .collect::<String>(),
77 )
78 .to_string();
79 DeployableReleaseManifestV1 {
80 schema_version: 1,
81 release_id,
82 route_manifest_digest,
83 artifacts: inventory,
84 }
85}
86
87#[must_use]
88pub fn static_request_handoff_json_v1(value: &StaticRequestHandoffV1) -> String {
89 serde_json::to_string_pretty(value).expect("request handoff serializes") + "\n"
90}
91
92#[must_use]
93pub fn deployable_release_manifest_json_v1(value: &DeployableReleaseManifestV1) -> String {
94 serde_json::to_string_pretty(value).expect("release manifest serializes") + "\n"
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use crate::RouteManifestEntryV1;
101
102 #[test]
103 fn derives_static_requests_and_stable_release_inventory() {
104 let routes = RouteManifestV1 {
105 schema_version: 1,
106 routes: vec![RouteManifestEntryV1 {
107 path: "/".into(),
108 component_id: "component:home".into(),
109 artifact_root: "routes/root".into(),
110 parent_path: None,
111 }],
112 };
113 let request = build_static_request_handoff_v1(&routes);
114 assert_eq!(request.routes[0].artifact, "routes/root/index.html");
115 let mut artifacts = BTreeMap::new();
116 artifacts.insert("routes/root/index.html".into(), b"<main />".to_vec());
117 let first = build_deployable_release_manifest_v1(&routes, &artifacts);
118 let second = build_deployable_release_manifest_v1(&routes, &artifacts);
119 assert_eq!(first.release_id, second.release_id);
120 assert!(deployable_release_manifest_json_v1(&first).contains("release_id"));
121 }
122}