use crate::config::{ClientConfig, ClientOpts, EnvConfig, ENV_CONFIG};
use crate::plugins::httpd::{setup_httpd, start_httpd};
use crate::plugins::Plugin;
#[cfg(not(target_os = "windows"))]
use crate::shell::get_cache_dir;
use crate::shell::{find, SubProcess};
use anyhow::{bail, Context, Result};
use async_trait::async_trait;
use cloudpub_common::protocol::message::Message;
use cloudpub_common::protocol::ServerEndpoint;
use parking_lot::RwLock;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::mpsc;
use xml::escape::escape_str_attribute;
#[cfg(target_os = "windows")]
const WSAP_MODULE: &str = "wsap24.dll";
#[cfg(all(unix, debug_assertions))]
const WSAP_MODULE: &str = "wsap24t.so";
#[cfg(all(unix, not(debug_assertions)))]
const WSAP_MODULE: &str = "wsap24.so";
pub const ONEC_SUBDIR: &str = "1c";
const ONEC_CONFIG: &str = include_str!("httpd.conf");
const DEFAULT_VRD: &str = include_str!("default.vrd");
fn detect_platform() -> Option<EnvConfig> {
for patform in ENV_CONFIG.iter() {
if std::path::Path::new(&patform.1.home_1c).exists() {
return Some((*patform.1).clone());
}
}
None
}
fn check_enviroment(config: Arc<RwLock<ClientConfig>>) -> Result<EnvConfig> {
let env = if let Some(platform) = config.read().one_c_platform.as_ref() {
ENV_CONFIG.get(platform).cloned()
} else {
detect_platform()
};
let mut env = if let Some(env) = env {
env
} else {
bail!(crate::t!("error-onec-platform-not-found"));
};
if let Some(one_c_home) = &config.read().one_c_home {
env.home_1c = PathBuf::from(one_c_home);
}
if !std::path::Path::new(&env.home_1c).exists() {
bail!(crate::t!("error-onec-path-not-found", "path" => env.home_1c.to_str().unwrap()));
}
Ok(env)
}
pub struct OneCPlugin;
#[async_trait]
impl Plugin for OneCPlugin {
fn name(&self) -> &'static str {
"onec"
}
async fn setup(
&self,
config: &Arc<RwLock<ClientConfig>>,
_opts: &ClientOpts,
command_rx: &mut mpsc::Receiver<Message>,
result_tx: &mpsc::Sender<Message>,
) -> Result<()> {
let env = check_enviroment(config.clone())?;
setup_httpd(config, command_rx, result_tx, env).await
}
async fn publish(
&self,
endpoint: &ServerEndpoint,
config: &Arc<RwLock<ClientConfig>>,
_opts: &ClientOpts,
result_tx: &mpsc::Sender<Message>,
) -> Result<SubProcess> {
let env = check_enviroment(config.clone())?;
#[cfg(not(target_os = "windows"))]
let one_c_publish_dir = config
.read()
.one_c_publish_dir
.as_ref()
.map(PathBuf::from)
.unwrap_or_else(|| get_cache_dir(ONEC_SUBDIR).unwrap());
#[cfg(target_os = "windows")]
let one_c_publish_dir = config
.read()
.one_c_publish_dir
.as_ref()
.map(PathBuf::from)
.unwrap_or_else(|| {
PathBuf::from(
std::env::var("PROGRAMDATA").unwrap_or_else(|_| "C:\\ProgramData".to_string()),
)
.join("CloudPub")
.join(ONEC_SUBDIR)
});
let publish_dir = one_c_publish_dir.join(&endpoint.guid);
std::fs::create_dir_all(publish_dir.clone()).context("Can't create publish dir")?;
let mut default_vrd = publish_dir.clone();
default_vrd.push("default.vrd");
let wsap_error = crate::t!("error-onec-wsap-not-found", "module" => WSAP_MODULE, "path" => env.home_1c.to_str().unwrap());
let wsap = if let Some(wsap) =
find(&env.home_1c, &PathBuf::from(WSAP_MODULE)).context(wsap_error.clone())?
{
wsap
} else {
bail!(wsap_error);
};
let local_addr = endpoint.client.as_ref().unwrap().local_addr.clone();
let ib = if std::path::Path::new(&local_addr).exists() {
format!("File=\"{}\"", local_addr)
} else {
local_addr.clone()
};
let vrd_config = DEFAULT_VRD.replace("[[IB]]", &escape_str_attribute(&ib));
if !default_vrd.exists() {
std::fs::write(&default_vrd, vrd_config)
.context(crate::t!("error-onec-writing-vrd"))?;
}
let httpd_config = ONEC_CONFIG.replace("[[WSAP_MODULE]]", wsap.to_str().unwrap());
start_httpd(
endpoint,
&httpd_config,
ONEC_SUBDIR,
publish_dir.to_str().unwrap(),
env,
result_tx.clone(),
)
.await
}
}