mj_controller/database/
mounts.rs1use super::*;
2
3pub fn remember_mount_sources(host: &str, mounts: &[AdditionalMount]) -> Result<()> {
5 if mounts.is_empty() {
6 return Ok(());
7 }
8 let host = host.to_owned();
9 let sources = mounts
10 .iter()
11 .map(|mount| mount.source.clone())
12 .collect::<Vec<_>>();
13 submit_database_write("remember_mount_sources", move |_| {
14 remember_sources(&database_path(), &host, sources)
15 })
16}
17
18pub fn replace_mount_history(host: &str, sources: &[PathBuf]) -> Result<()> {
19 let host = host.to_owned();
20 let sources = sources.to_vec();
21 submit_database_write("replace_mount_history", move |_| {
22 replace_mount_history_in(&database_path(), &host, &sources)
23 })
24}
25
26pub(super) fn replace_mount_history_in(path: &Path, host: &str, sources: &[PathBuf]) -> Result<()> {
27 let mut connection = open(path)?;
28 let tx = connection.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?;
29 write_mount_history(&tx, host, sources)?;
30 tx.commit()?;
31 Ok(())
32}
33
34pub(super) fn write_mount_history(
35 tx: &Transaction<'_>,
36 host: &str,
37 sources: &[PathBuf],
38) -> Result<()> {
39 tx.execute("DELETE FROM mount_history WHERE host = ?1", [host])?;
40 let mut written = Vec::new();
41 for source in sources.iter().take(20) {
42 if written.contains(source) {
43 continue;
44 }
45 tx.execute(
46 "INSERT INTO mount_history(host, source, ordinal) VALUES (?1, ?2, ?3)",
47 params![host, path_to_blob(source), written.len() as i64],
48 )?;
49 written.push(source.clone());
50 }
51 Ok(())
52}
53
54pub(super) fn write_host_container_size(
55 tx: &Transaction<'_>,
56 host: &str,
57 size: HostContainerSize,
58) -> Result<()> {
59 ensure!(!host.trim().is_empty(), "container size host is empty");
60 let cpus = i64::try_from(size.cpus).context("container CPU count exceeds SQLite range")?;
61 let memory =
62 i64::try_from(size.memory_bytes).context("container memory exceeds SQLite range")?;
63 ensure!(
64 cpus > 0 && memory > 0,
65 "container size values must be positive"
66 );
67 tx.execute(
68 "INSERT INTO host_container_sizes(host, cpus, memory_bytes)
69 VALUES (?1, ?2, ?3)
70 ON CONFLICT(host) DO UPDATE SET cpus = excluded.cpus, memory_bytes = excluded.memory_bytes",
71 params![host, cpus, memory],
72 )?;
73 Ok(())
74}
75
76pub fn remember_project_directory(host: &str, directory: &Path) -> Result<()> {
77 let host = format!("project:{host}");
78 let directory = directory.to_path_buf();
79 submit_database_write("remember_project_directory", move |_| {
80 remember_sources(&database_path(), &host, std::iter::once(directory))
81 })
82}
83
84pub(super) fn remember_sources(
85 path: &Path,
86 host: &str,
87 new_sources: impl IntoIterator<Item = PathBuf>,
88) -> Result<()> {
89 let mut connection = open(path)?;
90 let tx = connection.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?;
91 let mut sources = {
92 let mut statement =
93 tx.prepare("SELECT source FROM mount_history WHERE host = ?1 ORDER BY ordinal")?;
94 statement
95 .query_map([host], |row| Ok(blob_to_path(row.get_ref(0)?.as_blob()?)))?
96 .collect::<rusqlite::Result<Vec<_>>>()?
97 };
98 let additions = new_sources.into_iter().collect::<Vec<_>>();
99 for source in additions.iter().rev() {
100 sources.retain(|existing| existing != source);
101 sources.insert(0, source.clone());
102 }
103 sources.truncate(20);
104 write_mount_history(&tx, host, &sources)?;
105 tx.commit()?;
106 Ok(())
107}