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 nfsserve::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 mod fs_impl;
17pub mod logger;
18pub mod mount;
19pub mod utils;
20
21impl Drive {
22    pub async fn init() -> Self {
23        let lb = Lb::init(Config::cli_config("drive")).await.unwrap();
24
25        let root = lb.root().await.map(|file| file.id).unwrap_or(Uuid::nil());
26
27        let data = Arc::default();
28
29        Self { lb, root, data }
30    }
31
32    pub async fn import() -> CliResult<()> {
33        let drive = Self::init().await;
34
35        if io::stdin().is_terminal() {
36            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()));
37        }
38
39        let mut account_string = String::new();
40        io::stdin()
41            .read_line(&mut account_string)
42            .expect("failed to read from stdin");
43        account_string.retain(|c| !c.is_whitespace());
44
45        println!("importing account...");
46        drive
47            .lb
48            .import_account(&account_string, None)
49            .await
50            .unwrap();
51
52        drive.lb.sync(Self::progress()).await.unwrap();
53
54        Ok(())
55    }
56
57    pub async fn mount() -> CliResult<()> {
58        let drive = Self::init().await;
59        drive.prepare_caches().await;
60        info!("registering sig handler");
61
62        // capture ctrl_c and try to cleanup
63        tokio::spawn(async move {
64            tokio::signal::ctrl_c().await.unwrap();
65            umount().await;
66            info!("cleaned up, goodbye!");
67            exit(0);
68        });
69
70        // sync periodically in the background
71        let syncer = drive.clone();
72        tokio::spawn(async move {
73            loop {
74                info!("will sync in 5 minutes");
75                tokio::time::sleep(Duration::from_secs(300)).await;
76                info!("syncing");
77                syncer.sync().await;
78            }
79        });
80
81        // todo have a better port selection strategy
82        info!("creating server");
83        let listener = NFSTcpListener::bind("127.0.0.1:11111", drive)
84            .await
85            .unwrap();
86
87        info!("mounting");
88        mount();
89
90        info!("ready");
91        listener.handle_forever().await.unwrap();
92        Ok(())
93    }
94
95    pub fn progress() -> Option<Box<dyn Fn(SyncProgress) + Send>> {
96        Some(Box::new(|status| println!("{status}")))
97    }
98}