use crate::domain::entity::app_instance_entity::AppInstanceEntity;
use crate::domain::entity::application_entity::ApplicationEntity;
use genies::context::CONTEXT;
use rbatis::rbdc::db::ExecResult;
pub struct AppInstanceDomainService;
impl AppInstanceDomainService {
pub async fn register_or_update(entity: &AppInstanceEntity) -> Result<(), String> {
let rb = &CONTEXT.rbatis;
let tx = rb.acquire_begin().await.map_err(|e| e.to_string())?;
let instance_id = entity.instance_id.ok_or("instance_id is required")?;
let app_name = entity.app_name.as_deref().unwrap_or_default();
if !app_name.is_empty() {
let existing_app = ApplicationEntity::find_by_app_name(&tx, app_name)
.await
.map_err(|e| e.to_string())?;
if existing_app.is_none() {
ApplicationEntity::insert_app(&tx, app_name, app_name, "", "", &1)
.await
.map_err(|e| e.to_string())?;
}
}
let existing = AppInstanceEntity::select_by_instance_id(&tx, &instance_id)
.await
.map_err(|e| e.to_string())?;
if let Some(mut old) = existing.into_iter().next() {
old.base_url = entity.base_url.clone();
old.version = entity.version.clone();
old.status = Some(1);
old.last_heartbeat_at = Some(rbdc::DateTime::now());
old.app_name = entity.app_name.clone();
old.metadata = entity.metadata.clone();
AppInstanceEntity::update_by_map(&tx, &old, "id".into())
.await
.map_err(|e| e.to_string())?;
} else {
let mut new_entity = entity.clone();
new_entity.status = Some(1);
new_entity.registered_at = Some(rbdc::DateTime::now());
new_entity.last_heartbeat_at = Some(rbdc::DateTime::now());
AppInstanceEntity::insert(&tx, &new_entity)
.await
.map_err(|e| e.to_string())?;
}
tx.commit().await.map_err(|e| e.to_string())?;
Ok(())
}
pub async fn heartbeat(instance_id: i64) -> Result<ExecResult, String> {
let rb = &CONTEXT.rbatis;
AppInstanceEntity::update_heartbeat(rb, &instance_id)
.await
.map_err(|e| e.to_string())
}
pub async fn deregister(instance_id: i64) -> Result<(), String> {
let rb = &CONTEXT.rbatis;
let tx = rb.acquire_begin().await.map_err(|e| e.to_string())?;
let existing = AppInstanceEntity::select_by_instance_id(&tx, &instance_id)
.await
.map_err(|e| e.to_string())?;
if let Some(mut entity) = existing.into_iter().next() {
entity.status = Some(0);
AppInstanceEntity::update_by_map(&tx, &entity, "id".into())
.await
.map_err(|e| e.to_string())?;
}
tx.commit().await.map_err(|e| e.to_string())?;
Ok(())
}
pub async fn cleanup_stale(threshold_seconds: i64) -> Result<ExecResult, String> {
let rb = &CONTEXT.rbatis;
AppInstanceEntity::mark_stale_offline(rb, &threshold_seconds)
.await
.map_err(|e| e.to_string())
}
pub async fn delete_stale_instances(threshold_seconds: i64) -> Result<ExecResult, String> {
let rb = &CONTEXT.rbatis;
AppInstanceEntity::delete_offline_older_than(rb, &threshold_seconds)
.await
.map_err(|e| e.to_string())
}
}