-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create _canonical_urls system table (#34431)
create a new system table `_canonical_urls` which will be the source of truth for the canonical urls of an instance. This data is related to but stored independently from the custom/vanity domains, which are used at the routing layer. In contrast, the canonical urls are owned by the backend/instance, so they can be used in `process.env.CONVEX_CLOUD_URL` and `process.env.CONVEX_SITE_URL`. Note the storage of urls instead of domains, since the urls can potentially be `http://` instead of `https://`, or have a `/http` path at the end. The overall plan is for the backend to own this "canonical url" information, and big brain doesn't care if those get out of sync with the verified custom domains (that big brain owns). These canonical urls will be used as the system env variables and also will be publically accessible so they can be used for `VITE_CONVEX_URL` by the CLI and such. The table is empty by default, in which case the urls used are the .convex.cloud and .convex.site ones. GitOrigin-RevId: aaa0bc6e0824d10f47d09c45bbc141d99d771d17
- Loading branch information
Showing
5 changed files
with
165 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
use std::{ | ||
collections::BTreeMap, | ||
sync::LazyLock, | ||
}; | ||
|
||
use common::{ | ||
document::{ | ||
ParsedDocument, | ||
ResolvedDocument, | ||
}, | ||
http::RequestDestination, | ||
query::{ | ||
Order, | ||
Query, | ||
}, | ||
runtime::Runtime, | ||
types::TableName, | ||
}; | ||
use database::{ | ||
ResolvedQuery, | ||
SystemMetadataModel, | ||
Transaction, | ||
}; | ||
use value::TableNamespace; | ||
|
||
use self::types::CanonicalUrl; | ||
use crate::SystemTable; | ||
|
||
pub mod types; | ||
|
||
pub static CANONICAL_URLS_TABLE: LazyLock<TableName> = LazyLock::new(|| { | ||
"_canonical_urls" | ||
.parse() | ||
.expect("Invalid built-in table name") | ||
}); | ||
|
||
pub struct CanonicalUrlsTable; | ||
|
||
impl SystemTable for CanonicalUrlsTable { | ||
fn table_name(&self) -> &'static TableName { | ||
&CANONICAL_URLS_TABLE | ||
} | ||
|
||
fn indexes(&self) -> Vec<crate::SystemIndex> { | ||
vec![] | ||
} | ||
|
||
fn validate_document(&self, document: ResolvedDocument) -> anyhow::Result<()> { | ||
ParsedDocument::<CanonicalUrl>::try_from(document).map(|_| ()) | ||
} | ||
} | ||
|
||
pub struct CanonicalUrlsModel<'a, RT: Runtime> { | ||
tx: &'a mut Transaction<RT>, | ||
} | ||
|
||
impl<'a, RT: Runtime> CanonicalUrlsModel<'a, RT> { | ||
pub fn new(tx: &'a mut Transaction<RT>) -> Self { | ||
Self { tx } | ||
} | ||
|
||
pub async fn get_canonical_urls( | ||
&mut self, | ||
) -> anyhow::Result<BTreeMap<RequestDestination, ParsedDocument<CanonicalUrl>>> { | ||
let query = Query::full_table_scan(CANONICAL_URLS_TABLE.clone(), Order::Asc); | ||
let mut query_stream = ResolvedQuery::new(self.tx, TableNamespace::Global, query)?; | ||
let mut canonical_urls = BTreeMap::new(); | ||
while let Some(document) = query_stream.next(self.tx, None).await? { | ||
let canonical_url = ParsedDocument::<CanonicalUrl>::try_from(document)?; | ||
canonical_urls.insert(canonical_url.request_destination, canonical_url); | ||
} | ||
Ok(canonical_urls) | ||
} | ||
|
||
pub async fn set_canonical_url( | ||
&mut self, | ||
request_destination: RequestDestination, | ||
url: String, | ||
) -> anyhow::Result<()> { | ||
if let Some(existing_canonical_url) = | ||
self.get_canonical_urls().await?.get(&request_destination) | ||
{ | ||
if existing_canonical_url.url == url { | ||
// Url isn't changing, so no-op. | ||
return Ok(()); | ||
} else { | ||
// Delete the existing canonical url. | ||
SystemMetadataModel::new_global(self.tx) | ||
.delete(existing_canonical_url.id()) | ||
.await?; | ||
} | ||
} | ||
let canonical_url = CanonicalUrl { | ||
request_destination, | ||
url, | ||
}; | ||
SystemMetadataModel::new_global(self.tx) | ||
.insert(&CANONICAL_URLS_TABLE, canonical_url.try_into()?) | ||
.await?; | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
use common::http::RequestDestination; | ||
use serde::{ | ||
Deserialize, | ||
Serialize, | ||
}; | ||
use value::codegen_convex_serialization; | ||
|
||
#[derive(Clone, Debug, Eq, PartialEq)] | ||
#[cfg_attr(any(test, feature = "testing"), derive(proptest_derive::Arbitrary))] | ||
pub struct CanonicalUrl { | ||
pub request_destination: RequestDestination, | ||
pub url: String, | ||
} | ||
|
||
#[derive(Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
struct SerializedCanonicalUrl { | ||
request_destination: String, | ||
url: String, | ||
} | ||
|
||
impl From<CanonicalUrl> for SerializedCanonicalUrl { | ||
fn from(value: CanonicalUrl) -> Self { | ||
Self { | ||
request_destination: match value.request_destination { | ||
RequestDestination::ConvexCloud => "convexCloud".to_string(), | ||
RequestDestination::ConvexSite => "convexSite".to_string(), | ||
}, | ||
url: value.url, | ||
} | ||
} | ||
} | ||
|
||
impl TryFrom<SerializedCanonicalUrl> for CanonicalUrl { | ||
type Error = anyhow::Error; | ||
|
||
fn try_from(value: SerializedCanonicalUrl) -> Result<Self, Self::Error> { | ||
Ok(Self { | ||
request_destination: match value.request_destination.as_str() { | ||
"convexCloud" => RequestDestination::ConvexCloud, | ||
"convexSite" => RequestDestination::ConvexSite, | ||
_ => anyhow::bail!("Invalid request destination: {}", value.request_destination), | ||
}, | ||
url: value.url, | ||
}) | ||
} | ||
} | ||
|
||
codegen_convex_serialization!(CanonicalUrl, SerializedCanonicalUrl); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters