install_framework_gui/
interface.rs

1// Copyright 2021 Yuri6037
2
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19// IN THE SOFTWARE.
20
21use std::collections::HashMap;
22use std::path::Path;
23use install_framework_core::interface::Interface;
24use install_framework_core::interface::Installer;
25use install_framework_core::interface::InstallMethod;
26use install_framework_core::interface::PostInstall;
27use install_framework_core::interface::PostUninstall;
28use install_framework_core::interface::Component;
29use install_framework_base::interface::BaseInterface;
30use async_channel::Sender;
31use async_channel::Receiver;
32
33use crate::interpreter::ThreadedInterpreter;
34use crate::messages::RenderMessage;
35use crate::messages::ThreadMessage;
36use crate::messages::Page;
37use crate::error::GuiError;
38use crate::ext::SenderSync;
39use crate::ext::ReceiverSync;
40
41pub struct ThreadLinker
42{
43    sender: Sender<RenderMessage>,
44    receiver: Receiver<ThreadMessage>
45}
46
47impl ThreadLinker
48{
49    pub fn new(sender: Sender<RenderMessage>, receiver: Receiver<ThreadMessage>) -> ThreadLinker
50    {
51        return ThreadLinker
52        {
53            sender: sender,
54            receiver: receiver
55        };
56    }
57
58    pub fn recv(&mut self) -> Result<ThreadMessage, GuiError>
59    {
60        match self.receiver.recv_sync()
61        {
62            Ok(v) => return Ok(v),
63            Err(e) => return Err(GuiError::channel_recv(e))
64        };
65    }
66
67    pub fn send(&mut self, msg: RenderMessage) -> Result<(), GuiError>
68    {
69        if let Err(e) = self.sender.send_sync(msg)
70        {
71            return Err(GuiError::channel_send(e));
72        }
73        return Ok(());
74    }
75
76    pub fn clone_sender(&self) -> Sender<RenderMessage>
77    {
78        return self.sender.clone();
79    }
80
81    pub fn clone_receiver(&self) -> Receiver<ThreadMessage>
82    {
83        return self.receiver.clone();
84    }
85}
86
87pub struct GuiInterface
88{
89    base: BaseInterface<ThreadedInterpreter, GuiError>,
90    thread: ThreadLinker,
91    uninstall: bool,
92    method: InstallMethod
93}
94
95impl GuiInterface
96{
97    pub fn new(thread: ThreadLinker) -> GuiInterface
98    {
99        return GuiInterface
100        {
101            base: BaseInterface::new(ThreadedInterpreter::new(thread.clone_sender(), thread.clone_receiver())),
102            thread: thread,
103            uninstall: false,
104            method: InstallMethod::SystemInstall
105        };
106    }
107
108    fn wait_next_or_error(&mut self) -> Result<Option<(InstallMethod, bool)>, GuiError>
109    {
110        loop
111        {
112            match self.thread.recv()?
113            {
114                ThreadMessage::Next(data) => return Ok(data),
115                ThreadMessage::Terminate => return Err(GuiError::Interupted),
116                _ => return Err(GuiError::IllegalMessage)
117            }
118        }
119    }
120
121    fn wait_install_components(&mut self) -> Result<Vec<Component>, GuiError>
122    {
123        loop
124        {
125            match self.thread.recv()?
126            {
127                ThreadMessage::InstallComponents(data) => return Ok(data),
128                ThreadMessage::Terminate => return Err(GuiError::Interupted),
129                _ => return Err(GuiError::IllegalMessage)
130            }
131        }
132    }
133
134    fn wait_terminate(&mut self) -> Result<(), GuiError>
135    {
136        loop
137        {
138            if let Ok(v) = self.thread.recv()
139            {
140                match v
141                {
142                    ThreadMessage::Terminate => return Ok(()),
143                    _ => return Err(GuiError::IllegalMessage)
144                }
145            }
146            return Ok(());
147        }
148    }
149}
150
151impl Interface for GuiInterface
152{
153    type ErrorType = GuiError;
154
155    fn welcome(&mut self, name: &'static str, version: &'static str, author: &'static str) -> Result<(), GuiError>
156    {
157        self.base.set_static_info(name, version, author);
158        self.thread.send(RenderMessage::SwitchPage(Page::Welcome(name, version, author)))?;
159        match self.wait_next_or_error()?
160        {
161            Some((method, uninstall)) =>
162            {
163                self.method = method;
164                self.uninstall = uninstall;
165                return Ok(());
166            },
167            None => return Err(GuiError::IllegalMessage)
168        };
169    }
170
171    fn get_install_method(&mut self) -> Result<InstallMethod, GuiError>
172    {
173        return Ok(self.method);
174    }
175
176    fn should_uninstall(&self) -> Result<bool, GuiError>
177    {
178        return Ok(self.uninstall);
179    }
180
181    fn run_install(&mut self, installer: &mut dyn Installer, dir: &Path, method: InstallMethod, resources: &HashMap<&'static str, &'static [u8]>) -> Result<(), GuiError>
182    {
183        self.thread.send(RenderMessage::SwitchPage(Page::Processing))?;
184        let components = self.base.get_components(installer, resources)?;
185        let copy = components.clone();
186        let state = self.base.get_installation_state(components, installer, dir)?;
187        self.thread.send(RenderMessage::SwitchPage(Page::ComponentView(copy, state, false)))?;
188        let comps = self.wait_install_components()?;
189        self.thread.send(RenderMessage::SwitchPage(Page::Processing))?;
190        for v in comps
191        {
192            self.base.install_component(&v, installer, dir, method, resources)?;
193        }
194        return Ok(());
195    }
196
197    fn run_post_install(&mut self, post: &mut dyn PostInstall, dir: &Path) -> Result<(), GuiError>
198    {
199        self.base.run_post_install(post, dir)?;
200        return Ok(());
201    }
202
203    fn run_uninstall(&mut self, installer: &mut dyn Installer, dir: &Path, method: InstallMethod, resources: &HashMap<&'static str, &'static [u8]>) -> Result<(), GuiError>
204    {
205        self.thread.send(RenderMessage::SwitchPage(Page::Processing))?;
206        let components = self.base.get_components(installer, resources)?;
207        let copy = components.clone();
208        let state = self.base.get_installation_state(components, installer, dir)?;
209        self.thread.send(RenderMessage::SwitchPage(Page::ComponentView(copy, state, true)))?;
210        let comps = self.wait_install_components()?;
211        self.thread.send(RenderMessage::SwitchPage(Page::Processing))?;
212        for v in comps
213        {
214            self.base.uninstall_component(&v, installer, dir, method)?;
215        }
216        return Ok(());
217    }
218
219    fn run_post_uninstall(&mut self, post: &mut dyn PostUninstall, dir: &Path) -> Result<(), GuiError>
220    {
221        self.base.run_post_uninstall(post, dir)?;
222        return Ok(());
223    }
224
225    fn error(&mut self, e: GuiError) -> i32
226    {
227        let (_, code) = e.translate();
228        if let Err(e) = self.thread.send(RenderMessage::SwitchPage(Page::Error(e)))
229        {
230            return handle_low_level_error(&e);
231        }
232        if let Err(e) = self.wait_terminate()
233        {
234            return handle_low_level_error(&e);
235        }
236        return code;
237    }
238
239    fn finish(&mut self) -> i32
240    {
241        let msg =
242        {
243            if self.uninstall
244            {
245                String::from("Uninstall complete!")
246            }
247            else
248            {
249                String::from("Install complete!")
250            }
251        };
252        if let Err(e) = self.thread.send(RenderMessage::SwitchPage(Page::Finish(msg)))
253        {
254            return handle_low_level_error(&e);
255        }
256        if let Err(e) = self.wait_terminate()
257        {
258            return handle_low_level_error(&e);
259        }
260        return 0;
261    }
262}
263
264fn handle_low_level_error(e: &GuiError) -> i32
265{
266    let (s, exit) = e.translate();
267    eprintln!("{}", s);
268    return exit;
269}