ai-cortex-sdk 0.1.0

Rust client SDK for AI Cortex server: PAT auth, device binding, software store, offline license (Ed25519), and auto-update (check-update pull + SSE push).
Documentation
use futures_util::StreamExt;

use ai_cortex_sdk::{CortexClient, CortexConfig};

/// 演示自动更新流程:
///   1. check_update(Pull):轮询是否有新版本,打印 has_update / force_update / 目标版本
///   2. open_update_events(Push,可选):订阅 SSE 更新事件流,打印 3 条后退出
///
/// Usage:
///   cargo run --example auto_update -- [PAT] [SOFTWARE_ID]
///   # 末尾追加 "stream" 参数以演示 SSE:cargo run --example auto_update -- <PAT> <SOFTWARE_ID> stream
#[tokio::main]
async fn main() {
    let server_url =
        std::env::var("CORTEX_SERVER_URL").unwrap_or_else(|_| "http://localhost:40404".into());
    let pat = std::env::args()
        .nth(1)
        .or_else(|| std::env::var("CORTEX_PAT").ok())
        .unwrap_or_else(|| "REPLACE_WITH_YOUR_PAT".to_string());
    let software_id = std::env::args()
        .nth(2)
        .or_else(|| std::env::var("CORTEX_SOFTWARE_ID").ok())
        .unwrap_or_else(|| "00000000-0000-0000-0000-000000000000".to_string());
    // 第 3 个位置参数(任意值)= 演示 SSE 流
    let demo_stream = std::env::args().nth(3).is_some();

    // 关闭心跳,避免示例对服务端产生副作用
    let config = CortexConfig::new(&server_url, &pat, &software_id).without_heartbeat();
    let client = CortexClient::new(config);

    // --- 1. Pull:检查更新 ---
    println!("=== Check Update (Pull) ===");
    let platform = std::env::consts::OS; // linux / macos / windows
    let current_version = "1.0.0";
    match client
        .check_update(platform, current_version, None)
        .await
    {
        Ok(info) => {
            println!("current_version : {}", info.current_version);
            println!("has_update      : {}", info.has_update);
            println!("force_update    : {}", info.force_update);
            if let Some(t) = &info.target_version {
                println!("target_version  : {} (channel={}, size={} bytes)", t.version, t.channel, t.file_size);
                println!("release_notes   : {}", t.release_notes);
                println!("min_compatible  : {}", t.min_compatible);
            }
            // force_update 语义:客户端应阻止启动直到用户升级
            if info.has_update && info.force_update {
                println!("\n>>> 强制更新:当前版本被阻塞,必须升级后才能继续。");
            }
        }
        Err(e) => eprintln!("check_update failed: {e}"),
    }

    // --- 2. Push:订阅 SSE 更新事件流(可选) ---
    if demo_stream {
        println!("\n=== Update Events (Push / SSE) ===");
        match client.open_update_events(Some(&software_id), None).await {
            Ok(mut stream) => {
                println!("SSE connected. Waiting for events (will print 3 then exit)...");
                let mut count = 0usize;
                while let Some(ev) = stream.next().await {
                    match ev {
                        Ok(e) => {
                            println!(
                                "event #{}: software={} version={} platform={} channel={} force={}",
                                e.id, e.software_id, e.version, e.platform, e.channel, e.force_update
                            );
                            count += 1;
                            if count >= 3 {
                                println!("Received 3 events, exiting demo.");
                                break;
                            }
                        }
                        Err(e) => {
                            eprintln!("stream error: {e}");
                            break;
                        }
                    }
                }
            }
            Err(e) => eprintln!("open_update_events failed: {e}"),
        }
    }
}