1use std::{
2 any::Any,
3 convert::Infallible,
4 marker::PhantomData,
5 sync::{atomic::AtomicBool, Arc, RwLock},
6};
7
8use once_cell::sync::Lazy;
9
10use crate::{
11 async_task::{IAsyncTaskRuntimeAdapter, MistyAsyncTaskPools},
12 controllers::{call_controller, ControllerRet, MistyController},
13 resources::MistyResourceManager,
14 schedule::{controller_flush_scheduled_tasks, ScheduleManager},
15 services::MistyServiceManager,
16 signals::{MistySignal, SignalEmitter},
17 states::MistyStateManager,
18 views::MistyViewModelManager,
19};
20
21use super::{MistyClientAccessor, MistyClientId, MistyClientInner};
22
23struct MistyClient<R> {
24 inner: Arc<MistyClientInner>,
25 _marker: PhantomData<R>,
26}
27
28impl<R> MistyClient<R>
29where
30 R: Any + Default + Send + Sync + 'static,
31{
32 fn new(
33 view_manager: MistyViewModelManager<R>,
34 state_manager: MistyStateManager,
35 service_manager: MistyServiceManager,
36 async_task_runtime: impl IAsyncTaskRuntimeAdapter + Send + Sync + 'static,
37 ) -> Self {
38 let inner = Arc::new(MistyClientInner {
39 id: MistyClientId::alloc(),
40 state_manager,
41 view_manager: Box::new(view_manager),
42 service_manager,
43 resource_manager: MistyResourceManager::new(),
44 async_task_pools: MistyAsyncTaskPools::new(),
45 async_task_runtime: Box::new(async_task_runtime),
46 schedule_manager: ScheduleManager::new(),
47 signal_emitter: SignalEmitter::new(),
48 destroyed: AtomicBool::new(false),
49 });
50
51 Self {
52 inner,
53 _marker: Default::default(),
54 }
55 }
56}
57
58pub struct SingletonMistyClientPod<R> {
59 client: Lazy<RwLock<Option<MistyClient<R>>>>,
60}
61
62impl<R> SingletonMistyClientPod<R>
63where
64 R: Any + Default + Send + Sync + 'static,
65{
66 pub const fn new() -> Self {
67 Self {
68 client: Lazy::new(|| Default::default()),
69 }
70 }
71
72 pub fn reset(&self) {
73 let _ = tracing::span!(tracing::Level::INFO, "SingletonMistyClientPod.reset").enter();
74 let pod = self.client.write().unwrap().take();
75 if let Some(client) = pod {
76 client.inner.destroy();
77 }
78 }
79
80 pub fn destroy(&self) {
81 self.inner().destroy();
82 }
83
84 pub fn create(
85 &self,
86 view_manager: MistyViewModelManager<R>,
87 state_manager: MistyStateManager,
88 service_manager: MistyServiceManager,
89 async_task_runtime: impl IAsyncTaskRuntimeAdapter + Send + Sync + 'static,
90 ) {
91 let _ = tracing::span!(tracing::Level::INFO, "SingletonMistyClientPod.set").enter();
92
93 let mut pod = self.client.write().unwrap();
94 if pod.is_some() {
95 panic!("client is already in pod");
96 }
97 *pod = Some(MistyClient::new(
98 view_manager,
99 state_manager,
100 service_manager,
101 async_task_runtime,
102 ));
103 }
104
105 pub fn call_controller<Controller, Arg, E>(
106 &self,
107 controller: Controller,
108 arg: Arg,
109 ) -> Result<ControllerRet<R>, E>
110 where
111 Controller: MistyController<Arg, E>,
112 {
113 let inner = {
114 let pod = self.client.read().unwrap();
115 if let Some(client) = pod.as_ref() {
116 client.inner.clone()
117 } else {
118 panic!(
119 "client not in singleton pod. controller is {}",
120 std::any::type_name::<Controller>()
121 );
122 }
123 };
124 call_controller(&inner, controller, arg)
125 }
126
127 pub fn on_signal(&self, f: impl Fn(MistySignal) + Send + Sync + 'static) {
128 let inner = self.inner();
129 inner.signal_emitter.set(f);
130 }
131
132 pub fn flush_scheduled_tasks(&self) -> Result<ControllerRet<R>, Infallible> {
133 self.call_controller(controller_flush_scheduled_tasks, ())
134 }
135
136 pub fn accessor(&self) -> MistyClientAccessor {
137 MistyClientAccessor {
138 inner: Arc::downgrade(&self.inner()),
139 }
140 }
141
142 fn inner(&self) -> Arc<MistyClientInner> {
143 let pod = self.client.read().unwrap();
144 if let Some(client) = pod.as_ref() {
145 client.inner.clone()
146 } else {
147 panic!("client not in singleton pod.");
148 }
149 }
150}