mirror of
https://github.com/modrinth/code.git
synced 2026-08-26 01:26:23 +00:00
* chore(labrinth): bump to redis 1.4.1 * feat(labrinth): redis cluster * chore: cleanup * feat(labrinth): cache locking * fix(labrinth): clippy * chore(labrinth): cleanup env, remove postcard support * chore(ci): fix test env for labrinth * chore(labrinth): bump all key versions * chore(labrinth): improve redis key identities handling * chore(labrinth): simplify deadline handling * chore(labrinth): remove unused lease tracking * chore(labrinth): remove distributed cache locking for now * chore(labrinth): improve redis backend init error * feat(labrinth): expose redis read replica strategy * chore(ci): remove other connection mode tests * chore: split xredis crate * feat(xredis): primaries routing * chore: tombi fmt * chore: clippy * chore: update query cache
76 lines
2.0 KiB
Rust
76 lines
2.0 KiB
Rust
use std::fmt::Display;
|
|
use std::sync::Arc;
|
|
|
|
use crate::RedisTopology;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct KeyBuilder {
|
|
meta_namespace: Arc<str>,
|
|
mode: RedisTopology,
|
|
}
|
|
|
|
impl KeyBuilder {
|
|
pub fn new(
|
|
meta_namespace: impl Into<Arc<str>>,
|
|
mode: RedisTopology,
|
|
) -> Self {
|
|
Self {
|
|
meta_namespace: meta_namespace.into(),
|
|
mode,
|
|
}
|
|
}
|
|
|
|
/// Build a key with the given namespace and logical key. The logical key is used as the key's slot tag.
|
|
pub fn entity(&self, namespace: &str, logical_key: impl Display) -> String {
|
|
let logical_key = logical_key.to_string();
|
|
self.with_slot(namespace, &logical_key, &logical_key)
|
|
}
|
|
|
|
/// Build a metadata key with the given namespace and logical key. The slot tag is fixed to `_metadata`.
|
|
pub fn metadata(
|
|
&self,
|
|
namespace: &str,
|
|
logical_key: impl Display,
|
|
) -> String {
|
|
self.with_slot(namespace, logical_key, "_metadata")
|
|
}
|
|
|
|
/// Build a key with the given namespace, logical key, and slot tag.
|
|
pub fn with_slot(
|
|
&self,
|
|
namespace: &str,
|
|
logical_key: impl Display,
|
|
slot_tag: impl Display,
|
|
) -> String {
|
|
match self.mode {
|
|
RedisTopology::Standalone => {
|
|
format!("{}_{}:{}", self.meta_namespace, namespace, logical_key)
|
|
}
|
|
RedisTopology::Cluster => format!(
|
|
"{}_{}:{{{}}}:{}",
|
|
self.meta_namespace,
|
|
namespace,
|
|
escape_slot_tag(&slot_tag.to_string()),
|
|
logical_key
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn escape_slot_tag(value: &str) -> String {
|
|
if value.is_empty() {
|
|
return "%00".to_string();
|
|
}
|
|
|
|
let mut escaped = String::with_capacity(value.len());
|
|
for character in value.chars() {
|
|
match character {
|
|
'%' => escaped.push_str("%25"),
|
|
'{' => escaped.push_str("%7B"),
|
|
'}' => escaped.push_str("%7D"),
|
|
_ => escaped.push(character),
|
|
}
|
|
}
|
|
escaped
|
|
}
|