headless_lms_server/
lib.rs

1/*!
2The server that handles the requests.
3
4## See also
5
6* [headless_lms_utils]
7* [headless_lms_models]
8*/
9
10pub mod config;
11pub mod controllers;
12pub mod domain;
13pub mod prelude;
14
15pub mod programs;
16#[cfg(test)]
17pub mod test_helper;
18#[cfg(all(test, feature = "ts_rs"))]
19pub mod ts_binding_generator;
20
21#[macro_use]
22extern crate tracing;
23
24#[macro_use]
25extern crate doc_macro;
26
27use anyhow::Result;
28use headless_lms_utils::file_store::{
29    FileStore, google_cloud_file_store::GoogleCloudFileStore, local_file_store::LocalFileStore,
30};
31use oauth2::{EndpointNotSet, EndpointSet};
32use std::{env, sync::Arc};
33use tracing_error::ErrorLayer;
34use tracing_log::LogTracer;
35use tracing_subscriber::{EnvFilter, layer::SubscriberExt};
36
37pub type OAuthClient = oauth2::basic::BasicClient<
38    EndpointSet,
39    EndpointNotSet,
40    EndpointNotSet,
41    EndpointNotSet,
42    EndpointSet,
43>;
44
45/**
46Sets up tokio tracing. Also makes sure that log statements from libraries respect the log level
47settings that have been set with RUST_LOG, for example:
48
49```no_run
50use std::env;
51unsafe {
52    env::set_var("RUST_LOG", "info,actix_web=info,sqlx=warn");
53}
54```
55*/
56pub fn setup_tracing() -> Result<()> {
57    let subscriber = tracing_subscriber::Registry::default()
58        .with(
59            tracing_subscriber::fmt::layer()
60                .event_format(tracing_subscriber::fmt::format().compact()),
61        )
62        .with(ErrorLayer::default())
63        .with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")));
64    tracing::subscriber::set_global_default(subscriber)?;
65    LogTracer::init()?;
66    Ok(())
67}
68
69/**
70Setups file store so that it can be passed to actix web as data.
71Using Arc here so that this can be accessed from all the different worker threads.
72*/
73pub fn setup_file_store() -> Arc<dyn FileStore + Send + Sync> {
74    if env::var("FILE_STORE_USE_GOOGLE_CLOUD_STORAGE").is_ok() {
75        info!("Using Google Cloud Storage as the file store");
76        let bucket_name = env::var("GOOGLE_CLOUD_STORAGE_BUCKET_NAME").expect("env FILE_STORE_USE_GOOGLE_CLOUD_STORAGE was defined but GOOGLE_CLOUD_STORAGE_BUCKET_NAME was not.");
77        Arc::new(GoogleCloudFileStore::new(bucket_name).expect("Failed to initialize file store"))
78    } else {
79        info!("Using local file storage as the file store");
80        Arc::new(
81            LocalFileStore::new(
82                "uploads".into(),
83                "http://project-331.local/api/v0/files/uploads/".into(),
84            )
85            .expect("Failed to initialize file store"),
86        )
87    }
88}
89
90/// Includes the type's JSON example and/or TypeScript definition
91/// generated by doc-file-generator as a string.
92/// Used with the helper macro from the doc-macro crate: #[generated_doc]
93#[macro_export]
94macro_rules! generated_docs {
95    ($t: expr_2021, ts) => {
96        concat!(
97            "## Response TypeScript definition\n",
98            "```ts\n",
99            include_str!(concat!(
100                env!("CARGO_MANIFEST_DIR"),
101                "/generated-docs/",
102                stringify!($t),
103                ".ts"
104            )),
105            "\n```\n",
106        )
107    };
108    ($t: expr_2021, json) => {
109        concat!(
110            "## Example response\n",
111            "```json\n",
112            include_str!(concat!(
113                env!("CARGO_MANIFEST_DIR"),
114                "/generated-docs/",
115                stringify!($t),
116                ".json"
117            )),
118            "\n```\n",
119        )
120    };
121    ($t: expr_2021) => {
122        concat!(generated_docs!($t, ts), generated_docs!($t, json),)
123    };
124}