1use std::io;
16use std::sync::{Arc, Mutex, MutexGuard, Weak};
17
18use serde_json::Value;
19
20use xi_rpc::{Error as RpcError, Handler, ReadError, RemoteError, RpcCtx};
21use xi_trace;
22
23use crate::plugin_rpc::{PluginCommand, PluginNotification, PluginRequest};
24use crate::plugins::{Plugin, PluginId};
25use crate::rpc::*;
26use crate::tabs::{CoreState, ViewId};
27
28pub enum XiCore {
36 Waiting,
39 Running(Arc<Mutex<CoreState>>),
40}
41
42#[derive(Clone)]
44pub struct WeakXiCore(Weak<Mutex<CoreState>>);
45
46#[allow(dead_code)]
47impl XiCore {
48 pub fn new() -> Self {
49 XiCore::Waiting
50 }
51
52 fn is_waiting(&self) -> bool {
54 match *self {
55 XiCore::Waiting => true,
56 _ => false,
57 }
58 }
59
60 pub fn inner(&self) -> MutexGuard<CoreState> {
66 match self {
67 XiCore::Running(ref inner) => inner.lock().unwrap(),
68 XiCore::Waiting => panic!(
69 "core does not start until client_started \
70 RPC is received"
71 ),
72 }
73 }
74
75 fn weak_self(&self) -> Option<WeakXiCore> {
77 match self {
78 XiCore::Running(ref inner) => Some(WeakXiCore(Arc::downgrade(inner))),
79 XiCore::Waiting => None,
80 }
81 }
82}
83
84impl Handler for XiCore {
86 type Notification = CoreNotification;
87 type Request = CoreRequest;
88
89 fn handle_notification(&mut self, ctx: &RpcCtx, rpc: Self::Notification) {
90 use self::CoreNotification::*;
91
92 if let TracingConfig { enabled } = rpc {
94 match enabled {
95 true => xi_trace::enable_tracing(),
96 false => xi_trace::disable_tracing(),
97 }
98 info!("tracing in core = {:?}", enabled);
99 if self.is_waiting() {
100 return;
101 }
102 }
103
104 if let ClientStarted { ref config_dir, ref client_extras_dir } = rpc {
106 assert!(self.is_waiting(), "client_started can only be sent once");
107 let state =
108 CoreState::new(ctx.get_peer(), config_dir.clone(), client_extras_dir.clone());
109 let state = Arc::new(Mutex::new(state));
110 *self = XiCore::Running(state);
111 let weak_self = self.weak_self().unwrap();
112 self.inner().finish_setup(weak_self);
113 }
114
115 self.inner().client_notification(rpc);
116 }
117
118 fn handle_request(&mut self, _ctx: &RpcCtx, rpc: Self::Request) -> Result<Value, RemoteError> {
119 self.inner().client_request(rpc)
120 }
121
122 fn idle(&mut self, _ctx: &RpcCtx, token: usize) {
123 self.inner().handle_idle(token);
124 }
125}
126
127impl WeakXiCore {
128 fn upgrade(&self) -> Option<XiCore> {
131 self.0.upgrade().map(XiCore::Running)
132 }
133
134 pub fn plugin_connect(&self, plugin: Result<Plugin, io::Error>) {
137 if let Some(core) = self.upgrade() {
138 core.inner().plugin_connect(plugin)
139 }
140 }
141
142 pub fn plugin_exit(&self, plugin: PluginId, error: Result<(), ReadError>) {
144 if let Some(core) = self.upgrade() {
145 core.inner().plugin_exit(plugin, error)
146 }
147 }
148
149 pub fn handle_plugin_update(
156 &self,
157 plugin: PluginId,
158 view: ViewId,
159 response: Result<Value, RpcError>,
160 ) {
161 if let Some(core) = self.upgrade() {
162 let _t = xi_trace::trace_block("WeakXiCore::plugin_update", &["core"]);
163 core.inner().plugin_update(plugin, view, response);
164 }
165 }
166}
167
168impl Handler for WeakXiCore {
170 type Notification = PluginCommand<PluginNotification>;
171 type Request = PluginCommand<PluginRequest>;
172
173 fn handle_notification(&mut self, ctx: &RpcCtx, rpc: Self::Notification) {
174 let PluginCommand { view_id, plugin_id, cmd } = rpc;
175 if let Some(core) = self.upgrade() {
176 core.inner().plugin_notification(ctx, view_id, plugin_id, cmd)
177 }
178 }
179
180 fn handle_request(&mut self, ctx: &RpcCtx, rpc: Self::Request) -> Result<Value, RemoteError> {
181 let PluginCommand { view_id, plugin_id, cmd } = rpc;
182 if let Some(core) = self.upgrade() {
183 core.inner().plugin_request(ctx, view_id, plugin_id, cmd)
184 } else {
185 Err(RemoteError::custom(0, "core is missing", None))
186 }
187 }
188}
189
190#[cfg(test)]
191pub fn dummy_weak_core() -> WeakXiCore {
193 use xi_rpc::test_utils::DummyPeer;
194 use xi_rpc::Peer;
195 let peer = Box::new(DummyPeer);
196 let state = CoreState::new(&peer.box_clone(), None, None);
197 let core = Arc::new(Mutex::new(state));
198 WeakXiCore(Arc::downgrade(&core))
199}