1pub mod env;
28pub mod proc;
29pub mod natives;
30pub mod crypto;
31pub mod string;
32pub mod fs;
33pub mod paths;
34pub mod service;
35pub mod types;
36pub mod utils;
37pub mod download_file;
38
39#[cfg(target_os = "windows")]
40use winreg::enums::*;
41#[cfg(target_os = "windows")]
42use winreg::RegKey;
43#[cfg(target_os = "windows")]
44use std::path::Path;
45use std::process::Stdio;
46use std::thread::sleep;
47use semver::Version;
48
49use std::io::Write;
50use std::net::TcpStream;
51
52pub type PisPasResult<T> = Result<T, anyhow::Error>;
53pub type CancelToken = std::sync::Arc<std::sync::atomic::AtomicBool>;
54
55pub use natives::api::{Lock, SingleInstance};
56
57pub const VERSION: &str = env!("CARGO_PKG_VERSION");
58pub fn get_version() -> Version {
59 Version::parse(VERSION).unwrap_or_else(|e| {
60 tracing::warn!("Error parsing version: {}", e);
61 Version::new(0, 0, 0)
62 })
63}
64#[allow(unused_variables)]
65pub(crate) const KEY_FILE_NAME: &str = ".secret";
66#[cfg(target_os = "windows")]
67pub const CHANNEL_NAME_OLD: &str = r"\\.\pipe\pispas-channel2";
68#[cfg(not(target_os = "windows"))]
69pub const CHANNEL_NAME_OLD: &str = r"/tmp/pispas-channel2";
70pub const CHANNEL_NAME: &str = r"127.0.0.1:7878";
71pub const CHANNEL_NAME_CFG: &str = r"127.0.0.1:7879";
72
73pub const DATA_VALUES_DELIMITER: &str = "!";
74pub const DATA_DELIMITER: &str = "|";
75
76const ROOT_FOLDER: &str = ".config";
77pub const BASE_FOLDER: &str = "pispas";
78pub const CONFIG_FILE_NAME: &str = "printsvc.json";
79pub const ENV_FILE_NAME: &str = ".env";
80pub const SUMATRA_FILE: &str = "SumatraPDF-3.5.2-64.exe";
81#[cfg(target_os = "windows")]
82pub const WKHTMLTOPDF_FILE: &str = "wkhtmltopdf.exe";
83#[cfg(not(target_os = "windows"))]
84pub const WKHTMLTOPDF_FILE: &str = "wkhtmltopdf";
85pub const PDF_INFO_FILE: &str = "pdfinfo.exe";
86pub const PYTHON_FOLDER: &str = "python";
87pub const POS_DRIVER_FILE: &str = "PosDriver.exe";
88pub const MYPOS_SERVER_FILE: &str = "server_mypos.exe";
89pub const PRINTER_TEST_FILE: &str = "Printer_Test.exe";
90pub const BEEPER_PDF_FILE: &str = "Configuracion_Alarma_Beeper.pdf";
91
92pub const APP_DEV_HOST: &str = "app_dev.unpispas.es";
93pub const APP_PRO_HOST: &str = "unpispas.es";
94pub const ICON_PISPAS: &str = "pispas.ico";
95pub const CONF_PATH: &str = "conf";
96pub const LOGS_PATH: &str = "logs";
97
98pub const LIBRARIES_PATH: &str = "lib";
99pub const BINARIES_PATH: &str = "bin";
100pub const TRAY_ICON_FOLDER: &str = "pispas-tray-app";
101pub const NAME_LEGAL: &str = "© 2024 Gekkotech S.L.";
102
103
104pub const SERVICE_NAME: &str = "pispas-service";
105#[cfg(target_os = "windows")]
106pub const SERVICE_NAME_EXE: &str = "pispas-service.exe";
107#[cfg(not(target_os = "windows"))]
108pub const SERVICE_NAME_EXE: &str = "pispas-service";
109#[cfg(target_os = "windows")]
110pub const TRAY_ICON_NAME: &str = "pispas-tray-app.exe";
111#[cfg(not(target_os = "windows"))]
112pub const TRAY_ICON_NAME: &str = "pispas-tray-app";
113#[cfg(target_os = "windows")]
114pub const NAME_SHORTCUT_DESKTOP: &str = "pispas-tray-icon.exe";
115
116#[cfg(target_os = "windows")]
117pub const PISPAS_CONFIGURATOR: &str = "pispas-configurator-html.exe";
118#[cfg(not(target_os = "windows"))]
119pub const PISPAS_CONFIGURATOR: &str = "pispas-configurator-html";
120#[cfg(target_os = "windows")]
121pub const PRINT_SERVICE: &str = "pispas-modules.exe";
122#[cfg(not(target_os = "windows"))]
123pub const PRINT_SERVICE: &str = "pispas-modules";
124
125#[cfg(target_os = "windows")]
126pub const ORDER_KITCHEN: &str = "pispas-order-kitchen.exe";
127#[cfg(not(target_os = "windows"))]
128pub const ORDER_KITCHEN: &str = "pispas-order-kitchen";
129#[cfg(target_os = "windows")]
130pub const PISPAS_ELEVATOR: &str = "pispas-elevator.exe";
131#[cfg(not(target_os = "windows"))]
132pub const PISPAS_ELEVATOR: &str = "pispas-elevator";
133
134pub const SERVICE_PYTHON_NAME: &str = "client.py";
135pub const OLD_SERVICE_PYTHON_NAME: &str = "local.py";
136pub const PRINTSVC_PYTHON_NAME: &str = "printsvc.py";
137pub const PRINTSVC_PYTHON_NAME_NEW: &str = "print.py";
138
139pub const PERSISTANCE_FILE_NAME: &str = "file.bin";
142
143pub const PNA_ALLOWED_ORIGINS: &[&str] = &[
161 "https://*.unpispas.es",
162 "https://*.unpispas.es:*",
163 "https://*.mywire.org",
164 "https://*.mywire.org:*",
165];
166
167#[cfg(target_os = "windows")]
168pub const PISPAS_INSTALLER: &str = "pispas-installer.exe";
169
170#[cfg(not(target_os = "windows"))]
171pub const PISPAS_INSTALLER: &str = "pispas-installer";
172
173
174#[cfg(target_os = "windows")]
175const PROGRAM_FILES_ENV_VAR: &'static str = "ProgramFiles";
176
177#[cfg(target_os = "windows")]
178pub const PROGRAM_FILES_KEY: &'static str = r"SOFTWARE\Microsoft\Windows\CurrentVersion";
179#[cfg(target_os = "windows")]
180pub const USER_PROFILE_KEY: &'static str = "USERPROFILE";
181#[cfg(target_os = "windows")]
182pub const TMP_KEY: &'static str = "TMP";
183#[cfg(target_os = "windows")]
184pub const ENVIRONMENT: &'static str = r"Environment";
185#[cfg(target_os = "windows")]
186pub const VOLATILE_ENVIRONMENT: &'static str = r"Volatile Environment";
187#[cfg(target_os = "windows")]
188const RUN: &'static str = "Run";
189#[cfg(target_os = "windows")]
190const PROGRAM_FILES_SUBKEY: &'static str = r"ProgramFilesDir";
191#[cfg(target_os = "windows")]
192const PATH_PROGRAMS_KEY: &'static str = r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
193#[cfg(target_os = "windows")]
194const PATH_PROGRAMS_UNINSTLAL_KEY: &'static str = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
195
196#[cfg(target_os = "windows")]
197pub fn get_info_parent() -> Option<proc::UserInfo> {
198 proc::get_gran_father_info().ok()
199}
200
201pub fn get_persistance_path() -> String {
202 let path = paths::bin_dir().join(PERSISTANCE_FILE_NAME);
203 if !path.exists() {
204 std::fs::create_dir_all(&path).expect("Failed to create persistance path");
205 }
206 path.to_str().unwrap().to_string()
207}
208pub fn get_path_mypos_server() -> String {
209 #[cfg(target_os = "windows")]
210 let path = paths::win_dir().join(MYPOS_SERVER_FILE);
211 #[cfg(not(target_os = "windows"))]
212 let path = paths::bin_dir().join(MYPOS_SERVER_FILE);
213 path.to_str().unwrap().to_string()
214}
215pub fn get_path_env() -> String {
216 let path_os_values = std::env::var(env::PATH_ENV).unwrap_or_default();
217 let env = format!(
218 "{}{}{}{}{}",
219 paths::lib_dir().to_str().unwrap(),
220 env::PATH_SEPARATOR,
221 paths::bin_dir().to_str().unwrap(),
222 env::PATH_SEPARATOR,
223 path_os_values
224 );
225 tracing::info!("env path: {}", env);
226 env
227}
228
229#[cfg(target_os = "windows")]
230pub fn get_python_path_install() -> String {
231 let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
233 match hklm.open_subkey("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"){
234 Ok(environment) => {
235 let python_path: String = environment.get_value("PYTHON_PATH").unwrap_or_default();
236 tracing::info!("PYTHON_PATH: {}", python_path);
237 python_path
238 }
239 Err(e) => {
240 tracing::warn!("Error reading PYTHON_PATH: {}", e);
241 "python.exe".to_string()
242 }
243 }
244}
245pub fn add_envs(command: &mut std::process::Command) {
246 command.current_dir(paths::PROGRAM_HOME_DIR.clone())
247 .env(env::PATH_ENV, get_path_env())
248 .env(env::LD_LIBRARY_PATH_ENV, paths::lib_dir().to_str().unwrap())
249 .stdout(Stdio::piped())
250 .stderr(Stdio::piped());
251}
252
253pub fn is_windows_7() -> bool {
254 #[cfg(target_os = "windows")]
255 {
256 let output = std::process::Command::new("cmd")
257 .arg("/c")
258 .arg("ver")
259 .output();
260
261 match output {
262 Ok(output) => {
263 let version_output = String::from_utf8_lossy(&output.stdout);
264 tracing::info!("Running on windows version: {}", version_output);
265 return version_output.contains("6.1.");
266 }
267 Err(e) => {
268 tracing::warn!("Running on windows with error: {}", e);
269 return false;
270 }
271 }
272 }
273
274 #[cfg(not(target_os = "windows"))]
275 {
276 tracing::info!("running on other windows version");
277 false
278 }
279}
280
281#[cfg(target_os = "windows")]
282pub fn remove_registry_entries() -> Result<(), Box<dyn std::error::Error>> {
283 let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
284 match hklm.open_subkey(PATH_PROGRAMS_KEY)
285 {
286 Ok(subkey) => {
287 let _ = subkey.delete_subkey(Path::new(TRAY_ICON_NAME));
288 }
289 Err(e) => {
290 tracing::warn!("Error removing registry entries: {}", e);
291 }
292 }
293 match hklm.open_subkey(PATH_PROGRAMS_UNINSTLAL_KEY) {
294 Ok(subkey) => {
295 let _ = subkey.delete_subkey(Path::new(TRAY_ICON_NAME));
296 }
297 Err(e) => {
298 tracing::warn!("Error removing registry entries: {}", e);
299 }
300 }
301
302 match hklm.create_subkey(format!("{}\\{}", PROGRAM_FILES_KEY, RUN)) {
303 Ok((key, disp)) => {
304 match disp {
305 REG_CREATED_NEW_KEY => tracing::info!("A new key has been created {:?}", key),
306 REG_OPENED_EXISTING_KEY => tracing::info!("An existing key has been opened {:?}", key),
307 }
308 let _ = key.delete_value(BASE_FOLDER);
309 }
310 Err(e) => {
311 tracing::warn!("Error creating registry entries: {}", e);
312 }
313 }
314
315 Ok(())
316}
317
318#[cfg(target_os = "windows")]
319pub fn create_registry_entries() -> Result<(), Box<dyn std::error::Error>> {
320 let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
321 match hklm.open_subkey(PATH_PROGRAMS_KEY)
322 {
323 Ok(subkey) => {
324 let (key, disp) = subkey.create_subkey(Path::new(TRAY_ICON_NAME))?;
325 match disp {
326 REG_CREATED_NEW_KEY => tracing::info!("A new key has been created {:?}", key),
327 REG_OPENED_EXISTING_KEY => tracing::info!("An existing key has been opened {:?}", key),
328 }
329 let _ = key.set_value("", &paths::tray_icon_path().display().to_string());
330 let _ = key.set_value("Path", &paths::bin_dir().display().to_string());
331 }
332 Err(e) => {
333 tracing::warn!("Error creating registry entries: {}", e);
334 }
335 }
336
337
338 match hklm.open_subkey(PATH_PROGRAMS_UNINSTLAL_KEY)
339 {
340 Ok(subkey) => {
341 let (key, disp) = subkey.create_subkey(Path::new(crate::TRAY_ICON_NAME))?;
342 match disp {
343 REG_CREATED_NEW_KEY => {
344 tracing::info!("A new key has been created {:?}", key);
345 let _ = key.set_value("DisplayIcon", &paths::tray_icon_path().display().to_string());
346 let _ = key.set_value("DisplayName", &"pispas Service");
347 let _ = key.set_value("DisplayVersion", &VERSION);
348 let _ = key.set_value("InstallLocation", &paths::bin_dir().display().to_string());
349 let _ = key.set_value("Publisher", &"GEKKOTECH S.L");
350 let uninstal_string = format!("{} -sd", paths::elevator_path().display().to_string());
351 let _ = key.set_value("UninstallString", &uninstal_string);
352 }
353 REG_OPENED_EXISTING_KEY => {
354 tracing::info!("An existing key has been opened {:?}", key);
355 let _ = key.set_value("DisplayVersion", &VERSION);
356 }
357 }
358 }
360 Err(e) => {
361 tracing::warn!("Error creating registry entries: {}", e);
362 }
363 }
364
365 match hklm.create_subkey(format!("{}\\{}", PROGRAM_FILES_KEY, RUN)) {
366 Ok((key, disp)) => {
367 match disp {
368 REG_CREATED_NEW_KEY => tracing::info!("A new key has been created {:?}", key),
369 REG_OPENED_EXISTING_KEY => tracing::info!("An existing key has been opened {:?}", key),
370 }
371 let _ = key.set_value(BASE_FOLDER, &paths::tray_icon_path().display().to_string());
372 }
373 Err(e) => {
374 tracing::warn!("Error creating registry entries: {}", e);
375 }
376 }
377
378 Ok(())
382}
383
384pub fn stop_pispas_modules() -> crate::PisPasResult<()> {
385 match TcpStream::connect(crate::CHANNEL_NAME) {
386 Ok(mut stream) => {
387 match stream.write_all(crate::service::Action::Stop.to_string().as_bytes()) {
388 Ok(_) => {
389 tracing::info!("Message sent: {}", crate::service::Action::Stop.to_string());
390 return Ok(());
391 }
392 Err(e) => {
393 tracing::error!("Failed to write to socket in dedicated thread {}", e);
394 return Err(anyhow::anyhow!("Failed to write to socket in dedicated thread {}", e));
395 }
396 }
397 }
398 Err(e) => {
399 tracing::error!("Error connecting to pispas-channel: {}", e);
400 }
401 }
402 sleep(std::time::Duration::from_secs(1));
403 Ok(())
404}
405
406pub fn launch_tray_icon() -> Result<(), Box<dyn std::error::Error>> {
407
408
409 let tray_string = crate::paths::tray_icon_path().display().to_string();
410
411
412 #[cfg(target_os = "windows")]
413 if let Err(err) = crate::natives::api::run_in_all_sessions(&tray_string, "", false, false) {
414 tracing::error!("Error launching tray icon: {} for all users", err);
415 }
416 #[cfg(not(target_os = "windows"))]
417 {
418 if let Err(err) = crate::natives::api::run_in_all_sessions(&tray_string, "", None, None) {
419 tracing::error!("Error launching tray icon: {} for all users", err);
420 }
421 }
422
423 sleep(std::time::Duration::from_secs(1));
424
425 Ok(())
426}