Skip to content

Commit 91d97de

Browse files
committed
fix: copy bundled navigation data
1 parent 6821122 commit 91d97de

File tree

5 files changed

+157
-30
lines changed

5 files changed

+157
-30
lines changed

src/wasm/src/consts.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub const NAVIGATION_DATA_DEFAULT_LOCATION: &str = ".\\NavigationData";
2-
pub const NAVIGATION_DATA_DOWNLOADED_LOCATION: &str = "\\work/NavigationData";
2+
pub const NAVIGATION_DATA_WORK_LOCATION: &str = "\\work/NavigationData";
3+
pub const NAVIGATION_DATA_INTERNAL_CONFIG_LOCATION: &str = "\\work/navigraph_navigation_data_interface_config.json";

src/wasm/src/dispatcher.rs

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
functions::{CallFunction, FunctionResult, FunctionStatus, FunctionType},
1212
params,
1313
},
14-
meta,
14+
meta::{self, InternalState},
1515
network_helper::NetworkHelper,
1616
util::{self, path_exists},
1717
};
@@ -117,23 +117,73 @@ impl<'a> Dispatcher<'a> {
117117

118118
fn load_database(&mut self) {
119119
println!("[NAVIGRAPH] Loading database");
120-
// First check if we have a database in the downloaded location
121-
let found_downloaded = self
122-
.set_database_if_exists(consts::NAVIGATION_DATA_DOWNLOADED_LOCATION)
123-
.is_ok();
124120

125-
if found_downloaded {
126-
println!("[NAVIGRAPH] Loaded database from downloaded location");
127-
return;
121+
// Are we bundled? None means we haven't installed anything yet
122+
let is_bundled = meta::get_internal_state()
123+
.map(|internal_state| Some(internal_state.is_bundled))
124+
.unwrap_or(None);
125+
126+
// Get the installed cycle
127+
let installed_cycle = match meta::get_installed_cycle_from_json(
128+
&Path::new(consts::NAVIGATION_DATA_WORK_LOCATION).join("cycle.json"),
129+
) {
130+
Ok(cycle) => Some(cycle.cycle),
131+
Err(_) => None,
132+
};
133+
134+
// Get the bundled cycle
135+
let bundled_cycle = match meta::get_installed_cycle_from_json(
136+
&Path::new(consts::NAVIGATION_DATA_DEFAULT_LOCATION).join("cycle.json"),
137+
) {
138+
Ok(cycle) => Some(cycle.cycle),
139+
Err(_) => None,
140+
};
141+
142+
let bundled_updated = if is_bundled.is_some() && is_bundled.unwrap() {
143+
// If we are bundled, we need to check if the bundled cycle is newer than the installed cycle
144+
if installed_cycle.is_some() && bundled_cycle.is_some() {
145+
bundled_cycle.unwrap() > installed_cycle.unwrap()
146+
} else {
147+
false
148+
}
149+
} else {
150+
false
151+
};
152+
153+
let need_to_copy = is_bundled.is_none();
154+
155+
// If we are bundled and the installed cycle is older than the bundled cycle, we need to copy the bundled database to the work location. Or if we haven't installed anything yet, we need to copy the bundled database to the work location
156+
if bundled_updated || need_to_copy {
157+
// we need to copy to the work location
158+
match util::copy_files_to_folder(
159+
&Path::new(consts::NAVIGATION_DATA_DEFAULT_LOCATION),
160+
&Path::new(consts::NAVIGATION_DATA_WORK_LOCATION),
161+
) {
162+
Ok(_) => {
163+
let res = meta::set_internal_state(InternalState { is_bundled: true });
164+
if let Err(e) = res {
165+
println!("[NAVIGRAPH] Failed to set internal state: {}", e);
166+
}
167+
},
168+
Err(e) => {
169+
println!(
170+
"[NAVIGRAPH] Failed to copy database from default location to work location: {}",
171+
e
172+
);
173+
return;
174+
},
175+
}
128176
}
129177

130-
// If we didn't find a database in the downloaded location, check the default location
131-
let found_default = self
132-
.set_database_if_exists(consts::NAVIGATION_DATA_DEFAULT_LOCATION)
178+
// Finally, set the active database
179+
let found_work = self
180+
.set_database_if_exists(consts::NAVIGATION_DATA_WORK_LOCATION)
133181
.is_ok();
134182

135-
if !found_default {
136-
println!("[NAVIGRAPH] No database found in default location, not loading any database");
183+
if found_work {
184+
println!("[NAVIGRAPH] Loaded database");
185+
} else {
186+
println!("[NAVIGRAPH] Failed to load database");
137187
}
138188
}
139189

@@ -146,7 +196,7 @@ impl<'a> Dispatcher<'a> {
146196
}
147197

148198
fn on_download_finish(&mut self) {
149-
match navigation_database::util::find_sqlite_file(consts::NAVIGATION_DATA_DOWNLOADED_LOCATION) {
199+
match navigation_database::util::find_sqlite_file(consts::NAVIGATION_DATA_WORK_LOCATION) {
150200
Ok(path) => {
151201
match self.database.set_active_database(path) {
152202
Ok(_) => {},

src/wasm/src/download/downloader.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
dispatcher::{Dispatcher, Task, TaskStatus},
88
download::zip_handler::{BatchReturn, ZipFileHandler},
99
json_structs::{events, params},
10+
meta::{self, InternalState},
1011
};
1112

1213
pub struct DownloadOptions {
@@ -63,6 +64,11 @@ impl NavigationDataDownloader {
6364
borrowed_task.status = TaskStatus::Success(None);
6465
}
6566
self.download_status.replace(DownloadStatus::Downloaded);
67+
// Update the internal state
68+
let res = meta::set_internal_state(InternalState { is_bundled: false });
69+
if let Err(e) = res {
70+
println!("[NAVIGRAPH] Failed to set internal state: {}", e);
71+
}
6672
},
6773
Ok(BatchReturn::MoreFilesToDelete) => {
6874
self.download_status.replace(DownloadStatus::CleaningDestination);
@@ -181,7 +187,7 @@ impl NavigationDataDownloader {
181187
return;
182188
}
183189

184-
let path = PathBuf::from(consts::NAVIGATION_DATA_DOWNLOADED_LOCATION);
190+
let path = PathBuf::from(consts::NAVIGATION_DATA_WORK_LOCATION);
185191

186192
// Check the data from the request
187193
let data = request.data();

src/wasm/src/meta.rs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{
22
cell::RefCell,
3+
error::Error,
34
path::{Path, PathBuf},
45
rc::Rc,
56
};
@@ -13,7 +14,18 @@ use crate::{
1314
util::path_exists,
1415
};
1516

16-
#[derive(serde::Serialize, Clone, Copy, Debug)]
17+
#[derive(serde::Serialize, serde::Deserialize, Debug)]
18+
pub struct InternalState {
19+
pub is_bundled: bool,
20+
}
21+
22+
impl Default for InternalState {
23+
fn default() -> Self {
24+
Self { is_bundled: false }
25+
}
26+
}
27+
28+
#[derive(serde::Serialize, Clone, Copy, Debug, PartialEq, Eq)]
1729
pub enum InstallStatus {
1830
Bundled,
1931
Manual,
@@ -55,6 +67,26 @@ pub struct InstalledNavigationDataCycleInfo {
5567
pub validity_period: String,
5668
}
5769

70+
pub fn get_internal_state() -> Result<InternalState, Box<dyn Error>> {
71+
let config_path = Path::new(consts::NAVIGATION_DATA_INTERNAL_CONFIG_LOCATION);
72+
if !path_exists(&config_path) {
73+
return Err("Internal config file does not exist")?;
74+
}
75+
76+
let config_file = std::fs::File::open(config_path)?;
77+
let internal_state: InternalState = serde_json::from_reader(config_file)?;
78+
79+
Ok(internal_state)
80+
}
81+
82+
pub fn set_internal_state(internal_state: InternalState) -> Result<(), Box<dyn Error>> {
83+
let config_path = Path::new(consts::NAVIGATION_DATA_INTERNAL_CONFIG_LOCATION);
84+
let config_file = std::fs::File::create(config_path)?;
85+
serde_json::to_writer(config_file, &internal_state)?;
86+
87+
Ok(())
88+
}
89+
5890
pub fn start_network_request(task: Rc<RefCell<Task>>) {
5991
let request = NetworkHelper::make_request("https://navdata.api.navigraph.com/info", Method::Get, None, None);
6092
let request = match request {
@@ -67,6 +99,13 @@ pub fn start_network_request(task: Rc<RefCell<Task>>) {
6799
task.borrow_mut().associated_network_request = Some(request);
68100
}
69101

102+
pub fn get_installed_cycle_from_json(path: &Path) -> Result<InstalledNavigationDataCycleInfo, Box<dyn Error>> {
103+
let json_file = std::fs::File::open(path)?;
104+
let installed_cycle_info: InstalledNavigationDataCycleInfo = serde_json::from_reader(json_file)?;
105+
106+
Ok(installed_cycle_info)
107+
}
108+
70109
pub fn get_navigation_data_install_status(task: Rc<RefCell<Task>>) {
71110
let response_bytes = match task.borrow().associated_network_request.as_ref() {
72111
Some(request) => {
@@ -98,23 +137,26 @@ pub fn get_navigation_data_install_status(task: Rc<RefCell<Task>>) {
98137
};
99138

100139
// figure out install status
101-
let found_downloaded = path_exists(Path::new(consts::NAVIGATION_DATA_DOWNLOADED_LOCATION));
140+
let found_downloaded = path_exists(Path::new(consts::NAVIGATION_DATA_WORK_LOCATION));
102141

103-
let found_bundled = path_exists(Path::new(consts::NAVIGATION_DATA_DEFAULT_LOCATION));
142+
let found_bundled = get_internal_state()
143+
.map(|internal_state| internal_state.is_bundled)
144+
.unwrap_or(false);
104145

105-
let status = if found_downloaded {
106-
InstallStatus::Manual
107-
} else if found_bundled {
146+
// Check bundled first, as downloaded and bundled are both possible
147+
let status = if found_bundled {
108148
InstallStatus::Bundled
149+
} else if found_downloaded {
150+
InstallStatus::Manual
109151
} else {
110152
InstallStatus::None
111153
};
112154

113155
// Open JSON
114-
let json_path = match status {
115-
InstallStatus::Manual => Some(PathBuf::from(consts::NAVIGATION_DATA_DOWNLOADED_LOCATION).join("cycle.json")),
116-
InstallStatus::Bundled => Some(PathBuf::from(consts::NAVIGATION_DATA_DEFAULT_LOCATION).join("cycle.json")),
117-
InstallStatus::None => None,
156+
let json_path = if status != InstallStatus::None {
157+
Some(PathBuf::from(consts::NAVIGATION_DATA_WORK_LOCATION).join("cycle.json"))
158+
} else {
159+
None
118160
};
119161

120162
let installed_cycle_info = match json_path {
@@ -154,10 +196,10 @@ pub fn get_navigation_data_install_status(task: Rc<RefCell<Task>>) {
154196
Some(installed_cycle_info) => Some(installed_cycle_info.cycle.clone()),
155197
None => None,
156198
},
157-
install_path: match status {
158-
InstallStatus::Manual => Some(consts::NAVIGATION_DATA_DOWNLOADED_LOCATION.to_string()),
159-
InstallStatus::Bundled => Some(consts::NAVIGATION_DATA_DEFAULT_LOCATION.to_string()),
160-
InstallStatus::None => None,
199+
install_path: if status == InstallStatus::Manual {
200+
Some(consts::NAVIGATION_DATA_WORK_LOCATION.to_string())
201+
} else {
202+
None
161203
},
162204
validity_period: match &installed_cycle_info {
163205
Some(installed_cycle_info) => Some(installed_cycle_info.validity_period.clone()),

src/wasm/src/util.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,34 @@ pub fn delete_folder_recursively(path: &Path, batch_size: Option<usize>) -> io::
4949
Ok(())
5050
}
5151

52+
pub fn copy_files_to_folder(from: &Path, to: &Path) -> io::Result<()> {
53+
// Make sure we are copying a directory (and in turn that it exists)
54+
if get_path_type(from) != PathType::Directory {
55+
return Ok(());
56+
}
57+
// Let's clear the directory we are copying to
58+
delete_folder_recursively(to, None)?;
59+
// Create the directory we are copying to
60+
fs::create_dir(to)?;
61+
// Collect the entries that we will copy
62+
let entries = fs::read_dir(from)?.collect::<Result<Vec<_>, _>>()?;
63+
// Copy the entries
64+
for entry in entries {
65+
let path = entry.path();
66+
let path_type = get_path_type(&path);
67+
68+
if path_type == PathType::Directory {
69+
let new_dir = to.join(path.file_name().unwrap());
70+
fs::create_dir(&new_dir)?;
71+
copy_files_to_folder(&path, &new_dir)?;
72+
} else if path_type == PathType::File {
73+
fs::copy(&path, to.join(path.file_name().unwrap()))?;
74+
}
75+
}
76+
77+
Ok(())
78+
}
79+
5280
pub fn trim_null_terminator(s: &str) -> &str {
5381
s.trim_end_matches(char::from(0))
5482
}

0 commit comments

Comments
 (0)