|
1 | 1 | use async_graphql::futures_util::future::ready; |
2 | 2 | use async_graphql::futures_util::{Stream, StreamExt, stream}; |
3 | | -use async_graphql::{Context, EmptyMutation, Enum, ID, Object, Schema, Subscription, Union}; |
| 3 | +use async_graphql::parser::types::{FragmentDefinition, Selection, SelectionSet}; |
| 4 | +use async_graphql::{ |
| 5 | + Context, EmptyMutation, Enum, ID, Name, Object, Positioned, Schema, Subscription, Union, |
| 6 | +}; |
4 | 7 | use std::collections::{HashMap, HashSet}; |
5 | 8 | use std::sync::{Arc, RwLock}; |
6 | 9 | use tokio::sync::broadcast::Sender; |
@@ -348,6 +351,91 @@ impl RiverSnapshot { |
348 | 351 | } |
349 | 352 | } |
350 | 353 |
|
| 354 | +fn collect_requested_event_types( |
| 355 | + fragments: &HashMap<Name, Positioned<FragmentDefinition>>, |
| 356 | + selection_set: &SelectionSet, |
| 357 | + out: &mut HashSet<RiverEventType>, |
| 358 | + visited: &mut HashSet<Name>, |
| 359 | +) { |
| 360 | + for selection in &selection_set.items { |
| 361 | + match &selection.node { |
| 362 | + Selection::Field(field) => { |
| 363 | + collect_requested_event_types( |
| 364 | + fragments, |
| 365 | + &field.node.selection_set.node, |
| 366 | + out, |
| 367 | + visited, |
| 368 | + ); |
| 369 | + } |
| 370 | + Selection::InlineFragment(fragment) => { |
| 371 | + if let Some(condition) = &fragment.node.type_condition { |
| 372 | + for ty in event_types_for_name(condition.node.on.node.as_str()) { |
| 373 | + out.insert(ty); |
| 374 | + } |
| 375 | + } |
| 376 | + collect_requested_event_types( |
| 377 | + fragments, |
| 378 | + &fragment.node.selection_set.node, |
| 379 | + out, |
| 380 | + visited, |
| 381 | + ); |
| 382 | + } |
| 383 | + Selection::FragmentSpread(spread) => { |
| 384 | + let name = spread.node.fragment_name.node.clone(); |
| 385 | + if !visited.insert(name.clone()) { |
| 386 | + continue; |
| 387 | + } |
| 388 | + if let Some(fragment) = fragments.get(&name) { |
| 389 | + for ty in |
| 390 | + event_types_for_name(fragment.node.type_condition.node.on.node.as_str()) |
| 391 | + { |
| 392 | + out.insert(ty); |
| 393 | + } |
| 394 | + collect_requested_event_types( |
| 395 | + fragments, |
| 396 | + &fragment.node.selection_set.node, |
| 397 | + out, |
| 398 | + visited, |
| 399 | + ); |
| 400 | + } |
| 401 | + } |
| 402 | + } |
| 403 | + } |
| 404 | +} |
| 405 | + |
| 406 | +fn requested_event_types(ctx: &Context<'_>) -> Option<HashSet<RiverEventType>> { |
| 407 | + let selection_set = &ctx.item.node.selection_set.node; |
| 408 | + if selection_set.items.is_empty() { |
| 409 | + return None; |
| 410 | + } |
| 411 | + let mut out = HashSet::new(); |
| 412 | + let mut visited = HashSet::new(); |
| 413 | + collect_requested_event_types( |
| 414 | + &ctx.query_env.fragments, |
| 415 | + selection_set, |
| 416 | + &mut out, |
| 417 | + &mut visited, |
| 418 | + ); |
| 419 | + if out.is_empty() { None } else { Some(out) } |
| 420 | +} |
| 421 | + |
| 422 | +fn event_types_for_name(name: &str) -> Vec<RiverEventType> { |
| 423 | + match name { |
| 424 | + "OutputFocusedTags" => vec![RiverEventType::OutputFocusedTags], |
| 425 | + "OutputViewTags" => vec![RiverEventType::OutputViewTags], |
| 426 | + "OutputUrgentTags" => vec![RiverEventType::OutputUrgentTags], |
| 427 | + "OutputLayoutName" => vec![ |
| 428 | + RiverEventType::OutputLayoutName, |
| 429 | + RiverEventType::OutputLayoutNameClear, |
| 430 | + ], |
| 431 | + "SeatFocusedOutput" => vec![RiverEventType::SeatFocusedOutput], |
| 432 | + "SeatUnfocusedOutput" => vec![RiverEventType::SeatUnfocusedOutput], |
| 433 | + "SeatFocusedView" => vec![RiverEventType::SeatFocusedView], |
| 434 | + "SeatMode" => vec![RiverEventType::SeatMode], |
| 435 | + _ => Vec::new(), |
| 436 | + } |
| 437 | +} |
| 438 | + |
351 | 439 | pub type RiverStateHandle = Arc<RwLock<RiverSnapshot>>; |
352 | 440 |
|
353 | 441 | pub fn new_river_state() -> RiverStateHandle { |
@@ -734,7 +822,9 @@ impl SubscriptionRoot { |
734 | 822 | let sender = ctx.data_unchecked::<Sender<river::Event>>().clone(); |
735 | 823 | let rx = sender.subscribe(); |
736 | 824 | let include_lists = tag_list.unwrap_or(false); |
737 | | - let tset = types.map(|v| v.into_iter().collect::<HashSet<_>>()); |
| 825 | + let tset = types |
| 826 | + .map(|v| v.into_iter().collect::<HashSet<_>>()) |
| 827 | + .or_else(|| requested_event_types(ctx)); |
738 | 828 | let initial_events = { |
739 | 829 | let handle = ctx.data_unchecked::<RiverStateHandle>(); |
740 | 830 | match handle.read() { |
@@ -770,7 +860,9 @@ impl SubscriptionRoot { |
770 | 860 | let sender = ctx.data_unchecked::<Sender<river::Event>>().clone(); |
771 | 861 | let rx = sender.subscribe(); |
772 | 862 | let include_lists = tag_list.unwrap_or(false); |
773 | | - let tset = types.map(|v| v.into_iter().collect::<HashSet<_>>()); |
| 863 | + let tset = types |
| 864 | + .map(|v| v.into_iter().collect::<HashSet<_>>()) |
| 865 | + .or_else(|| requested_event_types(ctx)); |
774 | 866 | let target_output = output_name; |
775 | 867 | let initial_events = { |
776 | 868 | let handle = ctx.data_unchecked::<RiverStateHandle>(); |
|
0 commit comments