use std::{
collections::{BTreeSet, HashMap},
sync::Arc,
time::{Duration, Instant},
};
use gled_model::collection::Collections as AssetCollections;
use kanal::{Receiver, unbounded};
use super::{
ClientId, ClientInput, ClientState, EngineConnector, EngineEvent, EngineState,
session::{EngineInput, Session},
};
pub fn fake_engine() -> (EngineConnector, FakeEngine) {
let (inputs, receiver) = unbounded();
(
EngineConnector {
inputs,
next_id: Arc::default(),
},
FakeEngine {
inputs: receiver,
sessions: HashMap::new(),
assets: Arc::default(),
preview: None,
},
)
}
#[derive(Debug)]
pub struct FakeEngine {
inputs: Receiver<EngineInput>,
sessions: HashMap<ClientId, Session>,
assets: Arc<AssetCollections>,
preview: Option<Arc<Vec<u8>>>,
}
impl FakeEngine {
pub fn next_input(&mut self, timeout: Duration) -> Option<(ClientId, ClientInput)> {
let deadline = Instant::now() + timeout;
loop {
let left = deadline.saturating_duration_since(Instant::now());
let input = if left.is_zero() {
self.inputs.try_recv().ok().flatten()
} else {
self.inputs.recv_timeout(left).ok()
};
match input? {
EngineInput::Connect { id, state, events } => {
self.sessions.insert(
id,
Session {
state,
events,
applied_sequence: 0,
keys: BTreeSet::new(),
},
);
}
EngineInput::Client { id, input } => {
if let Some(session) = self.sessions.get_mut(&id) {
match &input {
ClientInput::Action { sequence, .. } => {
session.applied_sequence = session.applied_sequence.max(*sequence);
}
ClientInput::Keys(keys) => session.keys = keys.clone(),
ClientInput::SetBeatsPerMinute(_)
| ClientInput::SaveAsset(_)
| ClientInput::DeleteAsset(_)
| ClientInput::Storage(_)
| ClientInput::SetServerSettings(_)
| ClientInput::HoverOutputRouting(_)
| ClientInput::WatchDevices(_)
| ClientInput::WatchMidi(_)
| ClientInput::MidiLearning(_)
| ClientInput::MidiTest(_)
| ClientInput::WatchSoundTriggers(_)
| ClientInput::SavePicture { .. }
| ClientInput::RequestPicture(_) => {}
}
}
return Some((id, input));
}
EngineInput::Disconnect(id) => {
self.sessions.remove(&id);
}
}
}
}
pub fn poll_connections(&mut self) {
while let Some(input) = self.next_input(Duration::ZERO) {
drop(input);
}
}
pub fn clients(&self) -> BTreeSet<ClientId> {
self.sessions.keys().copied().collect()
}
pub fn keys(&self, id: ClientId) -> BTreeSet<gled_model::input::key_code::KeyCode> {
self.sessions
.get(&id)
.map(|session| session.keys.clone())
.unwrap_or_default()
}
pub fn set_assets(&mut self, assets: AssetCollections) {
self.assets = Arc::new(assets);
}
pub fn set_preview(&mut self, output: Vec<u8>) {
self.preview = Some(Arc::new(output));
}
pub fn publish(&self, state: EngineState) {
let shared = Arc::new(state);
for session in self.sessions.values() {
let _ = session.state.try_send(ClientState {
shared: shared.clone(),
applied_sequence: session.applied_sequence,
assets: self.assets.clone(),
preview: self.preview.clone(),
sound: Arc::default(),
input_log: Arc::default(),
midi_log: Arc::default(),
learn_log: Arc::default(),
});
}
}
pub fn send_event(&self, event: EngineEvent) {
for session in self.sessions.values() {
let _ = session.events.send(event.clone());
}
}
}