Skip to main content

crafty_proto/
join.rs

1//! Cluster join handshake wire types over `/cluster/join` (join-rpc, join-version-skew).
2
3use serde::{Deserialize, Serialize};
4
5use crate::{Membership, NodeId};
6
7/// A request from a new node asking to join the cluster.
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct JoinRequest {
10    /// Wire/protocol version of the joining node (join-version-skew).
11    pub protocol_version: u32,
12    /// Desired node id, or `None` to have the leader assign the next free id.
13    #[serde(default)]
14    pub node_id: Option<NodeId>,
15    /// Address peers should use to reach the joining node.
16    pub advertise_addr: String,
17}
18
19/// The response to a [`JoinRequest`].
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub enum JoinResponse {
22    /// Join accepted; membership change committed by the leader.
23    Accepted {
24        /// Current leader.
25        leader: NodeId,
26        /// Id assigned to this node (matches the request when one was given).
27        node_id: NodeId,
28        /// Resulting cluster membership.
29        membership: Membership,
30    },
31    /// Contacted node is not the leader; retry against `leader`.
32    Redirect {
33        /// Best-known current leader, if any.
34        leader: Option<NodeId>,
35    },
36    /// Join refused.
37    Rejected {
38        /// Why the join was refused.
39        reason: JoinRejection,
40    },
41}
42
43/// One node's advertised address, as gossiped in a [`PeerBook`].
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub struct PeerEntry {
46    /// The node this address belongs to.
47    pub node: NodeId,
48    /// The address peers should dial to reach it (`host:port`).
49    pub addr: String,
50}
51
52/// A snapshot of a node's known peer addresses, served over `/cluster/peers`
53/// (discovery) so a newly joined node — and existing members — can learn how to
54/// reach every peer without static, cluster-wide address configuration. This is
55/// the address-plane counterpart to the Raft-replicated membership (which
56/// carries only [`NodeId`]s, not addresses).
57#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
58pub struct PeerBook {
59    /// Known `(node, addr)` pairs, ascending by id.
60    pub entries: Vec<PeerEntry>,
61}
62
63/// Reason a [`JoinRequest`] was rejected.
64#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
65pub enum JoinRejection {
66    /// Protocol version mismatch — hard reject (join-version-skew).
67    VersionSkew {
68        /// Version the cluster expects.
69        expected: u32,
70        /// Version the joiner offered.
71        got: u32,
72    },
73    /// The cluster is not currently accepting joins (`--allow-join` off).
74    JoinsDisabled,
75    /// A node with this id is already a member.
76    Duplicate,
77    /// Any other refusal, human-readable.
78    Other(String),
79}