Initial GuruConnect implementation - Phase 1 MVP

- Agent: DXGI/GDI screen capture, mouse/keyboard input, WebSocket transport
- Server: Axum relay, session management, REST API
- Dashboard: React viewer components with TypeScript
- Protocol: Protobuf definitions for all message types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
AZ Computer Guru
2025-12-21 17:18:05 -07:00
commit 33893ea73b
38 changed files with 7724 additions and 0 deletions

54
server/src/api/mod.rs Normal file
View File

@@ -0,0 +1,54 @@
//! REST API endpoints
use axum::{
extract::{Path, State},
Json,
};
use serde::Serialize;
use uuid::Uuid;
use crate::session::SessionManager;
/// Session info returned by API
#[derive(Debug, Serialize)]
pub struct SessionInfo {
pub id: String,
pub agent_id: String,
pub agent_name: String,
pub started_at: String,
pub viewer_count: usize,
}
impl From<crate::session::Session> for SessionInfo {
fn from(s: crate::session::Session) -> Self {
Self {
id: s.id.to_string(),
agent_id: s.agent_id,
agent_name: s.agent_name,
started_at: s.started_at.to_rfc3339(),
viewer_count: s.viewer_count,
}
}
}
/// List all active sessions
pub async fn list_sessions(
State(sessions): State<SessionManager>,
) -> Json<Vec<SessionInfo>> {
let sessions = sessions.list_sessions().await;
Json(sessions.into_iter().map(SessionInfo::from).collect())
}
/// Get a specific session by ID
pub async fn get_session(
State(sessions): State<SessionManager>,
Path(id): Path<String>,
) -> Result<Json<SessionInfo>, (axum::http::StatusCode, &'static str)> {
let session_id = Uuid::parse_str(&id)
.map_err(|_| (axum::http::StatusCode::BAD_REQUEST, "Invalid session ID"))?;
let session = sessions.get_session(session_id).await
.ok_or((axum::http::StatusCode::NOT_FOUND, "Session not found"))?;
Ok(Json(SessionInfo::from(session)))
}