atomfn 0.1.2

AtomService 函数服务 Rust SDK:与 TS SDK 协议一致的常驻 HTTP 运行时
Documentation
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};

use serde::Serialize;
use serde_json::{json, Value};

static REQUEST_COUNTER: AtomicU64 = AtomicU64::new(0);

fn now_millis() -> u128 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|d| d.as_millis())
        .unwrap_or(0)
}

fn now_iso() -> String {
    let now = time::OffsetDateTime::now_utc();
    let format = time::format_description::well_known::Rfc3339;
    now.format(&format).unwrap_or_else(|_| String::from("unknown"))
}

pub fn generate_request_id() -> String {
    let seq = REQUEST_COUNTER.fetch_add(1, Ordering::Relaxed);
    format!("{}-{}", now_millis(), seq)
}

#[derive(Clone)]
pub struct Ctx {
    pub request_id: String,
    pub project: String,
    pub bundle: String,
    pub function: String,
}

impl Ctx {
    fn emit(&self, level: &str, message: &str, fields: Option<Value>) {
        let mut record = json!({
            "ts": now_iso(),
            "level": level,
            "project": self.project,
            "bundle": self.bundle,
            "function": self.function,
            "requestId": self.request_id,
            "msg": message,
        });
        if let (Some(Value::Object(extra)), Value::Object(base)) = (fields, &mut record) {
            for (key, value) in extra {
                base.insert(key, value);
            }
        }
        println!("{}", record);
    }

    pub fn debug(&self, message: &str) {
        self.emit("debug", message, None);
    }

    pub fn info(&self, message: &str) {
        self.emit("info", message, None);
    }

    pub fn warn(&self, message: &str) {
        self.emit("warn", message, None);
    }

    pub fn error(&self, message: &str) {
        self.emit("error", message, None);
    }

    pub fn info_with(&self, message: &str, fields: Value) {
        self.emit("info", message, Some(fields));
    }
}

#[derive(Debug)]
pub enum FunctionError {
    Validation(String),
    Business { code: String, data: Value },
    Crash(String),
}

impl FunctionError {
    pub fn business<T: Serialize>(code: &str, data: T) -> Self {
        FunctionError::Business {
            code: code.to_string(),
            data: serde_json::to_value(data).unwrap_or(Value::Null),
        }
    }

    pub fn crash(message: impl Into<String>) -> Self {
        FunctionError::Crash(message.into())
    }
}