feat: wire up federation message routing and P2P client fallback
- Enqueue handler checks resolve_destination() for remote recipients - User resolution supports user@domain federated addresses - P2P mesh commands (/mesh start, /mesh stop) wired into client session - Federation routing integration tests with SqlStore - Fix DashMap deadlock in validate_session()
This commit is contained in:
@@ -12,6 +12,7 @@ use tokio::sync::Notify;
|
||||
|
||||
use crate::domain::delivery::DeliveryService;
|
||||
use crate::domain::types::{AckReq, BatchEnqueueReq, EnqueueReq, FetchReq, PeekReq};
|
||||
use crate::federation::routing;
|
||||
use crate::hooks::{HookAction, MessageEvent};
|
||||
|
||||
use super::{require_auth, ServerState};
|
||||
@@ -72,6 +73,26 @@ pub async fn handle_enqueue(state: Arc<ServerState>, ctx: RequestContext) -> Han
|
||||
}
|
||||
}
|
||||
|
||||
// Federation routing: detect remote recipients and enqueue to the local
|
||||
// store with a federation home-server annotation. The v1 Cap'n Proto handler
|
||||
// (which runs on a LocalSet) performs the actual outbound relay via
|
||||
// FederationClient. The v2 handler enqueues locally so the message is
|
||||
// persisted even if the remote server is temporarily unreachable.
|
||||
if state.federation_client.is_some() && !state.local_domain.is_empty() {
|
||||
let dest = routing::resolve_destination(
|
||||
&state.store,
|
||||
&req.recipient_key,
|
||||
&state.local_domain,
|
||||
);
|
||||
if let routing::Destination::Remote(ref remote_domain) = dest {
|
||||
tracing::info!(
|
||||
recipient_prefix = %hex::encode(&req.recipient_key[..4.min(req.recipient_key.len())]),
|
||||
domain = %remote_domain,
|
||||
"federation: recipient is on remote server, enqueuing locally for relay"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let svc = DeliveryService {
|
||||
store: Arc::clone(&state.store),
|
||||
waiters: Arc::clone(&state.waiters),
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::domain::types::{
|
||||
AuditKeyTransparencyReq, CheckRevocationReq, ResolveIdentityReq, ResolveUserReq, RevokeKeyReq,
|
||||
};
|
||||
use crate::domain::users::UserService;
|
||||
use crate::federation::address::FederatedAddress;
|
||||
|
||||
use super::{domain_err, require_auth, ServerState};
|
||||
|
||||
@@ -39,10 +40,29 @@ pub async fn handle_resolve_user(state: Arc<ServerState>, ctx: RequestContext) -
|
||||
}
|
||||
};
|
||||
|
||||
// Federation identity resolution: if the username contains '@', parse it
|
||||
// and resolve only if the domain matches local or is bare.
|
||||
let addr = FederatedAddress::parse(&req.username);
|
||||
if !addr.is_local(&state.local_domain) {
|
||||
// Remote user: the v2 path cannot proxy via FederationClient (capnp is !Send).
|
||||
// Return empty to indicate the user is not local. Clients should resolve
|
||||
// remote users through the v1 Cap'n Proto path which supports federation proxy.
|
||||
tracing::info!(
|
||||
username = %addr.username,
|
||||
domain = addr.domain.as_deref().unwrap_or(""),
|
||||
"federation: remote user, not resolvable on this server"
|
||||
);
|
||||
let proto = v1::ResolveUserResponse {
|
||||
identity_key: Vec::new(),
|
||||
inclusion_proof: Vec::new(),
|
||||
};
|
||||
return HandlerResult::ok(Bytes::from(proto.encode_to_vec()));
|
||||
}
|
||||
|
||||
let svc = user_svc(&state);
|
||||
|
||||
let domain_req = ResolveUserReq {
|
||||
username: req.username,
|
||||
username: addr.username,
|
||||
};
|
||||
|
||||
match svc.resolve_user(domain_req) {
|
||||
|
||||
Reference in New Issue
Block a user