Add support codes API and portal server changes
- support_codes.rs: 6-digit code management - main.rs: Portal routes, static file serving, AppState - relay/mod.rs: Updated for AppState - Cargo.toml: Added rand, tower-http fs feature Generated with Claude Code
This commit is contained in:
@@ -9,6 +9,7 @@ mod session;
|
||||
mod auth;
|
||||
mod api;
|
||||
mod db;
|
||||
mod support_codes;
|
||||
|
||||
pub mod proto {
|
||||
include!(concat!(env!("OUT_DIR"), "/guruconnect.rs"));
|
||||
@@ -17,13 +18,27 @@ pub mod proto {
|
||||
use anyhow::Result;
|
||||
use axum::{
|
||||
Router,
|
||||
routing::get,
|
||||
routing::{get, post},
|
||||
extract::{Path, State, Json},
|
||||
response::{Html, IntoResponse},
|
||||
http::StatusCode,
|
||||
};
|
||||
use std::net::SocketAddr;
|
||||
use tower_http::cors::{Any, CorsLayer};
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tower_http::services::ServeDir;
|
||||
use tracing::{info, Level};
|
||||
use tracing_subscriber::FmtSubscriber;
|
||||
use serde::Deserialize;
|
||||
|
||||
use support_codes::{SupportCodeManager, CreateCodeRequest, SupportCode, CodeValidation};
|
||||
|
||||
/// Application state
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
sessions: session::SessionManager,
|
||||
support_codes: SupportCodeManager,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
@@ -37,26 +52,42 @@ async fn main() -> Result<()> {
|
||||
|
||||
// Load configuration
|
||||
let config = config::Config::load()?;
|
||||
info!("Loaded configuration, listening on {}", config.listen_addr);
|
||||
|
||||
// Use port 3002 for GuruConnect
|
||||
let listen_addr = std::env::var("LISTEN_ADDR").unwrap_or_else(|_| "0.0.0.0:3002".to_string());
|
||||
info!("Loaded configuration, listening on {}", listen_addr);
|
||||
|
||||
// Initialize database connection (optional for MVP)
|
||||
// let db = db::init(&config.database_url).await?;
|
||||
|
||||
// Create session manager
|
||||
let sessions = session::SessionManager::new();
|
||||
// Create application state
|
||||
let state = AppState {
|
||||
sessions: session::SessionManager::new(),
|
||||
support_codes: SupportCodeManager::new(),
|
||||
};
|
||||
|
||||
// Build router
|
||||
let app = Router::new()
|
||||
// Health check
|
||||
.route("/health", get(health))
|
||||
|
||||
// Portal API - Support codes
|
||||
.route("/api/codes", post(create_code))
|
||||
.route("/api/codes", get(list_codes))
|
||||
.route("/api/codes/:code/validate", get(validate_code))
|
||||
.route("/api/codes/:code/cancel", post(cancel_code))
|
||||
|
||||
// WebSocket endpoints
|
||||
.route("/ws/agent", get(relay::agent_ws_handler))
|
||||
.route("/ws/viewer", get(relay::viewer_ws_handler))
|
||||
// REST API
|
||||
.route("/api/sessions", get(api::list_sessions))
|
||||
.route("/api/sessions/:id", get(api::get_session))
|
||||
|
||||
// REST API - Sessions
|
||||
.route("/api/sessions", get(list_sessions))
|
||||
.route("/api/sessions/:id", get(get_session))
|
||||
|
||||
// State
|
||||
.with_state(sessions)
|
||||
.with_state(state)
|
||||
|
||||
// Serve static files for portal (fallback)
|
||||
.fallback_service(ServeDir::new("static").append_index_html_on_directories(true))
|
||||
|
||||
// Middleware
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.layer(
|
||||
@@ -67,7 +98,7 @@ async fn main() -> Result<()> {
|
||||
);
|
||||
|
||||
// Start server
|
||||
let addr: SocketAddr = config.listen_addr.parse()?;
|
||||
let addr: SocketAddr = listen_addr.parse()?;
|
||||
let listener = tokio::net::TcpListener::bind(addr).await?;
|
||||
|
||||
info!("Server listening on {}", addr);
|
||||
@@ -80,3 +111,65 @@ async fn main() -> Result<()> {
|
||||
async fn health() -> &'static str {
|
||||
"OK"
|
||||
}
|
||||
|
||||
// Support code API handlers
|
||||
|
||||
async fn create_code(
|
||||
State(state): State<AppState>,
|
||||
Json(request): Json<CreateCodeRequest>,
|
||||
) -> Json<SupportCode> {
|
||||
let code = state.support_codes.create_code(request).await;
|
||||
info!("Created support code: {}", code.code);
|
||||
Json(code)
|
||||
}
|
||||
|
||||
async fn list_codes(
|
||||
State(state): State<AppState>,
|
||||
) -> Json<Vec<SupportCode>> {
|
||||
Json(state.support_codes.list_active_codes().await)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ValidateParams {
|
||||
code: String,
|
||||
}
|
||||
|
||||
async fn validate_code(
|
||||
State(state): State<AppState>,
|
||||
Path(code): Path<String>,
|
||||
) -> Json<CodeValidation> {
|
||||
Json(state.support_codes.validate_code(&code).await)
|
||||
}
|
||||
|
||||
async fn cancel_code(
|
||||
State(state): State<AppState>,
|
||||
Path(code): Path<String>,
|
||||
) -> impl IntoResponse {
|
||||
if state.support_codes.cancel_code(&code).await {
|
||||
(StatusCode::OK, "Code cancelled")
|
||||
} else {
|
||||
(StatusCode::BAD_REQUEST, "Cannot cancel code")
|
||||
}
|
||||
}
|
||||
|
||||
// Session API handlers (updated to use AppState)
|
||||
|
||||
async fn list_sessions(
|
||||
State(state): State<AppState>,
|
||||
) -> Json<Vec<api::SessionInfo>> {
|
||||
let sessions = state.sessions.list_sessions().await;
|
||||
Json(sessions.into_iter().map(api::SessionInfo::from).collect())
|
||||
}
|
||||
|
||||
async fn get_session(
|
||||
State(state): State<AppState>,
|
||||
Path(id): Path<String>,
|
||||
) -> Result<Json<api::SessionInfo>, (StatusCode, &'static str)> {
|
||||
let session_id = uuid::Uuid::parse_str(&id)
|
||||
.map_err(|_| (StatusCode::BAD_REQUEST, "Invalid session ID"))?;
|
||||
|
||||
let session = state.sessions.get_session(session_id).await
|
||||
.ok_or((StatusCode::NOT_FOUND, "Session not found"))?;
|
||||
|
||||
Ok(Json(api::SessionInfo::from(session)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user