use crate::backends::{backend_for, server_service_id};
use crate::brew::Brew;
use crate::config::{load_config, save_config};
use crate::daemon::{self, Status};
use crate::php;
use crate::ssl;
use crate::state::{load_state, save_state, Server, Vhost};
use anyhow::{anyhow, bail, Result};
pub fn require_server(name: &str) -> Result<Server> {
load_state()?
.get_server(name)
.cloned()
.ok_or_else(|| anyhow!("Server '{name}' not found"))
}
pub fn set_enabled(name: &str, enabled: bool) -> Result<()> {
let mut state = load_state()?;
if let Some(s) = state.servers.iter_mut().find(|s| s.name == name) {
s.enabled = enabled;
}
save_state(&state)
}
pub fn ensure_vhost_certs(vhosts: &[&Vhost], brew: &Brew) -> Result<()> {
for v in vhosts {
if v.ssl && !ssl::exists(&v.server_name) {
ssl::mint(brew, &v.server_name)?;
}
}
Ok(())
}
pub fn render_server(server: &Server) -> Result<()> {
let brew = Brew::detect()?;
let cfg = load_config()?;
let state = load_state()?;
let backend = backend_for(server.backend);
backend.ensure_installed(&brew)?;
let vhosts = state.vhosts_for(&server.name);
ensure_vhost_certs(&vhosts, &brew)?;
if server.default_site && !ssl::exists(crate::backends::DEFAULT_SITE_HOST) {
ssl::mint(&brew, crate::backends::DEFAULT_SITE_HOST)?;
}
backend.render(server, &vhosts, &state, &cfg, &brew)?;
backend.validate(server, &brew)?;
Ok(())
}
pub fn start_server(name: &str) -> Result<Status> {
let server = require_server(name)?;
render_server(&server)?;
let brew = Brew::detect()?;
let backend = backend_for(server.backend);
let spec = backend.service_spec(&server, &brew)?;
daemon::install(&spec)?;
daemon::restart(&server_service_id(&server))?;
set_enabled(name, true)?;
Ok(daemon::status(&server_service_id(&server)))
}
pub fn stop_server(name: &str) -> Result<()> {
let server = require_server(name)?;
daemon::unload(&server_service_id(&server))?;
set_enabled(name, false)?;
Ok(())
}
pub fn install_php(version: &str) -> Result<()> {
let brew = Brew::detect()?;
let record = php::install(&brew, version)?;
let mut state = load_state()?;
state.php_versions.retain(|p| p.version != version);
state.php_versions.push(record);
save_state(&state)?;
let mut cfg = load_config()?;
if cfg.default_php.is_none() {
cfg.default_php = Some(version.to_string());
save_config(&cfg)?;
}
Ok(())
}
pub fn remove_php(version: &str) -> Result<()> {
let mut state = load_state()?;
let users: Vec<String> = state
.vhosts
.iter()
.filter(|v| v.php_version == version)
.map(|v| v.server_name.clone())
.collect();
if !users.is_empty() {
bail!("PHP {version} is used by: {}", users.join(", "));
}
daemon::uninstall(&php::service_id(version)).ok();
state.php_versions.retain(|p| p.version != version);
save_state(&state)?;
let mut cfg = load_config()?;
if cfg.default_php.as_deref() == Some(version) {
cfg.default_php = state.php_versions.first().map(|p| p.version.clone());
save_config(&cfg)?;
}
Ok(())
}
pub fn set_default_php(version: &str) -> Result<()> {
let mut cfg = load_config()?;
cfg.default_php = Some(version.to_string());
save_config(&cfg)
}
pub fn restart_server(name: &str) -> Result<Status> {
let server = require_server(name)?;
render_server(&server)?;
let brew = Brew::detect()?;
let backend = backend_for(server.backend);
let spec = backend.service_spec(&server, &brew)?;
daemon::install(&spec)?;
daemon::restart(&server_service_id(&server))?;
Ok(daemon::status(&server_service_id(&server)))
}