gled_core/engine/
session.rs1use std::{
7 collections::BTreeSet,
8 sync::{
9 Arc,
10 atomic::{AtomicU64, Ordering::Relaxed},
11 },
12};
13
14use kanal::{Receiver, Sender, bounded, unbounded};
15use tracing::warn;
16
17use super::{ClientInput, EngineEvent, EngineState, InputLog, LearnLog, MidiLog, SoundSnapshot};
18use crate::{action::UiAction, input::key_code::KeyCode, pipeline::extract_output::PreviewOutput};
19use gled_model::collection::Collections as AssetCollections;
20
21pub type ClientId = u64;
23
24#[derive(Debug)]
26pub(super) enum EngineInput {
27 Connect {
28 id: ClientId,
29 state: Sender<ClientState>,
30 events: Sender<EngineEvent>,
31 },
32 Client {
33 id: ClientId,
34 input: ClientInput,
35 },
36 Disconnect(ClientId),
37}
38
39#[derive(Debug, Clone)]
42pub struct ClientState {
43 pub(crate) shared: Arc<EngineState>,
44 pub(crate) applied_sequence: u64,
46 pub(crate) assets: Arc<AssetCollections>,
48 pub(crate) preview: Option<PreviewOutput>,
50 pub(crate) sound: Arc<SoundSnapshot>,
52 pub(crate) input_log: Arc<InputLog>,
54 pub(crate) midi_log: Arc<MidiLog>,
56 pub(crate) learn_log: Arc<LearnLog>,
58}
59
60#[derive(Debug)]
62pub(super) struct Session {
63 pub(super) state: Sender<ClientState>,
64 pub(super) events: Sender<EngineEvent>,
65 pub(super) applied_sequence: u64,
66 pub(super) keys: BTreeSet<KeyCode>,
67}
68
69#[derive(Debug, Clone)]
72pub struct EngineConnector {
73 pub(super) inputs: Sender<EngineInput>,
74 pub(super) next_id: Arc<AtomicU64>,
75}
76
77impl EngineConnector {
78 pub fn connect(&self) -> ClientConnection {
80 let id = self.next_id.fetch_add(1, Relaxed);
81 let (state_sender, state) = bounded(4);
83 let (event_sender, events) = unbounded();
84 if let Err(err) = self.inputs.send(EngineInput::Connect {
85 id,
86 state: state_sender,
87 events: event_sender,
88 }) {
89 warn!("The engine has stopped: {err}");
90 }
91 ClientConnection {
92 id,
93 inputs: self.inputs.clone(),
94 sequence: Arc::default(),
95 state,
96 events,
97 }
98 }
99}
100
101#[derive(Debug)]
103pub struct ClientConnection {
104 id: ClientId,
105 inputs: Sender<EngineInput>,
106 sequence: Arc<AtomicU64>,
108 state: Receiver<ClientState>,
109 events: Receiver<EngineEvent>,
110}
111
112impl ClientConnection {
113 pub fn id(&self) -> ClientId {
114 self.id
115 }
116
117 pub fn send_numbered_action(&self, sequence: u64, action: UiAction) {
120 self.sequence.fetch_max(sequence, Relaxed);
121 self.send(ClientInput::Action { sequence, action });
122 }
123
124 pub fn send(&self, input: ClientInput) {
126 if let Err(err) = self.inputs.send(EngineInput::Client { id: self.id, input }) {
127 warn!("The engine has stopped: {err}");
128 }
129 }
130
131 pub fn latest_state(&self) -> Option<ClientState> {
133 let mut latest = None;
134 while let Ok(Some(state)) = self.state.try_recv() {
135 latest = Some(state);
136 }
137 latest
138 }
139
140 pub fn state_receiver(&self) -> &Receiver<ClientState> {
142 &self.state
143 }
144
145 pub fn event_receiver(&self) -> &Receiver<EngineEvent> {
147 &self.events
148 }
149
150 pub fn next_event(&self) -> Option<EngineEvent> {
152 self.events.try_recv().ok().flatten()
153 }
154}
155
156impl Drop for ClientConnection {
157 fn drop(&mut self) {
158 let _ = self.inputs.send(EngineInput::Disconnect(self.id));
160 }
161}