use std::path::{Path, PathBuf};
use anyhow::Context as _;
use super::Durability;
use knot_types::AccountDid;
use super::keys::{CobStateKey, RepoKey};
use super::record::{
Guarded, Locked, Once, OutputRoot, Put, Record, SealedDir, decode_json, encode_json,
};
pub(crate) struct Backend;
impl Record for Backend {
type Area = OutputRoot;
const NAME: &'static str = "backend publication record";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Fsync;
type Key = ();
type Value = crate::publish::BackendRecord;
fn relative((): &Self::Key) -> PathBuf {
PathBuf::from("active.json")
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
encode_json(Self::VERSION, value)
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
decode_json(Self::VERSION, Self::NAME, bytes)
}
}
impl Put for Backend {}
pub(crate) struct SpindleOutbox;
impl Record for SpindleOutbox {
type Area = OutputRoot;
const NAME: &'static str = "spindle outbox";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Fsync;
type Key = ();
type Value = crate::spindle::outbox::Queue;
fn relative((): &Self::Key) -> PathBuf {
PathBuf::from("spindle-outbox.json")
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
encode_json(Self::VERSION, value)
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
decode_json(Self::VERSION, Self::NAME, bytes)
}
}
impl Locked for SpindleOutbox {
const LOCK: &'static str = ".spindle-outbox.lock";
fn initial() -> Self::Value {
Self::Value::default()
}
}
pub(crate) struct SshKeys;
impl Record for SshKeys {
type Area = OutputRoot;
const NAME: &'static str = "ssh key set";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Fsync;
type Key = ();
type Value = crate::keys::Keys;
fn relative((): &Self::Key) -> PathBuf {
PathBuf::from("ssh-keys.json")
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
encode_json(Self::VERSION, value)
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
decode_json(Self::VERSION, Self::NAME, bytes)
}
}
impl Locked for SshKeys {
/// separate from the output-root lock because key sync waits on remote pds calls
const LOCK: &'static str = ".keys.lock";
fn initial() -> Self::Value {
Self::Value::new()
}
}
/// never replace it, a pds already holds the first public half.
pub(crate) struct OauthClientKey;
impl Record for OauthClientKey {
type Area = SealedDir;
const NAME: &'static str = "oauth client key";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Fsync;
type Key = ();
type Value = Vec<u8>;
fn relative((): &Self::Key) -> PathBuf {
PathBuf::from("client_key.sealed")
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
Ok(value.clone())
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
Ok(bytes.to_vec())
}
}
impl Once for OauthClientKey {}
pub(crate) struct OauthSession;
impl Record for OauthSession {
type Area = SealedDir;
const NAME: &'static str = "oauth session";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Fsync;
type Key = AccountDid;
type Value = Vec<u8>;
fn relative(owner: &Self::Key) -> PathBuf {
let name = owner.as_str().replace(':', "_");
Path::new("sessions").join(format!("{name}.sealed"))
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
Ok(value.clone())
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
Ok(bytes.to_vec())
}
}
impl Guarded for OauthSession {
fn lock(owner: &Self::Key) -> PathBuf {
let name = owner.as_str().replace(':', "_");
Path::new("sessions").join(format!(".{name}.lock"))
}
}
pub(crate) struct CobStatePointer;
impl Record for CobStatePointer {
type Area = OutputRoot;
const NAME: &'static str = "cob state pointer";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Fsync;
type Key = RepoKey;
type Value = CobStateKey;
fn relative(key: &Self::Key) -> PathBuf {
key.dir().join("cache/atproto-cobs.current")
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
Ok(value.as_str().as_bytes().to_vec())
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
CobStateKey::new(std::str::from_utf8(bytes).context("the cob state pointer is not text")?)
}
}
impl Put for CobStatePointer {}
pub(crate) struct ActivationTombstone;
impl Record for ActivationTombstone {
type Area = OutputRoot;
const NAME: &'static str = "activation tombstone";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Fsync;
type Key = ();
type Value = crate::tombstone::Tombstone;
fn relative((): &Self::Key) -> PathBuf {
PathBuf::from(crate::tombstone::FILE_NAME)
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
encode_json(Self::VERSION, value)
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
decode_json(Self::VERSION, Self::NAME, bytes)
}
}
impl Put for ActivationTombstone {}
pub(crate) struct OwnerHandles;
impl Record for OwnerHandles {
type Area = OutputRoot;
const NAME: &'static str = "owner handle cache";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Rename;
type Key = ();
type Value = crate::index_page::StoredHandles;
fn relative((): &Self::Key) -> PathBuf {
PathBuf::from("owner-handles.json")
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
encode_json(Self::VERSION, value)
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
decode_json(Self::VERSION, Self::NAME, bytes)
}
}
impl Put for OwnerHandles {}
pub(crate) struct IndexPulse;
impl Record for IndexPulse {
type Area = OutputRoot;
const NAME: &'static str = "index page push counts";
const VERSION: u32 = 1;
const DURABILITY: Durability = Durability::Rename;
type Key = ();
type Value = crate::index_page::Counted;
fn relative((): &Self::Key) -> PathBuf {
PathBuf::from("index-pulse.json")
}
fn encode(value: &Self::Value) -> anyhow::Result<Vec<u8>> {
encode_json(Self::VERSION, value)
}
fn decode(bytes: &[u8]) -> anyhow::Result<Self::Value> {
decode_json(Self::VERSION, Self::NAME, bytes)
}
}
impl Put for IndexPulse {}