tauri_plugin_stt/
paths.rs1use std::fs::create_dir_all;
5use std::path::PathBuf;
6use tauri::{AppHandle, Manager, Runtime};
7
8use crate::error::Error;
9
10const MODELS_SUBDIR: &str = "vosk-models";
12
13#[allow(dead_code)]
23pub fn get_models_dir<R: Runtime>(app: &AppHandle<R>) -> Result<PathBuf, Error> {
24 let base_path = app
25 .path()
26 .app_data_dir()
27 .map_err(|e| Error::ConfigError(format!("Could not determine app data directory: {e}")))?;
28
29 let full_path = base_path.join(MODELS_SUBDIR);
30
31 create_dir_all(&full_path).map_err(|e| {
32 Error::ConfigError(format!(
33 "Could not create models directory {}: {}",
34 full_path.display(),
35 e
36 ))
37 })?;
38
39 Ok(full_path)
40}
41
42#[allow(dead_code)]
48pub fn get_model_path<R: Runtime>(app: &AppHandle<R>, model_name: &str) -> Result<PathBuf, Error> {
49 validate_path(model_name)?;
50 let models_dir = get_models_dir(app)?;
51 Ok(models_dir.join(model_name))
52}
53
54#[allow(dead_code)]
56pub fn model_exists<R: Runtime>(app: &AppHandle<R>, model_name: &str) -> Result<bool, Error> {
57 let model_path = get_model_path(app, model_name)?;
58 Ok(model_path.exists() && model_path.is_dir())
59}
60
61#[allow(dead_code)]
63pub fn list_available_models<R: Runtime>(app: &AppHandle<R>) -> Result<Vec<String>, Error> {
64 let models_dir = get_models_dir(app)?;
65 let mut models = Vec::new();
66
67 if let Ok(entries) = std::fs::read_dir(&models_dir) {
68 for entry in entries.flatten() {
69 if let Ok(metadata) = entry.metadata() {
70 if metadata.is_dir() {
71 if let Some(name) = entry.file_name().to_str() {
72 models.push(name.to_string());
73 }
74 }
75 }
76 }
77 }
78
79 Ok(models)
80}
81
82#[allow(dead_code)]
84pub fn validate_path(path: &str) -> Result<(), Error> {
85 let path_buf = PathBuf::from(path);
86
87 for component in path_buf.components() {
88 if let std::path::Component::ParentDir = component {
89 return Err(Error::ConfigError(
90 "Path traversal not allowed (contains '..')".to_string(),
91 ));
92 }
93 }
94
95 Ok(())
96}