//! P2P handlers — publish/resolve endpoints and health check. use std::sync::Arc; use bytes::Bytes; use prost::Message; use quicprochat_proto::qpc::v1; use quicprochat_rpc::method::{HandlerResult, RequestContext}; use crate::domain::p2p::P2pService; use crate::domain::types::{CallerAuth, PublishEndpointReq, ResolveEndpointReq}; use super::{domain_err, require_auth, ServerState}; fn caller_auth(identity_key: Vec) -> CallerAuth { CallerAuth { identity_key, token: Vec::new(), device_id: None, } } pub async fn handle_publish_endpoint( state: Arc, ctx: RequestContext, ) -> HandlerResult { let identity_key = match require_auth(&state, &ctx) { Ok(ik) => ik, Err(e) => return e, }; let req = match v1::PublishEndpointRequest::decode(ctx.payload) { Ok(r) => r, Err(e) => { return HandlerResult::err( quicprochat_rpc::error::RpcStatus::BadRequest, &format!("decode: {e}"), ) } }; let svc = P2pService { store: Arc::clone(&state.store), }; let auth = caller_auth(identity_key); let domain_req = PublishEndpointReq { identity_key: req.identity_key, node_addr: req.node_addr, }; match svc.publish_endpoint(domain_req, &auth) { Ok(()) => { let proto = v1::PublishEndpointResponse {}; HandlerResult::ok(Bytes::from(proto.encode_to_vec())) } Err(e) => domain_err(e), } } pub async fn handle_resolve_endpoint( state: Arc, ctx: RequestContext, ) -> HandlerResult { let identity_key = match require_auth(&state, &ctx) { Ok(ik) => ik, Err(e) => return e, }; let req = match v1::ResolveEndpointRequest::decode(ctx.payload) { Ok(r) => r, Err(e) => { return HandlerResult::err( quicprochat_rpc::error::RpcStatus::BadRequest, &format!("decode: {e}"), ) } }; let svc = P2pService { store: Arc::clone(&state.store), }; let auth = caller_auth(identity_key); let domain_req = ResolveEndpointReq { identity_key: req.identity_key, }; match svc.resolve_endpoint(domain_req, &auth) { Ok(resp) => { let proto = v1::ResolveEndpointResponse { node_addr: resp.node_addr, }; HandlerResult::ok(Bytes::from(proto.encode_to_vec())) } Err(e) => domain_err(e), } } pub async fn handle_health( state: Arc, _ctx: RequestContext, ) -> HandlerResult { let status = if state.draining.load(std::sync::atomic::Ordering::Relaxed) { "draining" } else { "ok" }; let uptime = state.start_time.elapsed().as_secs(); let resp = v1::HealthResponse { status: status.into(), node_id: state.node_id.clone(), version: env!("CARGO_PKG_VERSION").to_string(), uptime_secs: uptime, storage_backend: state.storage_backend.clone(), }; HandlerResult::ok(Bytes::from(resp.encode_to_vec())) }