133 lines
4.2 KiB
Rust
133 lines
4.2 KiB
Rust
/*
|
|
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
use std::cell::RefCell;
|
|
use std::error::Error;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use tera::*;
|
|
use tokio::fs;
|
|
use tokio::io::AsyncWriteExt;
|
|
use tokio::process::Command;
|
|
|
|
use crate::templates::*;
|
|
|
|
pub struct Nginx;
|
|
|
|
impl Nginx {
|
|
pub async fn reload() -> MyResult<()> {
|
|
Command::new("sudo")
|
|
.arg("nginx")
|
|
.arg("-s")
|
|
.arg("reload")
|
|
.spawn()?
|
|
.wait()
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
pub async fn status() -> bool {
|
|
async fn run_async_cmd(cmd: &mut Command) -> bool {
|
|
if let Ok(mut child) = cmd.spawn() {
|
|
if let Ok(res) = child.wait().await {
|
|
return res.success();
|
|
}
|
|
}
|
|
false
|
|
}
|
|
run_async_cmd(Command::new("sudo").arg("nginx").arg("-t")).await
|
|
}
|
|
|
|
pub async fn new_site(
|
|
hostname: &str,
|
|
path: &str,
|
|
config: Option<libconfig::Config>,
|
|
) -> MyResult<()> {
|
|
let config = CreateSite::new(hostname, path, config);
|
|
let contents = config.render();
|
|
let staging = Self::get_staging(hostname);
|
|
let prod = Self::get_prod(hostname);
|
|
|
|
let mut file = fs::File::create(&staging).await?;
|
|
file.write_all(contents.as_bytes()).await?;
|
|
file.sync_all().await?;
|
|
fs::symlink(&staging, &prod).await?;
|
|
Self::reload().await
|
|
}
|
|
|
|
fn get_staging(hostname: &str) -> PathBuf {
|
|
Path::new(NGINX_STAGING_CONFIG_PATH).join(hostname)
|
|
}
|
|
fn get_prod(hostname: &str) -> PathBuf {
|
|
Path::new(NGINX_PRODUCTION_CONFIG_PATH).join(hostname)
|
|
}
|
|
|
|
pub fn site_exists(hostname: &str) -> bool {
|
|
Self::get_prod(hostname).exists()
|
|
}
|
|
|
|
pub async fn rm_site(hostname: &str) -> MyResult<()> {
|
|
let staging = Self::get_staging(hostname);
|
|
let prod = Self::get_prod(hostname);
|
|
|
|
fs::remove_file(&prod).await?;
|
|
fs::remove_file(&staging).await?;
|
|
Self::reload().await
|
|
}
|
|
|
|
pub fn env_exists() -> bool {
|
|
let prod = Path::new(NGINX_PRODUCTION_CONFIG_PATH);
|
|
let staging = Path::new(NGINX_STAGING_CONFIG_PATH);
|
|
prod.exists() && prod.is_dir() && staging.exists() && staging.is_dir()
|
|
}
|
|
}
|
|
|
|
pub struct CreateSite {
|
|
ctx: RefCell<Context>,
|
|
}
|
|
|
|
pub const CREATE_SITE: TemplateFile = TemplateFile::new("create_site", "nginx/create-site.j2");
|
|
pub const CREATE_SITE_FRAGMENT: TemplateFile =
|
|
TemplateFile::new("new_site_frag", "nginx/_new_site.fragement.j2");
|
|
|
|
pub const HOSTNAME_KEY: &str = "hostname";
|
|
pub const DOMAINS_KEY: &str = "domains";
|
|
pub const PATH_KEY: &str = "path";
|
|
pub const REDIRECTS_KEY: &str = "redirects";
|
|
|
|
pub const NGINX_STAGING_CONFIG_PATH: &str = "/etc/librepages/nginx/sites-available/";
|
|
pub const NGINX_PRODUCTION_CONFIG_PATH: &str = "/etc/librepages/nginx/sites-enabled/";
|
|
|
|
type MyResult<T> = std::result::Result<T, Box<dyn Error>>;
|
|
|
|
impl CreateSite {
|
|
fn new(hostname: &str, path: &str, config: Option<libconfig::Config>) -> Self {
|
|
let ctx = RefCell::new(context());
|
|
ctx.borrow_mut().insert(HOSTNAME_KEY, hostname);
|
|
ctx.borrow_mut().insert(PATH_KEY, path);
|
|
if let Some(config) = config {
|
|
ctx.borrow_mut().insert(REDIRECTS_KEY, &config.redirects);
|
|
ctx.borrow_mut().insert(DOMAINS_KEY, &config.domains);
|
|
}
|
|
Self { ctx }
|
|
}
|
|
|
|
fn render(&self) -> String {
|
|
TEMPLATES
|
|
.render(CREATE_SITE.name, &self.ctx.borrow())
|
|
.unwrap()
|
|
}
|
|
}
|