lb_fs/
lib.rs

1use crate::fs_impl::Drive;
2use crate::mount::{mount, umount};
3use cli_rs::cli_error::{CliError, CliResult};
4use lb_rs::model::core_config::Config;
5use lb_rs::service::sync::SyncProgress;
6use lb_rs::{Lb, Uuid};
7use nfs3_server::tcp::{NFSTcp, NFSTcpListener};
8use std::io;
9use std::io::IsTerminal;
10use std::process::exit;
11use std::sync::Arc;
12use std::time::Duration;
13use tracing::info;
14
15pub mod cache;
16pub(crate) mod file_handle;
17pub mod fs_impl;
18pub mod logger;
19pub mod mount;
20pub mod utils;
21
22impl Drive {
23    pub async fn init() -> Self {
24        let lb = Lb::init(Config {
25            writeable_path: Config::writeable_path("drive"),
26            background_work: false,
27            logs: false,
28            stdout_logs: false,
29            colored_logs: false,
30        })
31        .await
32        .unwrap();
33
34        let root = lb.root().await.map(|file| file.id).unwrap_or(Uuid::nil());
35
36        let data = Arc::default();
37
38        Self { lb, root, data }
39    }
40
41    pub async fn import() -> CliResult<()> {
42        let drive = Self::init().await;
43
44        if io::stdin().is_terminal() {
45            return Err(CliError::from("to import an existing lockbook account, pipe your account string into this command, e.g.:\npbpaste | lb-fs import".to_string()));
46        }
47
48        let mut account_string = String::new();
49        io::stdin()
50            .read_line(&mut account_string)
51            .expect("failed to read from stdin");
52        account_string.retain(|c| !c.is_whitespace());
53
54        println!("importing account...");
55        drive
56            .lb
57            .import_account(&account_string, None)
58            .await
59            .unwrap();
60
61        drive.lb.sync(Self::progress()).await.unwrap();
62
63        Ok(())
64    }
65
66    pub async fn mount() -> CliResult<()> {
67        let drive = Self::init().await;
68        drive.prepare_caches().await;
69        info!("registering sig handler");
70
71        // capture ctrl_c and try to cleanup
72        tokio::spawn(async move {
73            tokio::signal::ctrl_c().await.unwrap();
74            umount().await;
75            info!("cleaned up, goodbye!");
76            exit(0);
77        });
78
79        // sync periodically in the background
80        let syncer = drive.clone();
81        tokio::spawn(async move {
82            loop {
83                info!("will sync in 5 minutes");
84                tokio::time::sleep(Duration::from_secs(300)).await;
85                info!("syncing");
86                syncer.sync().await;
87            }
88        });
89
90        // todo have a better port selection strategy
91        info!("creating server");
92        let listener = NFSTcpListener::bind("127.0.0.1:11111", drive)
93            .await
94            .unwrap();
95
96        info!("mounting");
97        mount();
98
99        info!("ready");
100        listener.handle_forever().await.unwrap();
101        Ok(())
102    }
103
104    pub fn progress() -> Option<Box<dyn Fn(SyncProgress) + Send>> {
105        Some(Box::new(|status| println!("{status}")))
106    }
107}