174 lines
4.5 KiB
Rust
174 lines
4.5 KiB
Rust
use std::convert::TryFrom;
|
|
use std::net::SocketAddr;
|
|
use std::path::PathBuf;
|
|
use std::str::FromStr;
|
|
use std::sync::Arc;
|
|
|
|
use warp::Filter;
|
|
|
|
use structopt::StructOpt;
|
|
|
|
use tokio::net::UnixListener;
|
|
|
|
use geoffrey_models::logging::LogLevel;
|
|
use geoffrey_models::models::parameters::add_token_params::AddTokenParams;
|
|
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
|
|
use geoffrey_models::models::token::Permissions;
|
|
|
|
use crate::commands::add_token::AddToken;
|
|
use crate::commands::{command_filter, Command};
|
|
use crate::config::GeoffreyAPIConfig;
|
|
use crate::context::Context;
|
|
use crate::logging::init_logging;
|
|
use crate::model::{local_model_filter, remote_model_filter};
|
|
use tokio_stream::wrappers::UnixListenerStream;
|
|
|
|
mod api_endpoint;
|
|
mod commands;
|
|
mod config;
|
|
mod context;
|
|
mod helper;
|
|
mod logging;
|
|
mod model;
|
|
|
|
pub type Result<T> = std::result::Result<T, GeoffreyAPIError>;
|
|
|
|
#[derive(Debug, StructOpt, Clone, Default)]
|
|
#[structopt(name = "GeoffreyAPI", about = "Geoffrey Central API")]
|
|
pub struct Args {
|
|
#[structopt(env = "GEOFFREY_CONFIG", parse(from_os_str))]
|
|
config: PathBuf,
|
|
#[structopt(
|
|
short,
|
|
long,
|
|
env = "GEOFFREY_LOG_LEVEL",
|
|
parse(from_str),
|
|
default_value = "Info"
|
|
)]
|
|
log_level: LogLevel,
|
|
|
|
#[structopt(short, long)]
|
|
force_migration: bool,
|
|
|
|
#[structopt(subcommand)]
|
|
command: GeoffreyApiCommand,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, StructOpt, Clone)]
|
|
pub enum GeoffreyApiCommand {
|
|
Run,
|
|
CreateAdminToken(CreateTokenCommand),
|
|
}
|
|
|
|
impl Default for GeoffreyApiCommand {
|
|
fn default() -> Self {
|
|
Self::Run
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, StructOpt, PartialEq, Clone)]
|
|
pub struct CreateTokenCommand {
|
|
#[structopt(parse(try_from_str = Permissions::try_from))]
|
|
pub permissions: Vec<Permissions>,
|
|
}
|
|
|
|
async fn run_local_server(ctx: &Arc<Context>) {
|
|
let socket_path = ctx
|
|
.cfg
|
|
.server_config
|
|
.local_socket
|
|
.as_ref()
|
|
.expect("Expected local_socket to be defined");
|
|
|
|
if socket_path.exists() {
|
|
if let Err(e) = std::fs::remove_file(&socket_path) {
|
|
log::error!("Unable to cleanup local socket: {}", e);
|
|
return;
|
|
}
|
|
}
|
|
|
|
let listener = match UnixListener::bind(socket_path) {
|
|
Ok(l) => l,
|
|
Err(e) => {
|
|
log::error!("Unable to open local socket: {}", e);
|
|
return;
|
|
}
|
|
};
|
|
|
|
let unix_listener_stream = UnixListenerStream::new(listener);
|
|
|
|
let local_api = local_model_filter(ctx.clone());
|
|
|
|
warp::serve(local_api.clone())
|
|
.run_incoming(unix_listener_stream)
|
|
.await;
|
|
}
|
|
|
|
async fn run_remote_server(ctx: &Arc<Context>) {
|
|
let socket_addr = match SocketAddr::from_str(ctx.cfg.server_config.host.as_str()) {
|
|
Ok(socket_addr) => socket_addr,
|
|
Err(e) => {
|
|
log::warn!(
|
|
"Error parsing {} as address: {}",
|
|
ctx.cfg.server_config.host,
|
|
e
|
|
);
|
|
return;
|
|
}
|
|
};
|
|
|
|
let api = command_filter(ctx.clone()).or(remote_model_filter(ctx.clone()));
|
|
|
|
warp::serve(api).run(socket_addr).await;
|
|
}
|
|
|
|
async fn run_server(ctx: Arc<Context>) {
|
|
tokio::select! {
|
|
// Start local api
|
|
_ = run_local_server(&ctx), if ctx.cfg.server_config.local_socket.is_some() => {
|
|
log::warn!("Socket API exited")
|
|
}
|
|
// Start HTTP api
|
|
_ = run_remote_server(&ctx) => {
|
|
log::warn!("HTTP API exited")
|
|
}
|
|
}
|
|
}
|
|
|
|
fn create_token(ctx: Arc<Context>, perms: Vec<Permissions>) {
|
|
match AddToken::run_command(ctx, &AddTokenParams { permissions: perms }, None) {
|
|
Ok(token) => {
|
|
// Don't log this to keep tokens out of the log
|
|
println!("Added admin token with secret: {}", token.secret)
|
|
}
|
|
Err(e) => {
|
|
log::warn!("Unable to create admin token: {}", e)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let args: Args = Args::from_args();
|
|
|
|
if let Err(e) = init_logging(args.log_level) {
|
|
println!("Unable to initialize logger: {}", e);
|
|
return;
|
|
}
|
|
|
|
let cfg = match GeoffreyAPIConfig::new(args.config.as_path()) {
|
|
Ok(cfg) => cfg,
|
|
Err(e) => {
|
|
log::warn!("Error opening config: {}", e);
|
|
return;
|
|
}
|
|
};
|
|
|
|
let ctx = Context::new(cfg, args.clone()).unwrap();
|
|
|
|
match args.command {
|
|
GeoffreyApiCommand::Run => run_server(ctx).await,
|
|
GeoffreyApiCommand::CreateAdminToken(perms) => create_token(ctx, perms.permissions),
|
|
};
|
|
}
|