forked from lavina/lavina
1
0
Fork 0

initial dialogs impl

This commit is contained in:
Nikita Vilunov 2024-04-21 21:01:29 +02:00
parent ddb348bee9
commit 662aae5075
3 changed files with 98 additions and 1 deletions

View File

@ -0,0 +1,14 @@
create table dialogs(
participant_1 integer not null,
participant_2 integer not null,
created_at timestamp not null,
message_count integer not null default 0,
primary key (participant_1, participant_2)
);
create table dialog_messages(
dialog_id integer not null,
id integer not null, -- unique per dialog, sequential in one dialog
content string not null,
primary key (dialog_id, id)
);

View File

@ -0,0 +1,75 @@
//! Domain of dialogs conversations between two participants.
//!
//! Dialogs are different from rooms in that they are always between two participants.
//! There are no
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock as AsyncRwLock;
use crate::player::PlayerId;
use crate::repo::Storage;
/// Id of a conversation between two players.
///
/// Dialogs are identified by the pair of participants' ids. The order of ids does not matter.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct DialogId(PlayerId, PlayerId);
impl DialogId {
pub fn new(a: PlayerId, b: PlayerId) -> DialogId {
if a.as_inner() < b.as_inner() {
DialogId(a, b)
} else {
DialogId(b, a)
}
}
pub fn as_inner(&self) -> (&PlayerId, &PlayerId) {
(&self.0, &self.1)
}
pub fn into_inner(self) -> (PlayerId, PlayerId) {
(self.0, self.1)
}
}
struct Dialog {
storage_id: u32,
id: DialogId,
message_count: u32,
}
struct DialogRegistryInner {
dialogs: HashMap<DialogId, AsyncRwLock<Dialog>>,
storage: Storage,
}
#[derive(Clone)]
pub struct DialogRegistry(Arc<AsyncRwLock<DialogRegistryInner>>);
impl DialogRegistry {
pub fn new(storage: Storage) -> DialogRegistry {
DialogRegistry(Arc::new(AsyncRwLock::new(DialogRegistryInner {
dialogs: HashMap::new(),
storage,
})))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dialog_id_new() {
let a = PlayerId::from("a").unwrap();
let b = PlayerId::from("b").unwrap();
let id1 = DialogId::new(a.clone(), b.clone());
let id2 = DialogId::new(a.clone(), b.clone());
// Dialog ids are invariant with respect to the order of participants
assert_eq!(id1, id2);
assert_eq!(id1.as_inner(), (&a, &b));
assert_eq!(id2.as_inner(), (&a, &b));
}
}

View File

@ -2,10 +2,12 @@
use anyhow::Result; use anyhow::Result;
use prometheus::Registry as MetricsRegistry; use prometheus::Registry as MetricsRegistry;
use crate::dialog::DialogRegistry;
use crate::player::PlayerRegistry; use crate::player::PlayerRegistry;
use crate::repo::Storage; use crate::repo::Storage;
use crate::room::RoomRegistry; use crate::room::RoomRegistry;
pub mod dialog;
pub mod player; pub mod player;
pub mod prelude; pub mod prelude;
pub mod repo; pub mod repo;
@ -18,6 +20,7 @@ mod table;
pub struct LavinaCore { pub struct LavinaCore {
pub players: PlayerRegistry, pub players: PlayerRegistry,
pub rooms: RoomRegistry, pub rooms: RoomRegistry,
pub dialogs: DialogRegistry,
} }
impl LavinaCore { impl LavinaCore {
@ -25,7 +28,12 @@ impl LavinaCore {
// TODO shutdown all services in reverse order on error // TODO shutdown all services in reverse order on error
let rooms = RoomRegistry::new(&mut metrics, storage.clone())?; let rooms = RoomRegistry::new(&mut metrics, storage.clone())?;
let players = PlayerRegistry::empty(rooms.clone(), storage.clone(), &mut metrics)?; let players = PlayerRegistry::empty(rooms.clone(), storage.clone(), &mut metrics)?;
Ok(LavinaCore { players, rooms }) let dialogs = DialogRegistry::new(storage.clone());
Ok(LavinaCore {
players,
rooms,
dialogs,
})
} }
pub async fn shutdown(mut self) -> Result<()> { pub async fn shutdown(mut self) -> Result<()> {