summaryrefslogtreecommitdiffstats
path: root/src/main.rs
blob: 1d96b4698c6480e7f79cef0c672dcd225d593443 (plain)
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#![allow(warnings)]

extern crate ipfs_api;
extern crate chrono;
extern crate mime;
extern crate futures;
extern crate serde;
extern crate serde_json;
extern crate uuid;
extern crate clap;
extern crate toml;
extern crate config;
extern crate hyper;
extern crate env_logger;
extern crate itertools;
extern crate xdg;
extern crate handlebars;
extern crate web_view;
extern crate actix_rt;
extern crate actix_web;
extern crate failure;
extern crate pidlock;

#[macro_use] extern crate anyhow;
#[macro_use] extern crate is_match;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate log;
#[macro_use] extern crate tokio;
#[macro_use] extern crate add_getters_setters;
#[macro_use] extern crate structopt;

mod app;
mod cli;
mod configuration;
mod repository;
mod types;
mod version;

use std::collections::BTreeMap;
use std::str::FromStr;
use std::ops::Deref;
use std::sync::Arc;
use std::path::PathBuf;

use chrono::NaiveDateTime;
use futures::future::Future;
use futures::future::FutureExt;
use futures::future::TryFutureExt;
use serde_json::to_string_pretty as serde_json_to_string_pretty;
use serde_json::from_str as serde_json_from_str;
use anyhow::Result;
use anyhow::Error;
use actix_web::{web, HttpResponse, Responder};

use crate::app::App;
use crate::cli::*;
use crate::configuration::Configuration;
use crate::repository::repository::Repository;
use crate::types::block::Block;
use crate::types::content::Content;
use crate::types::payload::Payload;
use crate::types::util::IPFSHash;
use crate::types::util::IPNSHash;
use crate::types::util::MimeType;
use crate::types::util::Timestamp;
use crate::types::util::Version;

use std::process::exit;

fn start_server(cli: &CLI) -> bool {
    cli.cmd().map(|cmd| Command::Server == *cmd).unwrap_or(false)
}

#[actix_rt::main]
async fn main() -> Result<()> {
    let cli = cli()?;
    let _ = env_logger::init();
    debug!("Logger initialized");

    let config_file_name = PathBuf::from("distrox.toml");
    let config: Configuration = {
        let configfile = xdg::BaseDirectories::with_prefix("distrox")?
            .find_config_file(&config_file_name)
            .ok_or_else(|| anyhow!("No configuration found"))?;

        let configstr = ::std::fs::read_to_string(&configfile)?;
        ::toml::from_str(&configstr)?
    };

    let port = cli.port().unwrap_or_else(|| *config.get_app_port());
    let adr = format!("127.0.0.1:{}", port);

    if start_server(&cli) {
        let mut lock = pidlock::Pidlock::new("/tmp/distrox_server.pid");
        if *lock.state() == pidlock::PidlockState::Acquired {
            // We assume that the server is already running
            info!("Assuming that the server is already running. Doing nothing.");
            return Ok(())
        }

        info!("Starting server");
        let _ = lock.acquire().map_err(|_| anyhow!("Error while getting the PID lock"))?;

        info!("Got PID lock for server");
        actix_web::HttpServer::new(|| {
            actix_web::App::new()
                .service(actix_web::web::resource("/{name}/{id}/index.html").to(index))
        })
        .bind(adr.clone())
        .expect(&format!("Could not bind to address {}", adr))
        .run()
        .await;

        info!("Server shutdown");
        info!("Releasing PID lock for server");
        lock.release().map_err(|_| anyhow!("Error while releasing the PID lock"))
    } else {
        let app = {
            let device_name = config.get_device_name();
            let device_key  = config.get_device_key();

            if let (Some(name), Some(key)) = (device_name, device_key) {
                let name        = IPNSHash::from(name.clone());
                let key         = key.clone();
                let api_url     = config.get_api_url().clone();
                let api_port    = config.get_api_port().clone();

                App::load(name, key, &api_url, api_port)
            } else {
                // ask user for name(s)
                // boot repository
                // load App object
                unimplemented!()
            }
        };

        let webview_content = web_view::Content::Url(adr.clone());

        web_view::builder()
            .title("My Project")
            .content(webview_content)
            .resizable(true)
            .debug(true)
            .user_data(())
            .invoke_handler(|_webview, _arg| Ok(()))
            .build()
            .map_err(Error::from)?
            .run()
            .map_err(Error::from)
    }
}

async fn index() -> impl Responder {
   HttpResponse::Ok()
}