use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use everruns_contracts::error::Result;
use everruns_contracts::typed_id::{MessageId, SessionId};
use super::{AcceptedTurnInput, InProcessRuntime};
use crate::event_emitter::EventEmitter;
use crate::events::{EventContext, EventRequest, InputMessageData};
#[derive(Clone, Debug)]
pub struct TurnSteering {
state: Arc<Mutex<TurnSteeringState>>,
}
#[derive(Debug)]
pub enum TurnSteeringPushError {
Closed(Box<AcceptedTurnInput>),
Full(Box<AcceptedTurnInput>),
}
const TURN_STEERING_CAPACITY: usize = 256;
#[derive(Debug, Default)]
struct TurnSteeringState {
open: bool,
inputs: VecDeque<AcceptedTurnInput>,
}
impl TurnSteering {
pub fn new() -> Self {
Self {
state: Arc::new(Mutex::new(TurnSteeringState {
open: true,
inputs: VecDeque::new(),
})),
}
}
pub fn try_push(
&self,
input: AcceptedTurnInput,
) -> std::result::Result<(), TurnSteeringPushError> {
let mut state = self.state.lock().expect("turn steering lock poisoned");
if !state.open {
return Err(TurnSteeringPushError::Closed(Box::new(input)));
}
if state.inputs.len() >= TURN_STEERING_CAPACITY {
return Err(TurnSteeringPushError::Full(Box::new(input)));
}
state.inputs.push_back(input);
Ok(())
}
pub fn drain(&self) -> Vec<AcceptedTurnInput> {
let mut state = self.state.lock().expect("turn steering lock poisoned");
state.inputs.drain(..).collect()
}
pub fn drain_or_close(&self) -> Vec<AcceptedTurnInput> {
let mut state = self.state.lock().expect("turn steering lock poisoned");
if state.inputs.is_empty() {
state.open = false;
return vec![];
}
state.inputs.drain(..).collect()
}
pub fn close(&self) {
self.state.lock().expect("turn steering lock poisoned").open = false;
}
pub fn close_and_drain(&self) -> Vec<AcceptedTurnInput> {
let mut state = self.state.lock().expect("turn steering lock poisoned");
state.open = false;
state.inputs.drain(..).collect()
}
}
impl Default for TurnSteering {
fn default() -> Self {
Self::new()
}
}
impl InProcessRuntime {
pub async fn persist_accepted_input(
&self,
session_id: SessionId,
input: AcceptedTurnInput,
) -> Result<MessageId> {
let message = input.into_message();
let message_id = message.id;
self.event_emitter
.emit(EventRequest::new(
session_id,
EventContext::empty(),
InputMessageData::new(message),
))
.await?;
Ok(message_id)
}
}