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
//! # Minerva System: SESSION Service
//!
//! ## About this service
//! This service's responsibility is to provide a means for managing user
//! authentication, especially user sessions. Through this module, an existing
//! user can start a session on the system so that it becomes possible to
//! perform certain other operations.
//!
//! This service does not manage user data, but should have direct access to
//! both databases so that it can check authentication data and create the
//! actual session data, which is stored and managed server-side.

#![warn(clippy::all)]
#![warn(missing_docs)]

use dotenv::dotenv;
use log::{debug, info};
use minerva_cache as cache;
use minerva_data::{db, mongo};
use minerva_rpc::session::session_server::SessionServer;
use std::collections::HashMap;
use std::env;
use tonic::transport::Server;

mod repository;
mod service;

#[cfg(test)]
mod tests;

/// Entry point for this module.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Minerva System: SESSION service");
    println!("Copyright (c) 2022 Lucas S. Vieira");
    println!();

    dotenv().ok();

    let logconfig = env::var("LOG_CONFIG_FILE").unwrap_or_else(|_| "./logging.yml".to_owned());

    match log4rs::init_file(logconfig, Default::default()) {
        Ok(_) => info!("Log system initialized."),
        Err(e) => eprintln!(
            "Failure while initializing logs: {:?}\n\
			     You might be flying solo now.",
            e
        ),
    }

    let port = env::var("SESSION_SERVICE_PORT").expect("Unable to read SESSION_SERVICE_PORT");
    let dbserver =
        env::var("DATABASE_SERVICE_SERVER").expect("Unable to read DATABASE_SERVICE_SERVER");
    let mongoserver =
        env::var("MONGO_SERVICE_SERVER").expect("Unable to read MONGO_SERVICE_SERVER");
    let redisserver =
        env::var("REDIS_SERVICE_SERVER").expect("Unable to read REDIS_SERVICE_SERVER");

    let mut pools = HashMap::new();
    let mongo = mongo::make_client(&mongoserver).await;
    let redis = cache::build_client(&redisserver).expect("Unable to create Redis client");
    for tenant in minerva_data::tenancy::get_tenants("tenancy.toml") {
        let pool = db::make_connection_pool(&tenant.database, &dbserver, tenant.connections).await;
        pools.insert(
            tenant.database.clone(),
            (pool, mongo.clone(), redis.clone()),
        );
        debug!(
            "Added database connections for tenant {} ({} connections + 1 MongoDB client + 1 Redis client).",
            tenant.name, tenant.connections
        );
    }

    let addr = format!("0.0.0.0:{}", port).parse()?;

    info!("Starting SESSION on {}...", addr);

    let server = Server::builder()
        .add_service(SessionServer::new(service::SessionService { pools }))
        .serve(addr);

    info!("SESSION is ready to accept connections.");
    server.await?;
    info!("SESSION shut down.");
    Ok(())
}