move repos into monorepo

This commit is contained in:
Timur Gordon
2025-11-13 20:44:00 +01:00
commit 4b23e5eb7f
204 changed files with 33737 additions and 0 deletions

29
bin/osiris/Cargo.toml Normal file
View File

@@ -0,0 +1,29 @@
[package]
name = "osiris-server"
version.workspace = true
edition.workspace = true
description = "Osiris HTTP server"
license = "MIT OR Apache-2.0"
[[bin]]
name = "osiris"
path = "src/main.rs"
[dependencies]
# Osiris core
osiris-core = { path = "../../lib/osiris/core" }
# Web framework
axum = "0.7"
tower = "0.4"
tower-http.workspace = true
# Core dependencies
tokio.workspace = true
serde.workspace = true
serde_json.workspace = true
anyhow.workspace = true
# Tracing
tracing.workspace = true
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

145
bin/osiris/src/main.rs Normal file
View File

@@ -0,0 +1,145 @@
//! Osiris Server - Generic OpenAPI REST server for Osiris data structures
//!
//! Provides generic CRUD operations for all Osiris structs via REST API.
//! Routes follow pattern: GET /api/:struct_name/:id
use axum::{
extract::{Path, Query, State},
http::StatusCode,
response::{IntoResponse, Json},
routing::get,
Router,
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::collections::HashMap;
use std::sync::Arc;
use tower_http::cors::{Any, CorsLayer};
use tracing::{info, warn};
#[derive(Clone)]
struct AppState {
// In a real implementation, this would be a Redis connection pool
// For now, we'll use an in-memory store for demonstration
store: Arc<tokio::sync::RwLock<HashMap<String, HashMap<String, Value>>>>,
}
impl AppState {
fn new() -> Self {
Self {
store: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
}
}
}
#[tokio::main]
async fn main() {
// Initialize tracing
tracing_subscriber::fmt()
.with_target(false)
.compact()
.init();
let state = AppState::new();
// Build router
let app = Router::new()
.route("/health", get(health_check))
.route("/api/:struct_name", get(list_structs))
.route("/api/:struct_name/:id", get(get_struct))
.layer(
CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any),
)
.with_state(state);
let addr = "0.0.0.0:8081";
info!("🚀 Osiris Server starting on {}", addr);
info!("📖 API Documentation: http://localhost:8081/health");
let listener = tokio::net::TcpListener::bind(addr)
.await
.expect("Failed to bind address");
axum::serve(listener, app)
.await
.expect("Server failed");
}
/// Health check endpoint
async fn health_check() -> impl IntoResponse {
Json(json!({
"status": "healthy",
"service": "osiris-server",
"version": "0.1.0"
}))
}
/// Generic GET endpoint for a single struct by ID
/// GET /api/:struct_name/:id
async fn get_struct(
State(state): State<AppState>,
Path((struct_name, id)): Path<(String, String)>,
) -> Result<Json<Value>, (StatusCode, String)> {
info!("GET /api/{}/{}", struct_name, id);
let store = state.store.read().await;
if let Some(struct_store) = store.get(&struct_name) {
if let Some(data) = struct_store.get(&id) {
return Ok(Json(data.clone()));
}
}
warn!("Not found: {}/{}", struct_name, id);
Err((
StatusCode::NOT_FOUND,
format!("{}/{} not found", struct_name, id),
))
}
/// Generic LIST endpoint for all instances of a struct
/// GET /api/:struct_name?field=value
async fn list_structs(
State(state): State<AppState>,
Path(struct_name): Path<String>,
Query(params): Query<HashMap<String, String>>,
) -> Result<Json<Vec<Value>>, (StatusCode, String)> {
info!("GET /api/{} with params: {:?}", struct_name, params);
let store = state.store.read().await;
if let Some(struct_store) = store.get(&struct_name) {
let mut results: Vec<Value> = struct_store.values().cloned().collect();
// Apply filters if any
if !params.is_empty() {
results.retain(|item| {
params.iter().all(|(key, value)| {
item.get(key)
.and_then(|v| v.as_str())
.map(|v| v == value)
.unwrap_or(false)
})
});
}
return Ok(Json(results));
}
// Return empty array if struct type doesn't exist yet
Ok(Json(vec![]))
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_health_check() {
let response = health_check().await.into_response();
assert_eq!(response.status(), StatusCode::OK);
}
}