use std::collections::HashMap;
use std::time::Instant;
use crate::protocol::{ScriptEvent, ScriptEventData};
use super::PluginHost;
impl PluginHost {
pub fn overlays(&self) -> &HashMap<String, crate::protocol::PluginOverlay> {
&self.overlays
}
pub fn focused_overlay(&self) -> Option<&str> {
self.focused_overlay.as_deref()
}
pub fn focus_overlay(&mut self, plugin_id: &str) {
self.focused_overlay = self
.overlays
.get(plugin_id)
.filter(|o| o.interactive)
.map(|_| plugin_id.to_string());
}
pub fn unfocus_overlay(&mut self) {
self.focused_overlay = None;
}
pub(super) fn clear_focus_if(&mut self, plugin_id: &str) {
if self.focused_overlay.as_deref() == Some(plugin_id) {
self.focused_overlay = None;
}
}
pub fn send_overlay_event(
&mut self,
plugin_id: &str,
widget_id: &str,
event: crate::protocol::OverlayWidgetEvent,
) -> bool {
let Some(&sid) = self.overlay_running.get(plugin_id) else {
return false;
};
let Some(overlay) = self.overlays.get(plugin_id) else {
return false;
};
let script_event = ScriptEvent {
kind: crate::protocol::OVERLAY_EVENT_KIND.to_string(),
data: ScriptEventData::OverlayEvent {
overlay: overlay.id.clone(),
widget: widget_id.to_string(),
event,
},
};
match self.manager.send_event(sid, &script_event) {
Ok(()) => {
self.overlay_events_dispatched += 1;
true
}
Err(error) => {
if self.warned_event_delivery.should_warn(plugin_id) {
log::warn!(
"failed to deliver overlay event to plugin '{}': {}",
plugin_id,
error
);
}
false
}
}
}
pub fn overlay_events_dispatched_count(&self) -> u64 {
self.overlay_events_dispatched
}
const OVERLAY_UPDATE_WINDOW_SECS: u64 = 1;
const OVERLAY_UPDATE_MAX_PER_WINDOW: usize = 30;
pub(super) fn overlay_update_permitted(&mut self, id: &str, now: Instant) -> bool {
let times = self.overlay_update_times.entry(id.to_string()).or_default();
times.retain(|t| now.duration_since(*t).as_secs() < Self::OVERLAY_UPDATE_WINDOW_SECS);
if times.len() >= Self::OVERLAY_UPDATE_MAX_PER_WINDOW {
if self
.warned_event_delivery
.should_warn(&format!("{id}/overlay-rate"))
{
log::warn!(
"plugin '{id}' is pushing SetOverlay faster than {} per second; \
dropping the excess (update-rate clamp)",
Self::OVERLAY_UPDATE_MAX_PER_WINDOW
);
}
return false;
}
times.push(now);
true
}
}