Skip to content

Commit 0f829a3

Browse files
authored
serve: try the upstream ab-cdn before the JIT build lanes (#22)
1 parent 0cdf774 commit 0f829a3

7 files changed

Lines changed: 490 additions & 71 deletions

File tree

crate/src/abcdn/config.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ pub struct Config {
2424
pub jit_content_digest: bool,
2525

2626
pub upstream_ab_cdn: Option<String>,
27+
28+
pub upstream_ab_registry: Option<String>,
2729
}
2830

2931
impl Config {
@@ -40,6 +42,11 @@ impl Config {
4042
"http://127.0.0.1:5141/content".to_string()
4143
});
4244

45+
let upstream_ab_cdn = env::var("ABGEN_UPSTREAM_AB_CDN")
46+
.ok()
47+
.map(|s| s.trim().trim_end_matches('/').to_string())
48+
.filter(|s| !s.is_empty());
49+
4350
// A loopback content server is a dev preview server (sdk-commands): its
4451
// declared hashes are path-based and never change on edit, so content
4552
// revalidation defaults to ON there. Explicit env always wins.
@@ -77,13 +84,32 @@ impl Config {
7784
.filter(|s| !s.is_empty()),
7885
content_database_url: content_connection_string(),
7986
jit_content_digest,
80-
upstream_ab_cdn: env::var("ABGEN_UPSTREAM_AB_CDN")
87+
upstream_ab_cdn: upstream_ab_cdn.clone(),
88+
upstream_ab_registry: match env::var("ABGEN_UPSTREAM_AB_REGISTRY")
8189
.ok()
8290
.map(|s| s.trim().trim_end_matches('/').to_string())
83-
.filter(|s| !s.is_empty()),
91+
{
92+
Some(s) if s.eq_ignore_ascii_case("off") => None,
93+
Some(s) if !s.is_empty() => Some(s),
94+
// Registry answers must name the versions the CDN actually
95+
// serves, so the default pairs with the upstream CDN.
96+
_ => upstream_ab_cdn.as_deref().and_then(registry_for_ab_cdn),
97+
},
8498
})
8599
}
86100
}
101+
102+
fn registry_for_ab_cdn(cdn: &str) -> Option<String> {
103+
match cdn {
104+
"https://ab-cdn.decentraland.org" => {
105+
Some("https://asset-bundle-registry.decentraland.org".to_string())
106+
}
107+
"https://ab-cdn.decentraland.zone" => {
108+
Some("https://asset-bundle-registry.decentraland.zone".to_string())
109+
}
110+
_ => None,
111+
}
112+
}
87113
fn content_connection_string() -> Option<String> {
88114
if let Ok(url) = env::var("CONTENT_PG_CONNECTION_STRING") {
89115
if !url.trim().is_empty() {

crate/src/abcdn/handlers/dispatch.rs

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@ pub async fn dispatch(
88
) -> Response {
99
let path = uri.path().trim_start_matches('/').to_string();
1010
revalidate_if_stale(&state, &path).await;
11-
let resp = dispatch_with_fallbacks(&state, &path, &method, &headers).await;
12-
if resp.status() == StatusCode::NOT_FOUND && state.upstream_ab_cdn.is_some() {
13-
return upstream_fallback(&state, &path, &method, &headers, resp).await;
14-
}
15-
resp
11+
dispatch_with_fallbacks(&state, &path, &method, &headers).await
1612
}
1713

1814
async fn dispatch_with_fallbacks(
@@ -22,30 +18,48 @@ async fn dispatch_with_fallbacks(
2218
headers: &HeaderMap,
2319
) -> Response {
2420
let local = dispatch_local(state, path, method, headers).await;
21+
if local.status() != StatusCode::NOT_FOUND {
22+
return local;
23+
}
2524

26-
if local.status() == StatusCode::NOT_FOUND {
27-
if let Some(target) = resolver::shader_target(path) {
28-
return shader_fallback(state, path, &target, method, headers, local).await;
29-
}
30-
if let Some(proxy) = state.live_proxy.clone() {
31-
if let Some(target) = jit_target(path) {
32-
return bundle_fallback(state, proxy, path, &target, method, headers, local).await;
33-
}
34-
if br_bundle_target(path) {
35-
return with_reason(local, "br-not-built");
36-
}
37-
}
38-
if path.split('/').next() == Some("LOD") {
39-
return lod_fallback(state, path, method, headers, local).await;
25+
if let Some(target) = resolver::shader_target(path) {
26+
return shader_fallback(state, path, &target, method, headers, local).await;
27+
}
28+
29+
// Upstream before any build lane: when a production ab-cdn is configured,
30+
// entities it already serves (wearables, emotes, remote scenes) should
31+
// stream from it rather than be probed with a local JIT build — against a
32+
// preview content server that build can only fail its entity resolve and
33+
// log a write-back warning per entity. Local-corpus ids (b64-) and
34+
// upstream misses fall through to the build lanes as before.
35+
let local = if state.upstream_ab_cdn.is_some() {
36+
let up = upstream_fallback(state, path, method, headers, local).await;
37+
if up.status() != StatusCode::NOT_FOUND {
38+
return up;
4039
}
41-
let segs: Vec<&str> = path.split('/').collect();
42-
if segs.len() == 3 && segs[0] == "lods-unity" && segs[1] == "manifests" {
43-
return iss_fallback(state, path, method, headers, local).await;
40+
up
41+
} else {
42+
local
43+
};
44+
45+
if let Some(proxy) = state.live_proxy.clone() {
46+
if let Some(target) = jit_target(path) {
47+
return bundle_fallback(state, proxy, path, &target, method, headers, local).await;
4448
}
45-
if let Some((bare, platform)) = flat_target(path) {
46-
return flat_fallback(state, path, &bare, &platform, method, headers, local).await;
49+
if br_bundle_target(path) {
50+
return with_reason(local, "br-not-built");
4751
}
4852
}
53+
if path.split('/').next() == Some("LOD") {
54+
return lod_fallback(state, path, method, headers, local).await;
55+
}
56+
let segs: Vec<&str> = path.split('/').collect();
57+
if segs.len() == 3 && segs[0] == "lods-unity" && segs[1] == "manifests" {
58+
return iss_fallback(state, path, method, headers, local).await;
59+
}
60+
if let Some((bare, platform)) = flat_target(path) {
61+
return flat_fallback(state, path, &bare, &platform, method, headers, local).await;
62+
}
4963
local
5064
}
5165

0 commit comments

Comments
 (0)