Files
galaxy/crates/warp_server_client/src/persistence/cloud_objects.rs
T

133 lines
4.7 KiB
Rust

//! Supporting types for persisting cloud objects to SQLite.
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use crate::{
auth::UserUid,
cloud_object::{CloudLinkSharing, CloudObjectGuest, ServerObjectContainer},
drive::sharing::{SharingAccessLevel, Subject, TeamKind, UserKind},
ids::ServerId,
};
/// Decode a link-sharing setting.
pub fn decode_link_sharing(
encoded_access_level: &str,
encoded_source: Option<&[u8]>,
) -> anyhow::Result<CloudLinkSharing> {
let access_level = encoded_access_level.parse()?;
let source = encoded_source.map(bincode::deserialize).transpose()?;
Ok(CloudLinkSharing {
access_level,
source,
})
}
/// Encode a link-sharing setting.
pub fn encode_link_sharing(
link_sharing: &CloudLinkSharing,
) -> anyhow::Result<(&'static str, Option<Vec<u8>>)> {
let source = link_sharing
.source
.as_ref()
.map(bincode::serialize)
.transpose()?;
Ok((link_sharing.access_level.to_serializable_value(), source))
}
/// Deserialize encoded object guests.
pub fn decode_guests(encoded_guests: &[u8]) -> anyhow::Result<Vec<CloudObjectGuest>> {
let persisted_guests = bincode::deserialize::<Vec<PersistedGuest>>(encoded_guests)?;
Ok(persisted_guests
.into_iter()
.map(PersistedGuest::into_cloud_object_guest)
.collect())
}
/// Encode object guests for persistence.
pub fn encode_guests(guests: &[CloudObjectGuest]) -> anyhow::Result<Vec<u8>> {
let persisted_guests = guests
.iter()
.map(PersistedGuest::try_from_cloud_object_guest)
.collect::<anyhow::Result<Vec<PersistedGuest>>>()?;
Ok(bincode::serialize(&persisted_guests)?)
}
/// Database representation of an object guest. These are [`bincode`]-serialized to support storing
/// an arbitrarily-long guest list.
#[derive(Serialize, Deserialize)]
struct PersistedGuest {
subject: PersistedSubject,
access_level: SharingAccessLevel,
source: Option<ServerObjectContainer>,
}
/// Database representation of a guest subject. This is restricted compared to the [`Subject`] type
/// since not all subjects are persisted.
#[derive(Serialize, Deserialize)]
enum PersistedSubject {
User { firebase_uid: String },
PendingUser { email: Option<String> },
Team { team_uid: ServerId },
}
impl PersistedGuest {
pub fn into_cloud_object_guest(self) -> CloudObjectGuest {
CloudObjectGuest {
subject: self.subject.into_subject(),
access_level: self.access_level,
source: self.source,
}
}
pub fn try_from_cloud_object_guest(guest: &CloudObjectGuest) -> anyhow::Result<Self> {
Ok(PersistedGuest {
subject: PersistedSubject::try_from_subject(&guest.subject)?,
access_level: guest.access_level,
source: guest.source,
})
}
}
impl PersistedSubject {
pub fn into_subject(self) -> Subject {
match self {
PersistedSubject::User { firebase_uid } => {
Subject::User(UserKind::Account(UserUid::new(&firebase_uid)))
}
PersistedSubject::PendingUser { email } => Subject::PendingUser { email },
PersistedSubject::Team { team_uid } => Subject::Team(TeamKind::Team { team_uid }),
}
}
/// Convert a [`Subject`] into a guest subject type. This is only supported for subjects that
/// may be direct object guests.
pub fn try_from_subject(subject: &Subject) -> anyhow::Result<Self> {
match subject {
Subject::User(user_kind) => match user_kind {
UserKind::Account(user_uid) => Ok(PersistedSubject::User {
firebase_uid: user_uid.to_string(),
}),
UserKind::SharedSessionParticipant(_) => {
// Shared sessions are transient, so we don't persist their ACLs to SQLite.
Err(anyhow!("Session-sharing participants not supported"))
}
},
Subject::PendingUser { email } => Ok(PersistedSubject::PendingUser {
email: email.clone(),
}),
Subject::Team(team_kind) => match team_kind {
TeamKind::Team { team_uid } => Ok(PersistedSubject::Team {
team_uid: *team_uid,
}),
TeamKind::SharedSessionTeam { .. } => {
// Shared sessions are transient, so we don't persist their ACLs to SQLite.
Err(anyhow!("Session-sharing teams not supported"))
}
},
// Link sharing is persisted separately in the schema.
Subject::AnyoneWithLink(_) => Err(anyhow!("Anyone with the link not supported")),
}
}
}