codex-mobile-bridge 0.3.16

Remote bridge and service manager for codex-mobile.
Documentation
use anyhow::{Context, Result};
use serde_json::json;

use super::*;
use crate::bridge_protocol::{
    BridgeManagementPhase, BridgeManagementStatus, BridgeManagementTask,
    BridgeManagementTaskPayload, ManagedBridgeReleaseDescriptor, ManagedBridgeSnapshot, now_millis,
};
use crate::storage::Storage;

mod install_ops;
mod service_ops;

pub(super) struct BridgeManagementRunner {
    storage: Storage,
    task: BridgeManagementTask,
    paths: ManagedPaths,
}

impl BridgeManagementRunner {
    pub(super) fn new(storage: Storage, task: BridgeManagementTask) -> Self {
        let paths = release::managed_paths().unwrap_or_else(|_| {
            ManagedPaths::new(
                env::var_os("HOME")
                    .map(PathBuf::from)
                    .unwrap_or_else(|| PathBuf::from("/")),
            )
        });
        Self {
            storage,
            task,
            paths,
        }
    }

    pub(super) fn run(mut self) -> Result<()> {
        self.update_task(
            BridgeManagementStatus::Running,
            BridgeManagementPhase::ResolveTarget,
            format!("开始执行远端 bridge {}", self.task.operation.as_str()),
            Some("bridge 已接受任务,正在解析本地状态".to_string()),
            None,
            true,
        )?;

        let result = match self.task.operation {
            crate::bridge_protocol::BridgeManagementOperation::Install
            | crate::bridge_protocol::BridgeManagementOperation::Update => {
                self.run_install_like(self.task.operation.as_str())
            }
            crate::bridge_protocol::BridgeManagementOperation::Repair => self.run_repair(),
            crate::bridge_protocol::BridgeManagementOperation::Rollback => self.run_rollback(),
            crate::bridge_protocol::BridgeManagementOperation::StartService => {
                self.run_start_service()
            }
            crate::bridge_protocol::BridgeManagementOperation::StopService => {
                self.run_stop_service()
            }
            crate::bridge_protocol::BridgeManagementOperation::RestartService => {
                self.run_restart_service()
            }
            crate::bridge_protocol::BridgeManagementOperation::Uninstall => self.run_uninstall(),
        };

        if let Err(error) = result {
            self.fail_task(error)?;
        }
        Ok(())
    }

    fn complete_success(&mut self, summary: String, detail: Option<String>) -> Result<()> {
        self.update_task(
            BridgeManagementStatus::Succeeded,
            BridgeManagementPhase::Done,
            summary,
            detail,
            None,
            true,
        )
    }

    fn fail_task(&mut self, error: anyhow::Error) -> Result<()> {
        let detail = error.to_string();
        self.update_task(
            BridgeManagementStatus::Failed,
            BridgeManagementPhase::Done,
            format!("远端 bridge {}失败", self.task.operation.as_str()),
            Some(detail.clone()),
            Some(failure_code_for_phase(&self.task.phase).to_string()),
            true,
        )?;
        Err(anyhow::anyhow!(detail))
    }

    fn update_task(
        &mut self,
        status: BridgeManagementStatus,
        phase: BridgeManagementPhase,
        summary: String,
        detail: Option<String>,
        failure_code: Option<String>,
        refresh_snapshot: bool,
    ) -> Result<()> {
        self.task.status = status;
        self.task.phase = phase;
        self.task.summary = summary;
        self.task.detail = detail;
        self.task.failure_code = failure_code;
        self.task.updated_at_ms = now_millis();
        if refresh_snapshot {
            self.task.snapshot = self.snapshot_now();
            if let Some(current_version) = self
                .task
                .snapshot
                .as_ref()
                .and_then(|value| value.install_record.as_ref())
                .and_then(|record| record.current_version.clone())
            {
                self.task.current_version = Some(current_version);
            }
        }
        self.storage.upsert_bridge_management_task(&self.task)?;
        self.storage.append_event(
            "bridge_management_updated",
            None,
            None,
            &json!(BridgeManagementTaskPayload {
                task: self.task.clone(),
            }),
        )?;
        Ok(())
    }

    fn snapshot_now(&self) -> Option<ManagedBridgeSnapshot> {
        current_bridge_management_snapshot(self.storage.db_path()).ok()
    }
}