Skip to main content

flams_system/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2//#![feature(file_buffered)]
3//#![feature(lazy_type_alias)]
4
5pub mod backend;
6//pub mod formats;
7pub mod building;
8#[cfg(feature = "tokio")]
9pub mod logging;
10pub mod settings;
11pub use flams_math_archives::FlamsExtension;
12
13pub fn span_capture<R>(f: impl FnOnce() -> R) -> (String, R) {
14    use tracing_subscriber::{fmt, layer::SubscriberExt};
15    #[derive(Clone)]
16    struct Buffer(std::sync::Arc<std::sync::Mutex<Vec<u8>>>);
17    impl std::io::Write for &Buffer {
18        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
19            if let Ok(mut l) = self.0.lock() {
20                l.extend_from_slice(buf);
21            }
22            Ok(buf.len())
23        }
24        #[inline]
25        fn flush(&mut self) -> std::io::Result<()> {
26            Ok(())
27        }
28    }
29    impl<'a> fmt::MakeWriter<'a> for Buffer {
30        type Writer = &'a Self;
31        #[inline]
32        fn make_writer(&'a self) -> Self::Writer {
33            self
34        }
35    }
36    let buffer = Buffer(std::sync::Arc::new(std::sync::Mutex::new(Vec::<u8>::new())));
37    let bufcl = buffer.clone();
38    let sub = tracing_subscriber::registry().with(
39        fmt::layer()
40            .with_writer(bufcl)
41            .with_ansi(false)
42            .with_filter(tracing_subscriber::filter::LevelFilter::INFO),
43    );
44    let ret = tracing::subscriber::with_default(sub, f);
45    let s = buffer
46        .0
47        .lock()
48        .map(|mut l| String::from_utf8_lossy(&std::mem::take(&mut *l)).into_owned())
49        .unwrap_or_default();
50    (s, ret)
51}
52
53#[cfg(feature = "zip")]
54pub mod zip;
55
56use building::queue_manager::QueueManager;
57use flams_math_archives::{utils::AsyncEngine, LocalArchive};
58use settings::SettingsSpec;
59
60pub use inventory::iter;
61pub use inventory::submit as register_exension;
62use tracing_subscriber::Layer;
63
64#[cfg(feature = "tokio")]
65pub struct TokioEngine;
66#[cfg(feature = "tokio")]
67impl AsyncEngine for TokioEngine {
68    fn background(f: impl FnOnce() + Send + 'static) {
69        let span = tracing::Span::current();
70        tokio::task::spawn_blocking(move || span.in_scope(f));
71    }
72    async fn block_on<R: Send + Sync + 'static>(
73        f: impl FnOnce() -> R + Send + Sync + 'static,
74    ) -> R {
75        tokio::task::spawn_blocking(f).await.expect("this is a bug")
76    }
77    fn exec_after(delay: std::time::Duration, f: impl FnOnce() + Send + 'static) {
78        tokio::task::spawn(async move {
79            tokio::time::sleep(delay).await;
80            f();
81        });
82    }
83}
84
85/// #### Panics
86pub fn initialize<A: AsyncEngine>(settings: SettingsSpec, rdf: bool) {
87    settings::Settings::initialize(settings);
88    let settings = settings::Settings::get();
89    #[cfg(feature = "rocksdb")]
90    if let Some(p) = &settings.rdf_database {
91        flams_math_archives::backend::set_global(p);
92    }
93    if settings.lsp {
94        use tracing::Level;
95        use tracing_subscriber::layer::SubscriberExt;
96        use tracing_subscriber::Layer;
97        #[cfg(feature = "tokio")]
98        let logger = logging::LogStore::new();
99        let debug = settings.debug;
100        let level = if debug { Level::TRACE } else { Level::INFO };
101
102        let l = tracing_subscriber::fmt::layer()
103            //.with_max_level(Level::INFO)//(if debug {Level::TRACE} else {Level::INFO})
104            .with_ansi(false)
105            .with_target(true)
106            .with_writer(std::io::stderr)
107            .with_filter(tracing::level_filters::LevelFilter::from(Level::INFO)); //.init();
108        #[cfg(feature = "tokio")]
109        let sub = tracing_subscriber::registry()
110            .with(logger.with_filter(tracing::level_filters::LevelFilter::from(level)))
111            .with(l);
112        #[cfg(not(feature = "tokio"))]
113        let sub = tracing_subscriber::registry().with(l);
114        tracing::subscriber::set_global_default(sub)
115            .expect("Failed to set global default logging subscriber");
116    } else {
117        #[cfg(feature = "tokio")]
118        logging::LogStore::initialize();
119    }
120    tracing::info_span!(target:"initializing",parent:None,"initializing").in_scope(move || {
121        #[cfg(feature = "gitlab")]
122        {
123            if let Some(url) = &settings.gitlab_url {
124                let cfg = flams_git::gl::GitlabConfig::new(
125                    url.clone(),
126                    settings.gitlab_token.as_ref().map(ToString::to_string),
127                    settings.gitlab_app_id.as_ref().map(ToString::to_string),
128                    settings.gitlab_app_secret.as_ref().map(ToString::to_string),
129                );
130                flams_git::gl::GLInstance::global().clone().load(cfg);
131            }
132        }
133        backend::initialize::<A>(rdf);
134        QueueManager::initialize(settings.num_threads);
135        for e in inventory::iter::<FlamsExtension>() {
136            A::background(|| {
137                tracing::info_span!("Initializing", extension = e.name).in_scope(|| (e.on_start)());
138            });
139        }
140    });
141}
142
143#[cfg(feature = "gitlab")]
144pub trait LocalArchiveExt {
145    fn is_managed(&self) -> Option<&flams_git::GitUrl>;
146}
147
148#[cfg(feature = "gitlab")]
149impl LocalArchiveExt for LocalArchive {
150    fn is_managed(&self) -> Option<&flams_git::GitUrl> {
151        let gl = crate::settings::Settings::get().gitlab_url.as_ref()?;
152        self.git_url(gl)
153    }
154}