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