use std::{collections::HashSet, sync::Arc};
use marshal_entities::{
GetAllSessionNicknames, GetAllSessions, Session, SessionNickname, SessionNicknameId, nickname,
};
use myko::{
command::{CommandContext, CommandError, CommandHandler},
myko_command,
prelude::myko_saga,
saga::{SagaContext, SagaHandler},
wire::{MEvent, MEventType},
};
pub fn link() {}
#[myko_saga]
pub struct AssignNicknameSaga;
impl SagaHandler for AssignNicknameSaga {
type EventItem = Session;
type Command = AssignNickname;
const EVENT_TYPE: MEventType = MEventType::SET;
fn handle(session: Session, _event: MEvent, _ctx: Arc<SagaContext>) -> Option<Self::Command> {
Some(AssignNickname {
session_id: session.id.0.as_ref().to_string(),
})
}
}
#[myko_command]
pub struct AssignNickname {
pub session_id: String,
}
impl CommandHandler for AssignNickname {
fn execute(self, ctx: CommandContext) -> Result<(), CommandError> {
let sessions: Vec<Arc<Session>> = ctx.exec_query(GetAllSessions {})?;
if !sessions
.iter()
.any(|s| s.id.0.as_ref() == self.session_id.as_str())
{
return Ok(());
}
let assigned: Vec<Arc<SessionNickname>> = ctx.exec_query(GetAllSessionNicknames {})?;
if assigned
.iter()
.any(|n| n.id.0.as_ref() == self.session_id.as_str())
{
return Ok(());
}
let taken: HashSet<&str> = assigned.iter().map(|n| n.nickname.as_str()).collect();
let mut handle = nickname(&self.session_id);
let mut salt = 0u32;
while taken.contains(handle.as_str()) {
salt += 1;
handle = nickname(&format!("{}#{salt}", self.session_id));
}
ctx.emit_set(&SessionNickname {
id: SessionNicknameId(Arc::from(self.session_id.as_str())),
nickname: handle,
})?;
Ok(())
}
}