1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*!
The server that handles the requests.

## See also

* [headless_lms_utils]
* [headless_lms_models]
*/

pub mod config;
pub mod controllers;
pub mod domain;
pub mod prelude;

pub mod programs;
#[cfg(test)]
pub mod test_helper;
#[cfg(all(test, feature = "ts_rs"))]
pub mod ts_binding_generator;

#[macro_use]
extern crate tracing;

#[macro_use]
extern crate doc_macro;

use anyhow::Result;
use headless_lms_utils::file_store::{
    google_cloud_file_store::GoogleCloudFileStore, local_file_store::LocalFileStore, FileStore,
};
use oauth2::basic::BasicClient;
use std::{env, sync::Arc};
use tracing_error::ErrorLayer;
use tracing_log::LogTracer;
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};

pub type OAuthClient = BasicClient;

/**
Sets up tokio tracing. Also makes sure that log statements from libraries respect the log level
settings that have been set with RUST_LOG, for example:

```no_run
use std::env;
env::set_var("RUST_LOG", "info,actix_web=info,sqlx=warn");
```
*/
pub fn setup_tracing() -> Result<()> {
    let subscriber = tracing_subscriber::Registry::default()
        .with(
            tracing_subscriber::fmt::layer()
                .event_format(tracing_subscriber::fmt::format().compact()),
        )
        .with(ErrorLayer::default())
        .with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")));
    tracing::subscriber::set_global_default(subscriber)?;
    LogTracer::init()?;
    Ok(())
}

/**
Setups file store so that it can be passed to actix web as data.
Using Arc here so that this can be accessed from all the different worker threads.
*/
pub fn setup_file_store() -> Arc<dyn FileStore + Send + Sync> {
    if env::var("FILE_STORE_USE_GOOGLE_CLOUD_STORAGE").is_ok() {
        info!("Using Google Cloud Storage as the file store");
        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.");
        Arc::new(GoogleCloudFileStore::new(bucket_name).expect("Failed to initialize file store"))
    } else {
        info!("Using local file storage as the file store");
        Arc::new(
            LocalFileStore::new(
                "uploads".into(),
                "http://project-331.local/api/v0/files/uploads/".into(),
            )
            .expect("Failed to initialize file store"),
        )
    }
}

/// Includes the type's JSON example and/or TypeScript definition
/// generated by doc-file-generator as a string.
/// Used with the helper macro from the doc-macro crate: #[generated_doc]
#[macro_export]
macro_rules! generated_docs {
    ($t: expr, ts) => {
        concat!(
            "## Response TypeScript definition\n",
            "```ts\n",
            include_str!(concat!(
                env!("CARGO_MANIFEST_DIR"),
                "/generated-docs/",
                stringify!($t),
                ".ts"
            )),
            "\n```\n",
        )
    };
    ($t: expr, json) => {
        concat!(
            "## Example response\n",
            "```json\n",
            include_str!(concat!(
                env!("CARGO_MANIFEST_DIR"),
                "/generated-docs/",
                stringify!($t),
                ".json"
            )),
            "\n```\n",
        )
    };
    ($t: expr) => {
        concat!(generated_docs!($t, ts), generated_docs!($t, json),)
    };
}