Skip to content
Extraits de code Groupes Projets
Valider 7755b39f rédigé par Kubat's avatar Kubat
Parcourir les fichiers

AMALIB: Add base things for the cache on client-side

parent 17586125
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
......@@ -30,6 +30,7 @@ version = "0.1.0"
dependencies = [
"commons",
"getset",
"hashbrown 0.13.2",
"lru",
"serde",
"smallstring",
......@@ -315,6 +316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
"serde",
]
[[package]]
......
......@@ -32,6 +32,7 @@ lazy_static = "^1"
thiserror = "^1"
smallvec = { version = "^1", default-features = false, features = ["serde"] }
hashbrown = { version = "^0.13", features = ["serde"] }
toml = { version = "^0.5", features = ["preserve_order"] }
serde = { version = "^1", default-features = false, features = [
......
......@@ -8,6 +8,7 @@ license.workspace = true
[dependencies]
serde.workspace = true
tokio.workspace = true
hashbrown.workspace = true
smallstring = { path = "../smallstring" }
commons = { path = "../commons" }
......
use crate::*;
use hashbrown::HashMap;
use lru::LruCache;
use serde::{Deserialize, Serialize};
use smallstring::SmallString;
use std::{collections::HashMap, num::NonZeroUsize};
/// Represent a global id for a kara, the pair (database, id).
#[derive(Debug, Deserialize, Serialize)]
pub struct KaraId {
pub repo: SmallString,
pub id: i64,
}
/// Represent what we want to override in a kara.
#[derive(Debug, Deserialize, Serialize)]
pub struct KaraOverride {}
/// A list of informations about a kara. This is the data from lektor. When
/// queried we patch it with the overrides given by the user.
#[derive(Debug)]
pub struct KaraInfo {}
#[allow(dead_code)]
#[derive(Debug)]
pub struct Playlist {
name: SmallString,
ctime: i64,
creator: SmallString,
content: Vec<i64>,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize, Serialize)]
#[serde(transparent)]
pub struct AmaDB {
/// Contains the content of the queue.
#[serde(skip)]
queue: Vec<i64>,
/// We cache the database so we don't have to make requests every time we
/// refresh the queue or a playlist.
databases: AmaDBCache,
}
use std::num::NonZeroUsize;
/// We cache objects locally so we don't have to always make requests to
/// lektord. When we get the update stored database event from mpv we clear the
......@@ -47,14 +11,13 @@ pub struct AmaDB {
/// it's the database, we clear everything.
#[allow(dead_code)]
#[derive(Debug, Deserialize, Serialize)]
struct AmaDBCache {
/// Cache requests to lektord.
#[serde(skip, default = "new_empty_kara_lru")]
lru_lektor: LruCache<i64, KaraInfo>,
/// Cache requests to lektord that where patched.
pub struct AmaDB {
/// Cache requests to lektord and patched karas. The first element is the
/// lektord entry, the second one is the patched version.
/// TODO: Find a structure that does COW to not duplicate too much
/// information in the patched version...
#[serde(skip, default = "new_empty_kara_lru")]
lru_patched: LruCache<i64, KaraInfo>,
karas: LruCache<i64, (KaraInfo, Option<KaraInfo>)>,
/// The playlists. We don't save them...
#[serde(skip, default = "new_empty_playlist_lru")]
......@@ -63,7 +26,7 @@ struct AmaDBCache {
/// The list of overrides, indexed by the local id of the kara.
overrides: HashMap<i64, KaraOverride>,
/// The conversion list for local id <-> repo id. Overrides are declared
/// The conversion list for `local id <-> repo id`. Overrides are declared
/// with the repo ids because it's the only thing that every client have in
/// common. We must adapt to the local id.
local_ids: HashMap<i64, KaraId>,
......@@ -71,7 +34,7 @@ struct AmaDBCache {
/// Create a new empty LRU cache. We set the value to the maximal count of
/// visible karas multiplied by a threeshold.
fn new_empty_kara_lru() -> LruCache<i64, KaraInfo> {
fn new_empty_kara_lru() -> LruCache<i64, (KaraInfo, Option<KaraInfo>)> {
use crate::constants::*;
LruCache::new(
NonZeroUsize::new(
......@@ -108,4 +71,32 @@ impl AmaDB {
pub fn clear_playlists_cache(&mut self) {
todo!()
}
/// Add an override to the override list. If a previous override is present
/// for the specified ID, we merge the new override into the previous one.
/// If the kara is present in the cache, we generate the patched version.
pub fn add_kara_override(&mut self, _id: KaraId, _override: KaraOverride) {
todo!()
}
/// Add a new kara into the lektord cache. If a patch is present for the
/// kara, it's patched and inserted into the patched cache.
pub fn add_kara(&mut self, _id: i64, _kara: KaraInfo) {
todo!()
}
/// Get the [KaraInfo] correspondig to the id. If the kara was patched with
/// a [KaraOverride], we return the patched version, overwise we return the
/// original version. If the [KaraInfo] was not found then we return [None].
pub fn kara(&mut self, id: i64) -> Option<&KaraInfo> {
match self.karas.get(&id)? {
(_, Some(info)) | (info, None) => Some(info),
}
}
/// Get the [Playlist] correspondif to the name. If the [Playlist] was not
/// found, we return [None].
pub fn playlist<'a>(&'a mut self, name: &SmallString) -> Option<&'a Playlist> {
self.playlists.get(name)
}
}
use crate::tags::*;
use getset::{CopyGetters, Getters};
use serde::{Deserialize, Serialize};
use smallstring::SmallString;
/// Represent a global id for a kara, the pair (database, id).
#[derive(Debug, Deserialize, Serialize, Getters, CopyGetters)]
pub struct KaraId {
#[getset(get = "pub")]
repo: SmallString,
#[getset(get_copy = "pub")]
id: i64,
}
/// Represent what we want to override in a kara.
#[derive(Debug, Deserialize, Serialize)]
pub struct KaraOverride {}
/// A list of informations about a kara. This is the data from lektor. When
/// queried we patch it with the overrides given by the user.
#[derive(Debug, Getters)]
#[getset(get = "pub")]
pub struct KaraInfo {
song_title: SmallString,
song_source: SmallString,
song_type: SmallString,
song_origin: SmallString,
languages: Vec<SmallString>,
kara_makers: Vec<SmallString>,
#[getset(skip)]
tags: SimpleTagSystem,
}
#[allow(dead_code)]
#[derive(Debug, Getters)]
#[getset(get = "pub")]
pub struct Playlist {
name: SmallString,
ctime: i64,
creator: SmallString,
content: Vec<i64>,
#[getset(skip)]
tags: SimpleTagSystem,
}
impl From<(&str, i64)> for KaraId {
fn from((repo, id): (&str, i64)) -> Self {
let repo = repo.into();
Self { repo, id }
}
}
impl From<(SmallString, i64)> for KaraId {
fn from((repo, id): (SmallString, i64)) -> Self {
Self { repo, id }
}
}
impl<'a> TaggedObject<'a> for Playlist {
type TagKeyType = <SimpleTagSystem as TaggedObject<'a>>::TagKeyType;
type TagValueType = <SimpleTagSystem as TaggedObject<'a>>::TagValueType;
type TagKeyIterator = <SimpleTagSystem as TaggedObject<'a>>::TagKeyIterator;
type TagValueIterator = <SimpleTagSystem as TaggedObject<'a>>::TagValueIterator;
fn add_tag(&mut self, tag: Self::TagKeyType, value: Option<Self::TagValueType>) {
self.tags.add_tag(tag, value)
}
fn delete_tag<S: AsRef<str>>(&mut self, tag: S) {
self.tags.delete_tag(tag)
}
fn clear_tags(&mut self) {
self.tags.clear()
}
fn tags(&'a self) -> Self::TagKeyIterator {
self.tags.tags()
}
fn iter_tag<S: AsRef<str>>(&'a self, tag: S) -> Option<Self::TagValueIterator> {
self.tags.iter_tag(tag)
}
}
impl<'a> TaggedObject<'a> for KaraInfo {
type TagKeyType = <SimpleTagSystem as TaggedObject<'a>>::TagKeyType;
type TagValueType = <SimpleTagSystem as TaggedObject<'a>>::TagValueType;
type TagKeyIterator = <SimpleTagSystem as TaggedObject<'a>>::TagKeyIterator;
type TagValueIterator = <SimpleTagSystem as TaggedObject<'a>>::TagValueIterator;
fn add_tag(&mut self, tag: Self::TagKeyType, value: Option<Self::TagValueType>) {
self.tags.add_tag(tag, value)
}
fn delete_tag<S: AsRef<str>>(&mut self, tag: S) {
self.tags.delete_tag(tag)
}
fn clear_tags(&mut self) {
self.tags.clear()
}
fn tags(&'a self) -> Self::TagKeyIterator {
self.tags.tags()
}
fn iter_tag<S: AsRef<str>>(&'a self, tag: S) -> Option<Self::TagValueIterator> {
self.tags.iter_tag(tag)
}
}
......@@ -4,17 +4,21 @@
//! communicate with the lektord server and elements to store and organise the
//! queried informations.
mod amacache;
mod cache;
mod connexion;
mod constants;
mod db_objects;
mod query;
mod response;
mod tags;
mod uri;
pub use amacache::*;
pub use cache::*;
pub use connexion::*;
pub use db_objects::*;
pub use query::*;
pub use response::*;
pub use tags::*;
pub use uri::*;
pub(crate) use commons::{log::*, *};
......
use hashbrown::HashMap;
use smallstring::SmallString;
/// Represent an object that can be tagged, e.g. a playlist or a kara. We
/// describe all the operations on such object here.
pub trait TaggedObject<'a> {
/// The type for the keys, e.g. the tag names.
type TagKeyType: AsRef<str> + 'a;
/// The type for the values of the tags. We enforce a string representation
/// for such tag.
type TagValueType: AsRef<str> + 'a;
/// The type of iterator for the list of keys.
type TagKeyIterator: Iterator<Item = &'a Self::TagKeyType>;
/// The type of iterator for the list the values of a tag.
type TagValueIterator: Iterator<Item = &'a Self::TagValueType>;
/// Add a tag to the object.
fn add_tag(&mut self, tag: Self::TagKeyType, value: Option<Self::TagValueType>);
/// Delete all values for a tag for the object.
fn delete_tag<S: AsRef<str>>(&mut self, tag: S);
/// Remove all tags from the object.
fn clear_tags(&mut self);
/// Get all the tags present on a kara.
fn tags(&'a self) -> Self::TagKeyIterator;
/// Iterate over the values of a tag.
fn iter_tag<S: AsRef<str>>(&'a self, tag: S) -> Option<Self::TagValueIterator>;
/// Has a tag with the specified name.
fn has_tag<S: AsRef<str>>(&'a self, tag: S) -> bool {
self.tags().any(|t| t.as_ref() == tag.as_ref())
}
/// Contains the (tag, value) pair.
fn has_tag_value<S: AsRef<str>>(&'a self, tag: S, value: S) -> bool {
self.iter_tag(tag)
.map(|mut values| values.any(|v| v.as_ref() == value.as_ref()))
.unwrap_or_default()
}
}
/// A simple tag system. Any object can reuse this type or implement the
/// [TaggedObject] trait itself. To reuse this type, you can forward calls to
/// the simple tag field when implementing the trait.
pub(crate) type SimpleTagSystem = HashMap<SmallString, Vec<SmallString>>;
impl<'a> TaggedObject<'a> for SimpleTagSystem {
type TagKeyType = SmallString;
type TagValueType = SmallString;
type TagKeyIterator = hashbrown::hash_map::Keys<'a, SmallString, Vec<SmallString>>;
type TagValueIterator = std::slice::Iter<'a, SmallString>;
fn tags(&'a self) -> Self::TagKeyIterator {
self.keys()
}
fn iter_tag<S: AsRef<str>>(&'a self, tag: S) -> Option<Self::TagValueIterator> {
self.get(tag.as_ref()).map(|tags| tags.iter())
}
fn add_tag(&mut self, tag: SmallString, value: Option<SmallString>) {
match self.get_mut(&tag) {
Some(values) => values.extend(value),
None => {
self.insert(tag, value.into_iter().collect());
}
}
}
fn delete_tag<S: AsRef<str>>(&mut self, tag: S) {
if let Some(values) = self.get_mut(tag.as_ref()) {
values.clear()
}
}
fn clear_tags(&mut self) {
self.clear()
}
fn has_tag<S: AsRef<str>>(&'a self, tag: S) -> bool {
self.contains_key(tag.as_ref())
}
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter