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 tokio::time;
14use tracing::{error, info};
15
16pub mod cache;
17pub(crate) mod file_handle;
18pub mod fs_impl;
19pub mod logger;
20pub mod mount;
21pub mod utils;
22
23impl Drive {
24 pub async fn init() -> Self {
25 let lb = Lb::init(Config {
26 writeable_path: Config::writeable_path("drive"),
27 background_work: false,
28 logs: false,
29 stdout_logs: false,
30 colored_logs: false,
31 })
32 .await
33 .unwrap();
34
35 logger::init();
36
37 let root = lb.root().await.map(|file| file.id).unwrap_or(Uuid::nil());
38
39 let data = Arc::default();
40
41 Self { lb, root, data }
42 }
43
44 pub async fn import() -> CliResult<()> {
45 let drive = Self::init().await;
46
47 if io::stdin().is_terminal() {
48 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()));
49 }
50
51 let mut account_string = String::new();
52 io::stdin()
53 .read_line(&mut account_string)
54 .expect("failed to read from stdin");
55 account_string.retain(|c| !c.is_whitespace());
56
57 println!("importing account...");
58 drive
59 .lb
60 .import_account(&account_string, None)
61 .await
62 .unwrap();
63
64 drive.lb.sync(Self::progress()).await.unwrap();
65
66 Ok(())
67 }
68
69 pub async fn mount() -> CliResult<()> {
70 let drive = Self::init().await;
71 drive.prepare_caches().await;
72 info!("registering sig handler");
73
74 tokio::spawn(async move {
76 tokio::signal::ctrl_c().await.unwrap();
77 let mut unmount_success = umount().await;
78 while !unmount_success {
79 error!("unmount failed, please close any apps using lb-fs! Retrying in 1s.");
80 time::sleep(Duration::from_secs(1)).await;
81 unmount_success = umount().await;
82 }
83 info!("cleaned up, goodbye!");
84 exit(0);
85 });
86
87 let syncer = drive.clone();
89 tokio::spawn(async move {
90 loop {
91 info!("will sync in 30 seconds");
92 tokio::time::sleep(Duration::from_secs(30)).await;
93 info!("syncing");
94 syncer.sync().await;
95 }
96 });
97
98 info!("creating server");
100 let listener = NFSTcpListener::bind("127.0.0.1:11111", drive)
101 .await
102 .unwrap();
103
104 info!("mounting");
105 mount();
106
107 info!("ready");
108 listener.handle_forever().await.unwrap();
109 Ok(())
110 }
111
112 pub fn progress() -> Option<Box<dyn Fn(SyncProgress) + Send>> {
113 Some(Box::new(|status| println!("{status}")))
114 }
115}