got basic system for passing configs back and forth with URL working
This commit is contained in:
parent
9e724d3903
commit
130581d61e
1
.env.dev
1
.env.dev
@ -1,3 +1,4 @@
|
|||||||
|
export GATEWAY_PASSPHRASE=foobar
|
||||||
export GATEWAY_ORIGIN_STORE_GIT_DIR_PATH=/tmp/gateway_dev_env/origin/git
|
export GATEWAY_ORIGIN_STORE_GIT_DIR_PATH=/tmp/gateway_dev_env/origin/git
|
||||||
export GATEWAY_DOMAIN_CHECKER_TARGET_CNAME=gateway.example.com
|
export GATEWAY_DOMAIN_CHECKER_TARGET_CNAME=gateway.example.com
|
||||||
export GATEWAY_DOMAIN_CONFIG_STORE_DIR_PATH=/tmp/gateway_dev_env/domain/config
|
export GATEWAY_DOMAIN_CONFIG_STORE_DIR_PATH=/tmp/gateway_dev_env/domain/config
|
||||||
|
12
src/main.rs
12
src/main.rs
@ -15,6 +15,9 @@ struct Cli {
|
|||||||
#[arg(long, default_value_t = SocketAddr::from_str("127.0.0.1:3030").unwrap(), env = "GATEWAY_HTTP_LISTEN_ADDR")]
|
#[arg(long, default_value_t = SocketAddr::from_str("127.0.0.1:3030").unwrap(), env = "GATEWAY_HTTP_LISTEN_ADDR")]
|
||||||
http_listen_addr: SocketAddr,
|
http_listen_addr: SocketAddr,
|
||||||
|
|
||||||
|
#[arg(long, required = true, env = "GATEWAY_PASSPHRASE")]
|
||||||
|
passphrase: String,
|
||||||
|
|
||||||
#[arg(long, required = true, env = "GATEWAY_ORIGIN_STORE_GIT_DIR_PATH")]
|
#[arg(long, required = true, env = "GATEWAY_ORIGIN_STORE_GIT_DIR_PATH")]
|
||||||
origin_store_git_dir_path: path::PathBuf,
|
origin_store_git_dir_path: path::PathBuf,
|
||||||
|
|
||||||
@ -59,7 +62,7 @@ async fn main() {
|
|||||||
.expect("git origin store initialized");
|
.expect("git origin store initialized");
|
||||||
|
|
||||||
let domain_checker = gateway::domain::checker::new(
|
let domain_checker = gateway::domain::checker::new(
|
||||||
config.domain_checker_target_cname,
|
config.domain_checker_target_cname.clone(),
|
||||||
&config.domain_checker_resolver_addr,
|
&config.domain_checker_resolver_addr,
|
||||||
)
|
)
|
||||||
.expect("domain checker initialized");
|
.expect("domain checker initialized");
|
||||||
@ -69,7 +72,12 @@ async fn main() {
|
|||||||
|
|
||||||
let manager = gateway::domain::manager::new(origin_store, domain_config_store, domain_checker);
|
let manager = gateway::domain::manager::new(origin_store, domain_config_store, domain_checker);
|
||||||
|
|
||||||
let service = gateway::service::new(manager).expect("service initialized");
|
let service = gateway::service::new(
|
||||||
|
manager,
|
||||||
|
config.domain_checker_target_cname,
|
||||||
|
config.passphrase,
|
||||||
|
)
|
||||||
|
.expect("service initialized");
|
||||||
|
|
||||||
let (addr, server) =
|
let (addr, server) =
|
||||||
warp::serve(service).bind_with_graceful_shutdown(config.http_listen_addr, async {
|
warp::serve(service).bind_with_graceful_shutdown(config.http_listen_addr, async {
|
||||||
|
@ -7,6 +7,7 @@ use warp::Filter;
|
|||||||
use crate::domain;
|
use crate::domain;
|
||||||
|
|
||||||
pub mod http_tpl;
|
pub mod http_tpl;
|
||||||
|
mod util;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* POST /domain/config (domain, config, secret, init?) -> token?
|
* POST /domain/config (domain, config, secret, init?) -> token?
|
||||||
@ -21,6 +22,9 @@ where
|
|||||||
DM: domain::manager::Manager,
|
DM: domain::manager::Manager,
|
||||||
{
|
{
|
||||||
domain_manager: sync::Arc<DM>,
|
domain_manager: sync::Arc<DM>,
|
||||||
|
target_cname: sync::Arc<domain::Name>,
|
||||||
|
passphrase: sync::Arc<String>,
|
||||||
|
|
||||||
handlebars: Handlebars<'a>,
|
handlebars: Handlebars<'a>,
|
||||||
query_args: HashMap<String, String>,
|
query_args: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
@ -71,6 +75,8 @@ where
|
|||||||
|
|
||||||
pub fn new<DM>(
|
pub fn new<DM>(
|
||||||
manager: DM,
|
manager: DM,
|
||||||
|
target_cname: domain::Name,
|
||||||
|
passphrase: String,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
impl warp::Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone + 'static,
|
impl warp::Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone + 'static,
|
||||||
Box<dyn Error>,
|
Box<dyn Error>,
|
||||||
@ -79,12 +85,16 @@ where
|
|||||||
DM: domain::manager::Manager + 'static,
|
DM: domain::manager::Manager + 'static,
|
||||||
{
|
{
|
||||||
let manager = sync::Arc::new(manager);
|
let manager = sync::Arc::new(manager);
|
||||||
|
let target_cname = sync::Arc::new(target_cname);
|
||||||
|
let passphrase = sync::Arc::new(passphrase);
|
||||||
|
|
||||||
let hbs = sync::Arc::new(self::http_tpl::get()?);
|
let hbs = sync::Arc::new(self::http_tpl::get()?);
|
||||||
let with_render_ctx = warp::any()
|
let with_render_ctx = warp::any()
|
||||||
.and(warp::query::<HashMap<String, String>>())
|
.and(warp::query::<HashMap<String, String>>())
|
||||||
.map(move |query_args: HashMap<String, String>| RenderContext {
|
.map(move |query_args: HashMap<String, String>| RenderContext {
|
||||||
domain_manager: manager.clone(),
|
domain_manager: manager.clone(),
|
||||||
|
target_cname: target_cname.clone(),
|
||||||
|
passphrase: passphrase.clone(),
|
||||||
handlebars: hbs.clone(),
|
handlebars: hbs.clone(),
|
||||||
query_args,
|
query_args,
|
||||||
});
|
});
|
||||||
@ -111,28 +121,87 @@ where
|
|||||||
domain: domain::Name,
|
domain: domain::Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
let domain_get = warp::get()
|
|
||||||
.and(with_render_ctx.clone())
|
|
||||||
.and(warp::path("domain.html"))
|
|
||||||
.and(warp::query::<DomainGetNewRequest>())
|
|
||||||
.map(
|
|
||||||
move |render_ctx: RenderContext<'_, DM>, req: DomainGetNewRequest| {
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct DomainGetNewResponse {
|
struct DomainGetNewResponse {
|
||||||
domain: domain::Name,
|
domain: domain::Name,
|
||||||
|
config: Option<domain::config::Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let domain_get = warp::get()
|
||||||
|
.and(with_render_ctx.clone())
|
||||||
|
.and(warp::path!("domain.html"))
|
||||||
|
.and(warp::query::<DomainGetNewRequest>())
|
||||||
|
.and(warp::query::<util::ConfigFromURL>())
|
||||||
|
.map(
|
||||||
|
|render_ctx: RenderContext<'_, DM>,
|
||||||
|
req: DomainGetNewRequest,
|
||||||
|
domain_config: util::ConfigFromURL| {
|
||||||
match render_ctx.domain_manager.get_config(&req.domain) {
|
match render_ctx.domain_manager.get_config(&req.domain) {
|
||||||
Ok(_config) => panic!("TODO"),
|
Ok(_config) => panic!("TODO"),
|
||||||
Err(domain::manager::GetConfigError::NotFound) => render_page(
|
Err(domain::manager::GetConfigError::NotFound) => render_page(
|
||||||
render_ctx,
|
render_ctx,
|
||||||
String::from("/domain_get_new.html"),
|
String::from("/domain_get_new.html"),
|
||||||
DomainGetNewResponse { domain: req.domain },
|
DomainGetNewResponse {
|
||||||
|
domain: req.domain,
|
||||||
|
config: domain_config.try_into().expect("TODO"),
|
||||||
|
},
|
||||||
),
|
),
|
||||||
Err(_) => panic!("TODO"),
|
Err(domain::manager::GetConfigError::Unexpected(e)) => {
|
||||||
|
panic!("{}", e) // TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(static_dir.or(index).or(domain_get))
|
#[derive(Deserialize)]
|
||||||
|
struct DomainPostRequest {
|
||||||
|
_init: bool,
|
||||||
|
domain: domain::Name,
|
||||||
|
passphrase: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain_post = warp::post()
|
||||||
|
.and(with_render_ctx.clone())
|
||||||
|
.and(warp::path!("domain.html"))
|
||||||
|
.and(warp::query::<DomainPostRequest>())
|
||||||
|
.and(warp::query::<util::ConfigFromURL>())
|
||||||
|
.map(
|
||||||
|
|render_ctx: RenderContext<'_, DM>,
|
||||||
|
req: DomainPostRequest,
|
||||||
|
domain_config: util::ConfigFromURL| {
|
||||||
|
if req.passphrase != render_ctx.passphrase.as_str() {
|
||||||
|
panic!("TODO")
|
||||||
|
}
|
||||||
|
|
||||||
|
//if req.init {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Response {
|
||||||
|
domain: domain::Name,
|
||||||
|
config: domain::config::Config,
|
||||||
|
target_cname: domain::Name,
|
||||||
|
challenge_token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let config: Option<domain::config::Config> =
|
||||||
|
domain_config.try_into().expect("TODO");
|
||||||
|
let config = config.expect("TODO");
|
||||||
|
|
||||||
|
let config_hash = config.hash().expect("TODO");
|
||||||
|
let target_cname = (*render_ctx.target_cname).clone();
|
||||||
|
|
||||||
|
return render_page(
|
||||||
|
render_ctx,
|
||||||
|
String::from("/domain_post_init.html"),
|
||||||
|
Response {
|
||||||
|
domain: req.domain,
|
||||||
|
config: config,
|
||||||
|
target_cname: target_cname,
|
||||||
|
challenge_token: config_hash,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
//}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(static_dir.or(index).or(domain_get).or(domain_post))
|
||||||
}
|
}
|
||||||
|
@ -10,19 +10,25 @@ automatically updated too!</p>
|
|||||||
<p><em>In the future Cosmux will support more backends than just git
|
<p><em>In the future Cosmux will support more backends than just git
|
||||||
repos.</em></p>
|
repos.</em></p>
|
||||||
|
|
||||||
|
|
||||||
<form method="POST" action="/domain.html">
|
<form method="POST" action="/domain.html">
|
||||||
<input name="init" type="hidden" value="true" />
|
<input name="init" type="hidden" value="true" />
|
||||||
<input name="domain" type="hidden" value="{{ data.domain }}" />
|
<input name="domain" type="hidden" value="{{ data.domain }}" />
|
||||||
|
<input name="config_origin_descr_kind" type="hidden" value="git" />
|
||||||
|
|
||||||
|
<label>
|
||||||
|
Passphrase (required during closed-beta):
|
||||||
|
<input name="passphrase" placeholder="shhhh" required />
|
||||||
|
</label>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Git Repository</legend>
|
<legend>Git Repository</legend>
|
||||||
<p>
|
<p>
|
||||||
<label>
|
<label>
|
||||||
URL (HTTPS only):
|
URL (HTTPS only):
|
||||||
<input name="git_url"
|
<input name="config_origin_descr_git_url"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="https://example.com/some_repo.git"
|
placeholder="https://example.com/some_repo.git"
|
||||||
|
value="{{ data.config.origin_descr.Git.url }}"
|
||||||
required />
|
required />
|
||||||
</label>
|
</label>
|
||||||
</p>
|
</p>
|
||||||
@ -30,12 +36,15 @@ automatically updated too!</p>
|
|||||||
<p>
|
<p>
|
||||||
<label>
|
<label>
|
||||||
Branch name:
|
Branch name:
|
||||||
<input name="git_branch_name"
|
<input name="config_origin_descr_git_branch_name"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="main / master / etc..."
|
placeholder="main / master / etc..."
|
||||||
|
value="{{ data.config.origin_descr.Git.branch_name }}"
|
||||||
required />
|
required />
|
||||||
</label>
|
</label>
|
||||||
</p>
|
</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<input type="submit" value="Next" />
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
37
src/service/util.rs
Normal file
37
src/service/util.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::{domain, origin};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct ConfigFromURL {
|
||||||
|
config_origin_descr_kind: Option<String>,
|
||||||
|
config_origin_descr_git_url: Option<String>,
|
||||||
|
config_origin_descr_git_branch_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<ConfigFromURL> for Option<domain::config::Config> {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(v: ConfigFromURL) -> Result<Self, Self::Error> {
|
||||||
|
match v
|
||||||
|
.config_origin_descr_kind
|
||||||
|
.unwrap_or("".to_string())
|
||||||
|
.as_str()
|
||||||
|
{
|
||||||
|
"" => Ok(None),
|
||||||
|
"git" => Ok(Some(domain::config::Config {
|
||||||
|
origin_descr: origin::Descr::Git {
|
||||||
|
url: v
|
||||||
|
.config_origin_descr_git_url
|
||||||
|
.ok_or("config_origin_descr_git_url missing")?,
|
||||||
|
branch_name: v
|
||||||
|
.config_origin_descr_git_branch_name
|
||||||
|
.ok_or("config_origin_descr_git_branch_name missing")?,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
_ => Err("invalid config_origin_descr_kind".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user