This repository has been archived by the owner on Sep 26, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.rs
123 lines (109 loc) · 3.6 KB
/
main.rs
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
#[macro_use]
extern crate clap;
#[macro_use]
extern crate serde_derive;
extern crate actix_web;
use actix_web::actix::{Actor, Addr, System};
use actix_web::{http, middleware, server, App, Binary, FromRequest, HttpRequest, Responder};
use futures::future::Future;
use handlers::{CatFile, GitRepos};
use std::path::Path;
const DEFAULT_PORT: &str = "7791";
const DEFAULT_HOST: &str = "localhost";
const DEFAULT_REPO_ROOT: &str = "./";
const DEFAULT_REFERENCE: &str = "heads/master";
fn main() {
let args = parse_args().get_matches();
let host = args.value_of("host").unwrap_or(DEFAULT_HOST);
let port = args.value_of("port").unwrap_or(DEFAULT_PORT);
let repo_root = Path::new(args.value_of("repo-root").unwrap_or(DEFAULT_REPO_ROOT));
run_server(host, port, repo_root);
}
#[derive(Deserialize)]
pub struct PathParams {
pub repo: String,
}
#[derive(Deserialize)]
pub struct QueryParams {
pub reference: Option<String>,
pub file: String,
}
pub struct AppState {
pub git_repos: Addr<GitRepos>,
}
fn run_server(host: &str, port: &str, repo_root: &Path) {
let _sys = System::new("gitkv-server");
let addr = GitRepos::new(git::load_repos(&repo_root)).start();
let listen_address = format!("{}:{}", host, port);
server::new(move || {
App::with_state(AppState {
git_repos: addr.clone(),
})
.middleware(middleware::Logger::default())
.resource("/repo/{repo}", |r| r.method(http::Method::GET).f(get_repo))
})
.bind(listen_address)
.expect("can't bind into address")
.run();
}
fn get_repo(req: &HttpRequest<AppState>) -> impl Responder {
//TODO https://actix.rs/docs/errors/
let path_params = actix_web::Path::<PathParams>::extract(req).expect("Wrong path params");
let query_params = actix_web::Query::<QueryParams>::extract(req).expect("Wrong query params");
let repo_key = path_params.repo.clone();
let filename = query_params.file.clone();
let reference = format!(
"refs/{}",
query_params
.reference
.as_ref()
.map(String::as_str)
.unwrap_or(DEFAULT_REFERENCE)
);
let gr: &Addr<GitRepos> = &req.state().git_repos;
//TODO return proper content type depending on the content of the blob
gr.send(CatFile {
repo_key,
filename,
reference,
})
.map(|x| {
x.0.map(Binary::from)
.map_err(|e| actix_web::error::InternalError::new(e, http::StatusCode::NOT_FOUND))
})
//TODO don't wait and return the future itself
.wait()
}
fn parse_args<'a, 'b>() -> clap::App<'a, 'b> {
clap::App::new(crate_name!())
.version(crate_version!())
.author(crate_authors!("\n"))
.about(crate_description!())
.arg(
clap::Arg::with_name("port")
.short("p")
.long("port")
.takes_value(true)
.value_name("PORT")
.default_value(DEFAULT_PORT)
.help("port to listen to"),
)
.arg(
clap::Arg::with_name("host")
.short("h")
.long("host")
.takes_value(true)
.value_name("HOST")
.default_value(DEFAULT_HOST)
.help("host to listen to"),
)
.arg(
clap::Arg::with_name("repo-root")
.short("r")
.long("repo-root")
.takes_value(true)
.value_name("PATH")
.default_value(DEFAULT_REPO_ROOT)
.help("path where the different repositories are located"),
)
}