1use crate::app::strategies::base::{create_app_strategy, AppStrategyPtr};
6use crate::app::strategies::framebuffer::DisplayId;
7use crate::drawing::DisplayRotation;
8use crate::geometry::Size;
9use crate::input::{DeviceId, UserInputMessage};
10use crate::message::Message;
11use crate::scene::facets::FacetId;
12use crate::view::strategies::base::ViewStrategyParams;
13use crate::view::{ViewAssistantPtr, ViewController, ViewKey};
14use crate::IdGenerator2;
15use anyhow::{bail, format_err, Context as _, Error};
16use fidl_fuchsia_hardware_display::{CoordinatorListenerRequest, VirtconMode};
17use fidl_fuchsia_input_report as hid_input_report;
18use fuchsia_async::{self as fasync, DurationExt, Timer};
19use fuchsia_component::{self as component};
20use fuchsia_trace::duration;
21
22use futures::channel::mpsc::{unbounded, UnboundedSender};
23use futures::future::{Either, Future};
24use futures::StreamExt;
25use once_cell::sync::OnceCell;
26use serde::Deserialize;
27use std::any::Any;
28use std::collections::BTreeMap;
29use std::fmt::Debug;
30use std::fs;
31use std::path::PathBuf;
32use std::pin::{pin, Pin};
33
34pub(crate) mod strategies;
35
36pub type LocalBoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
38
39fn virtcon_mode_from_str(mode_str: &str) -> Result<Option<VirtconMode>, Error> {
40 match mode_str {
41 "forced" => Ok(Some(VirtconMode::Forced)),
42 "fallback" => Ok(Some(VirtconMode::Fallback)),
43 _ => Err(format_err!("Invalid VirtconMode {}", mode_str)),
44 }
45}
46
47fn deserialize_virtcon_mode<'de, D>(deserializer: D) -> Result<Option<VirtconMode>, D::Error>
48where
49 D: serde::Deserializer<'de>,
50{
51 let str = String::deserialize(deserializer)?;
52 virtcon_mode_from_str(&str).map_err(serde::de::Error::custom)
53}
54
55const fn keyboard_autorepeat_default() -> bool {
56 true
57}
58
59fn duration_from_millis(time_in_millis: u64) -> Result<std::time::Duration, Error> {
60 Ok(std::time::Duration::from_millis(time_in_millis))
61}
62
63fn deserialize_millis<'de, D>(deserializer: D) -> Result<std::time::Duration, D::Error>
64where
65 D: serde::Deserializer<'de>,
66{
67 let ms = u64::deserialize(deserializer)?;
68 duration_from_millis(ms).map_err(serde::de::Error::custom)
69}
70
71const fn keyboard_autorepeat_slow_interval_default() -> std::time::Duration {
72 const KEYBOARD_AUTOREPEAT_SLOW_INTERVAL: std::time::Duration =
73 std::time::Duration::from_millis(250);
74 KEYBOARD_AUTOREPEAT_SLOW_INTERVAL
75}
76
77const fn keyboard_autorepeat_fast_interval_default() -> std::time::Duration {
78 const KEYBOARD_AUTOREPEAT_FAST_INTERVAL: std::time::Duration =
79 std::time::Duration::from_millis(50);
80 KEYBOARD_AUTOREPEAT_FAST_INTERVAL
81}
82
83const fn display_resource_release_delay_default() -> std::time::Duration {
84 const DISPLAY_RESOURCE_RELEASE_DELAY_DEFAULT: std::time::Duration =
85 std::time::Duration::from_secs(5);
86 DISPLAY_RESOURCE_RELEASE_DELAY_DEFAULT
87}
88
89const fn startup_delay_default() -> std::time::Duration {
90 const STARTUP_DELAY_DEFAULT: std::time::Duration = std::time::Duration::from_secs(0);
91 STARTUP_DELAY_DEFAULT
92}
93
94#[derive(Debug, Deserialize)]
97#[serde(rename_all = "lowercase")]
98pub enum ViewMode {
99 Auto,
101 Hosted,
103 Direct,
105}
106
107impl Default for ViewMode {
108 fn default() -> Self {
109 Self::Auto
110 }
111}
112
113#[derive(Debug, Deserialize)]
115pub struct Config {
116 #[serde(default = "keyboard_autorepeat_default")]
117 pub keyboard_autorepeat: bool,
120 #[serde(
121 default = "keyboard_autorepeat_slow_interval_default",
122 deserialize_with = "deserialize_millis"
123 )]
124 pub keyboard_autorepeat_slow_interval: std::time::Duration,
127 #[serde(
128 default = "keyboard_autorepeat_fast_interval_default",
129 deserialize_with = "deserialize_millis"
130 )]
131 pub keyboard_autorepeat_fast_interval: std::time::Duration,
134 #[serde(default)]
135 pub use_spinel: bool,
137 #[serde(default, deserialize_with = "deserialize_virtcon_mode")]
139 pub virtcon_mode: Option<VirtconMode>,
140 #[serde(default)]
142 pub view_mode: ViewMode,
143 #[serde(default)]
144 pub display_rotation: DisplayRotation,
146 #[serde(default)]
147 pub keymap_name: Option<String>,
150 #[serde(
151 default = "display_resource_release_delay_default",
152 deserialize_with = "deserialize_millis"
153 )]
154 pub display_resource_release_delay: std::time::Duration,
159 #[serde(default)]
160 pub buffer_count: Option<usize>,
165 #[serde(default)]
166 pub input: bool,
168 #[serde(default)]
169 pub needs_blending: bool,
171 #[serde(default = "startup_delay_default", deserialize_with = "deserialize_millis")]
172 pub startup_delay: std::time::Duration,
174}
175
176impl Config {
177 pub(crate) fn get() -> &'static Config {
178 CONFIG.get_or_init(|| Config::default())
181 }
182}
183
184impl Default for Config {
185 fn default() -> Self {
186 Self {
187 keyboard_autorepeat: keyboard_autorepeat_default(),
188 keyboard_autorepeat_slow_interval: keyboard_autorepeat_slow_interval_default(),
189 keyboard_autorepeat_fast_interval: keyboard_autorepeat_fast_interval_default(),
190 use_spinel: false,
191 virtcon_mode: None,
192 view_mode: ViewMode::default(),
193 display_rotation: DisplayRotation::Deg0,
194 keymap_name: None,
195 display_resource_release_delay: display_resource_release_delay_default(),
196 buffer_count: None,
197 input: true,
198 needs_blending: false,
199 startup_delay: Default::default(),
200 }
201 }
202}
203
204pub(crate) static CONFIG: OnceCell<Config> = OnceCell::new();
205
206pub(crate) type InternalSender = UnboundedSender<MessageInternal>;
207
208#[derive(Debug, Clone, Copy)]
210pub enum MessageTarget {
211 Facet(ViewKey, FacetId),
213 View(ViewKey),
215 Application,
217}
218
219pub type CreateViewOptions = Box<dyn Any>;
221
222#[derive(Clone)]
225pub struct AppSender {
226 sender: InternalSender,
227}
228
229impl AppSender {
230 pub fn queue_message(&self, target: MessageTarget, message: Message) {
232 self.sender
233 .unbounded_send(MessageInternal::TargetedMessage(target, message))
234 .expect("AppSender::queue_message - unbounded_send");
235 }
236
237 pub fn request_render(&self, target: ViewKey) {
239 self.sender
240 .unbounded_send(MessageInternal::RequestRender(target))
241 .expect("AppSender::request_render - unbounded_send");
242 }
243
244 pub fn set_virtcon_mode(&self, virtcon_mode: VirtconMode) {
247 self.sender
248 .unbounded_send(MessageInternal::SetVirtconMode(virtcon_mode))
249 .expect("AppSender::set_virtcon_mode - unbounded_send");
250 }
251
252 pub fn create_additional_view(&self, options: Option<CreateViewOptions>) -> ViewKey {
254 let view_key = IdGenerator2::<ViewKey>::next().expect("view_key");
255 self.sender
256 .unbounded_send(MessageInternal::CreateAdditionalView(view_key, options))
257 .expect("AppSender::create_additional_view - unbounded_send");
258 view_key
259 }
260
261 pub fn close_additional_view(&self, view_key: ViewKey) {
264 self.sender
265 .unbounded_send(MessageInternal::CloseAdditionalView(view_key))
266 .expect("AppSender::close_additional_view - unbounded_send");
267 }
268
269 pub fn create_cross_thread_sender<T: 'static + Send>(
277 &self,
278 target: MessageTarget,
279 ) -> UnboundedSender<T> {
280 let (sender, mut receiver) = unbounded::<T>();
281 let app_sender = self.sender.clone();
282 let f = async move {
283 while let Some(message) = receiver.next().await {
284 app_sender
285 .unbounded_send(MessageInternal::TargetedMessage(target, Box::new(message)))
286 .expect("unbounded_send");
287 }
288 };
289 fasync::Task::local(f).detach();
292 sender
293 }
294
295 pub fn new_for_testing_purposes_only() -> AppSender {
297 let (internal_sender, _) = unbounded::<MessageInternal>();
298 AppSender { sender: internal_sender }
299 }
300}
301
302fn make_app_assistant_fut<T: AppAssistant + Default + 'static>(
303 _: &AppSender,
304) -> LocalBoxFuture<'_, Result<AppAssistantPtr, Error>> {
305 let f = async move {
306 let assistant = Box::new(T::default());
307 Ok::<AppAssistantPtr, Error>(assistant)
308 };
309 Box::pin(f)
310}
311
312pub fn make_app_assistant<T: AppAssistant + Default + 'static>() -> AssistantCreatorFunc {
314 Box::new(make_app_assistant_fut::<T>)
315}
316
317pub struct ViewCreationParameters {
319 pub view_key: ViewKey,
321 pub app_sender: AppSender,
323 pub display_id: Option<DisplayId>,
326 pub options: Option<Box<dyn Any>>,
329}
330
331impl Debug for ViewCreationParameters {
332 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
333 f.debug_struct("ViewCreationParameters")
334 .field("view_key", &self.view_key)
335 .field("display_id", &self.display_id)
336 .field("options", &self.options)
337 .finish()
338 }
339}
340
341pub trait AppAssistant {
345 fn setup(&mut self) -> Result<(), Error>;
350
351 fn create_view_assistant(&mut self, _: ViewKey) -> Result<ViewAssistantPtr, Error> {
354 todo!("Must implement create_view_assistant_with_parameters or create_view_assistant");
355 }
356
357 fn create_view_assistant_with_parameters(
361 &mut self,
362 params: ViewCreationParameters,
363 ) -> Result<ViewAssistantPtr, Error> {
364 self.create_view_assistant(params.view_key)
365 }
366
367 fn outgoing_services_names(&self) -> Vec<&'static str> {
369 Vec::new()
370 }
371
372 fn handle_service_connection_request(
374 &mut self,
375 _service_name: &str,
376 _channel: fasync::Channel,
377 ) -> Result<(), Error> {
378 return Err(format_err!("handle_service_connection_request not implemented"));
379 }
380
381 fn filter_config(&mut self, _config: &mut Config) {}
383
384 #[allow(unused_variables)]
387 fn handle_message(&mut self, message: Message) {}
388}
389
390pub type AppAssistantPtr = Box<dyn AppAssistant>;
392
393pub struct App {
396 strategy: AppStrategyPtr,
397 view_controllers: BTreeMap<ViewKey, ViewController>,
398 assistant: AppAssistantPtr,
399 messages: Vec<(ViewKey, Message)>,
400 sender: InternalSender,
401 _inspect_server: Option<inspect_runtime::PublishedInspectController>,
402}
403
404#[derive(Debug)]
405pub(crate) enum MessageInternal {
406 ServiceConnection(zx::Channel, &'static str),
407 CreateView(ViewStrategyParams),
408 CreateAdditionalView(ViewKey, Option<CreateViewOptions>),
409 CloseAdditionalView(ViewKey),
410 MetricsChanged(ViewKey, Size),
411 SizeChanged(ViewKey, Size),
412 Focus(ViewKey, bool),
413 CloseViewsOnDisplay(DisplayId),
414 RequestRender(ViewKey),
415 Render(ViewKey),
416 ImageFreed(ViewKey, u64, u32),
417 TargetedMessage(MessageTarget, Message),
418 RegisterDevice(DeviceId, hid_input_report::DeviceDescriptor),
419 InputReport(DeviceId, hid_input_report::InputReport),
420 KeyboardAutoRepeat(DeviceId),
421 OwnershipChanged(bool),
422 DropDisplayResources,
423 FlatlandOnNextFrameBegin(ViewKey, fidl_fuchsia_ui_composition::OnNextFrameBeginValues),
424 FlatlandOnFramePresented(ViewKey, fidl_fuchsia_scenic_scheduling::FramePresentedInfo),
425 FlatlandOnError(ViewKey, fuchsia_scenic::flatland::FlatlandError),
426 NewDisplayCoordinator(PathBuf),
427 DisplayCoordinatorListenerRequest(CoordinatorListenerRequest),
428 SetVirtconMode(VirtconMode),
429 UserInputMessage(ViewKey, UserInputMessage),
430}
431
432pub type AssistantCreator<'a> = LocalBoxFuture<'a, Result<AppAssistantPtr, Error>>;
434pub type AssistantCreatorFunc = Box<dyn FnOnce(&AppSender) -> AssistantCreator<'_>>;
436
437impl App {
438 fn new(sender: InternalSender, strategy: AppStrategyPtr, assistant: AppAssistantPtr) -> App {
439 App {
440 strategy,
441 view_controllers: BTreeMap::new(),
442 assistant,
443 messages: Vec::new(),
444 sender,
445 _inspect_server: inspect_runtime::publish(
446 fuchsia_inspect::component::inspector(),
447 inspect_runtime::PublishOptions::default(),
448 ),
449 }
450 }
451
452 fn load_and_filter_config(assistant: &mut AppAssistantPtr) -> Result<(), Error> {
453 let mut config = Self::load_config()?;
454 assistant.filter_config(&mut config);
455 CONFIG.set(config).expect("config set");
456 Ok(())
457 }
458
459 pub fn run(assistant_creator_func: AssistantCreatorFunc) -> Result<(), Error> {
462 let mut executor = fasync::LocalExecutor::new();
463 let (internal_sender, mut internal_receiver) = unbounded::<MessageInternal>();
464 let f = async {
465 let app_sender = AppSender { sender: internal_sender.clone() };
466 let assistant_creator = assistant_creator_func(&app_sender);
467 let mut assistant = assistant_creator.await?;
468 Self::load_and_filter_config(&mut assistant)?;
469 let strat = create_app_strategy(&internal_sender).await?;
470 let mut app = App::new(internal_sender, strat, assistant);
471 app.app_init_common().await?;
472 let startup_delay = Config::get().startup_delay;
473 if !startup_delay.is_zero() {
474 duration!(c"gfx", c"App::run-startup-delay");
475 std::thread::sleep(Config::get().startup_delay);
476 }
477 while let Some(message) = internal_receiver.next().await {
478 app.handle_message(message).await?;
479 }
480 Ok::<(), Error>(())
481 };
482 executor.run_singlethreaded(f)?;
483 Ok(())
484 }
485
486 async fn handle_message(&mut self, message: MessageInternal) -> Result<(), Error> {
487 match message {
488 MessageInternal::ServiceConnection(channel, service_name) => {
489 let channel = fasync::Channel::from_channel(channel);
490 self.assistant
491 .handle_service_connection_request(service_name, channel)
492 .unwrap_or_else(|e| {
493 eprintln!("error running {} server: {:?}", service_name, e)
494 });
495 }
496 MessageInternal::CreateView(params) => {
497 self.create_view_with_params(params, None).await?
498 }
499 MessageInternal::CreateAdditionalView(view_key, options) => {
500 self.create_additional_view(view_key, options).await?
501 }
502 MessageInternal::CloseAdditionalView(view_key) => {
503 self.close_additional_view(view_key)?;
504 }
505 MessageInternal::MetricsChanged(view_id, metrics) => {
506 if let Ok(view) = self.get_view(view_id) {
507 view.handle_metrics_changed(metrics);
508 }
509 }
510 MessageInternal::SizeChanged(view_id, new_size) => {
511 if let Ok(view) = self.get_view(view_id) {
512 view.handle_size_changed(new_size);
513 }
514 }
515 MessageInternal::Focus(view_id, focused) => {
516 if let Ok(view) = self.get_view(view_id) {
517 view.focus(focused);
518 }
519 }
520 MessageInternal::RequestRender(view_id) => {
521 if let Ok(view) = self.get_view(view_id) {
522 view.request_render();
523 }
524 }
525 MessageInternal::Render(view_id) => {
526 if let Ok(view) = self.get_view(view_id) {
527 view.render().await;
528 }
529 }
530 MessageInternal::CloseViewsOnDisplay(display_id) => {
531 let view_keys = self.get_view_keys_for_display(display_id);
532 for view_key in view_keys.into_iter() {
533 self.close_view(view_key);
534 }
535 }
536 MessageInternal::ImageFreed(view_id, image_id, collection_id) => {
537 self.image_freed(view_id, image_id, collection_id)
538 }
539 MessageInternal::TargetedMessage(target, message) => match target {
540 MessageTarget::Facet(view_id, facet_id) => {
541 let view = self.get_view(view_id).context("TargetedMessage")?;
542 view.send_facet_message(facet_id, message).context("TargetedMessage")?;
543 }
544 MessageTarget::View(view_id) => {
545 let view = self.get_view(view_id).context("TargetedMessage")?;
546 view.send_message(message);
547 }
548 MessageTarget::Application => {
549 self.assistant.handle_message(message);
550 }
551 },
552 MessageInternal::RegisterDevice(device_id, device_descriptor) => {
553 self.strategy.handle_register_input_device(&device_id, &device_descriptor);
554 }
555 MessageInternal::InputReport(device_id, input_report) => {
556 let input_events = self.strategy.handle_input_report(&device_id, &input_report);
557 if let Some(focused_view_key) = self.get_focused_view_key() {
558 let view = self.get_view(focused_view_key).context("InputReport")?;
559 view.handle_input_events(input_events).context("InputReport")?;
560 } else {
561 eprintln!("dropping input report due to no focused view");
562 }
563 }
564 MessageInternal::KeyboardAutoRepeat(device_id) => {
565 let input_events = self.strategy.handle_keyboard_autorepeat(&device_id);
566 if let Some(focused_view_key) = self.get_focused_view_key() {
567 let view = self.get_view(focused_view_key).context("KeyboardAutoRepeat")?;
568 view.handle_input_events(input_events).context("KeyboardAutoRepeat")?;
569 } else {
570 eprintln!("dropping keyboard auto repeat due to no focused view");
571 }
572 }
573 MessageInternal::UserInputMessage(view_id, user_input_message) => {
574 let view = self.get_view(view_id).context("UserInputMessage")?;
575 view.handle_user_input_message(user_input_message)?;
576 }
577 MessageInternal::OwnershipChanged(owned) => {
578 self.ownership_changed(owned);
579 }
580 MessageInternal::DropDisplayResources => {
581 self.drop_display_resources();
582 }
583 MessageInternal::FlatlandOnNextFrameBegin(view_id, info) => {
584 let view = self.get_view(view_id).context("FlatlandOnNextFrameBegin")?;
585 view.handle_on_next_frame_begin(&info);
586 }
587 MessageInternal::FlatlandOnFramePresented(view_id, info) => {
588 let view = self.get_view(view_id).context("FlatlandOnFramePresented")?;
589 view.present_done(info);
590 }
591 MessageInternal::FlatlandOnError(view_id, error) => {
592 eprintln!("flatland error view: {}, error: {:#?}", view_id, error);
593 }
594 MessageInternal::NewDisplayCoordinator(display_path) => {
595 self.strategy.handle_new_display_coordinator(display_path).await;
596 }
597 MessageInternal::DisplayCoordinatorListenerRequest(request) => match request {
598 CoordinatorListenerRequest::OnVsync { display_id, .. } => {
599 if let Some(view_key) =
600 self.strategy.get_visible_view_key_for_display(display_id.into())
601 {
602 if let Ok(view) = self.get_view(view_key) {
603 view.handle_display_coordinator_listener_request(request).await;
604 } else {
605 eprintln!("vsync for display {:?} with no view", display_id);
608 }
609 }
610 }
611
612 _ => self.strategy.handle_display_coordinator_event(request).await,
613 },
614 MessageInternal::SetVirtconMode(virtcon_mode) => {
615 self.strategy.set_virtcon_mode(virtcon_mode);
616 }
617 }
618 Ok(())
619 }
620
621 async fn app_init_common(&mut self) -> Result<(), Error> {
622 self.assistant.setup().context("app setup")?;
623 self.start_services()?;
624 Ok(())
625 }
626
627 pub fn test(assistant_creator_func: AssistantCreatorFunc) -> Result<(), Error> {
632 let mut executor = fasync::LocalExecutor::new();
633 let (internal_sender, mut internal_receiver) = unbounded::<MessageInternal>();
634 let f = async {
635 let app_sender = AppSender { sender: internal_sender.clone() };
636 let assistant_creator = assistant_creator_func(&app_sender);
637 let mut assistant = assistant_creator.await?;
638 Self::load_and_filter_config(&mut assistant)?;
639 let strat = create_app_strategy(&internal_sender).await?;
640 strat.create_view_for_testing(&internal_sender)?;
641 let mut app = App::new(internal_sender, strat, assistant);
642 let mut frame_count = 0;
643 app.app_init_common().await?;
644 loop {
645 let timeout =
646 pin!(Timer::new(zx::MonotonicDuration::from_millis(500_i64).after_now()));
647 let either = futures::future::select(timeout, internal_receiver.next());
648 let resolved = either.await;
649 match resolved {
650 Either::Left(_) => {
651 return Err(format_err!(
652 "Carnelian test got timeout before seeing 10 frames"
653 ));
654 }
655 Either::Right((right_result, _)) => {
656 let message = right_result.expect("message");
657 match message {
658 MessageInternal::Render(_) => {
659 frame_count += 1;
660 }
661 _ => (),
662 }
663 app.handle_message(message).await.expect("handle_message failed");
664 if frame_count > 10 {
665 break;
666 }
667 }
668 }
669 }
670 Ok::<(), Error>(())
671 };
672
673 executor.run_singlethreaded(f)?;
674
675 Ok(())
676 }
677
678 fn get_focused_view_key(&self) -> Option<ViewKey> {
679 self.strategy.get_focused_view_key()
680 }
681
682 fn get_view(&mut self, view_key: ViewKey) -> Result<&mut ViewController, Error> {
683 if let Some(view) = self.view_controllers.get_mut(&view_key) {
684 Ok(view)
685 } else {
686 bail!("Could not find view controller for {}", view_key);
687 }
688 }
689
690 fn get_view_keys_for_display(&mut self, display_id: DisplayId) -> Vec<ViewKey> {
691 self.view_controllers
692 .iter()
693 .filter_map(|(view_key, view_controller)| {
694 view_controller.is_hosted_on_display(display_id).then_some(*view_key)
695 })
696 .collect()
697 }
698
699 fn close_view(&mut self, view_key: ViewKey) {
700 let view = self.view_controllers.remove(&view_key);
701 if let Some(mut view) = view {
702 view.close();
703 }
704 self.strategy.handle_view_closed(view_key);
705 }
706
707 fn ownership_changed(&mut self, owned: bool) {
708 for (_, view_controller) in &mut self.view_controllers {
709 view_controller.ownership_changed(owned);
710 }
711 }
712
713 fn drop_display_resources(&mut self) {
714 for (_, view_controller) in &mut self.view_controllers {
715 view_controller.drop_display_resources();
716 }
717 }
718
719 pub fn queue_message(&mut self, target: ViewKey, msg: Message) {
722 self.messages.push((target, msg));
723 }
724
725 fn create_view_assistant(
728 &mut self,
729 view_key: ViewKey,
730 display_id: Option<DisplayId>,
731 options: Option<CreateViewOptions>,
732 ) -> Result<ViewAssistantPtr, Error> {
733 Ok(self.assistant.create_view_assistant_with_parameters(ViewCreationParameters {
734 view_key,
735 display_id,
736 app_sender: AppSender { sender: self.sender.clone() },
737 options,
738 })?)
739 }
740
741 async fn create_view_with_params(
742 &mut self,
743 params: ViewStrategyParams,
744 options: Option<CreateViewOptions>,
745 ) -> Result<(), Error> {
746 let view_key = if let Some(view_key) = params.view_key() {
747 view_key
748 } else {
749 IdGenerator2::<ViewKey>::next().expect("view_key")
750 };
751 let view_assistant = self
752 .create_view_assistant(view_key, params.display_id(), options)
753 .context("create_view_assistant")?;
754 let sender = &self.sender;
755 let view_strat = {
756 let view_strat = self
757 .strategy
758 .create_view_strategy(view_key, sender.clone(), params)
759 .await
760 .context("create_view_strategy")?;
761 self.strategy.post_setup(sender).await.context("post_setup")?;
762 view_strat
763 };
764 let view_controller =
765 ViewController::new_with_strategy(view_key, view_assistant, view_strat, sender.clone())
766 .await
767 .context("new_with_strategy")?;
768
769 self.view_controllers.insert(view_key, view_controller);
770 Ok(())
771 }
772
773 async fn create_additional_view(
774 &mut self,
775 view_key: ViewKey,
776 options: Option<CreateViewOptions>,
777 ) -> Result<(), Error> {
778 let params = self.strategy.create_view_strategy_params_for_additional_view(view_key);
779 self.create_view_with_params(params, options).await
780 }
781
782 fn close_additional_view(&mut self, view_key: ViewKey) -> Result<(), Error> {
783 self.close_view(view_key);
784 Ok(())
785 }
786
787 fn start_services(self: &mut App) -> Result<(), Error> {
788 let mut fs = component::server::ServiceFs::new_local();
789
790 self.strategy.start_services(self.sender.clone(), &mut fs)?;
791
792 let outgoing_services_names = self.assistant.outgoing_services_names();
793 let mut public = fs.dir("svc");
794 for name in outgoing_services_names {
795 let sender = self.sender.clone();
796 public.add_service_at(name, move |channel| {
797 sender
798 .unbounded_send(MessageInternal::ServiceConnection(channel, name))
799 .expect("unbounded_send");
800 None
801 });
802 }
803
804 match fs.take_and_serve_directory_handle() {
805 Err(e) => eprintln!("Error publishing services: {:#}", e),
806 Ok(_) => (),
807 }
808
809 fasync::Task::local(fs.collect()).detach();
810 Ok(())
811 }
812
813 pub(crate) fn image_freed(&mut self, view_id: ViewKey, image_id: u64, collection_id: u32) {
814 if let Ok(view) = self.get_view(view_id) {
815 view.image_freed(image_id, collection_id);
816 }
817 }
818
819 fn load_config() -> Result<Config, Error> {
820 const CARNELIAN_CONFIG_PATH: &str = "/pkg/data/config/carnelian.toml";
821 let config_path = PathBuf::from(CARNELIAN_CONFIG_PATH);
822 if !config_path.exists() {
823 return Ok(Config::default());
824 }
825 let config_contents = fs::read_to_string(config_path)?;
826 let config = toml::from_str(&config_contents)?;
827 Ok(config)
828 }
829}