Skip to main content

bb_ops/syscalls/peers/
insert.rs

1//! `AddressBook::Insert(peer, addr)` - custom op registered via
2//! `bb::register_op!` that pushes a multiaddr into the engine's
3//! [`bb_runtime::framework::AddressBook`] from the data plane.
4//!
5//! The op routes through the existing `add_peer` / `register_address`
6//! API: a new peer creates an entry with `ref_count = 1`; a known
7//! peer dedupe-appends the address without a `ref_count` change.
8//! The `(peer, addr)` carriers ride the graph as `TYPE_PEER_ID` and
9//! `TYPE_MULTIADDRESS`.
10
11use bb_ir::proto::onnx::NodeProto;
12use bb_runtime::atomic::DispatchResult;
13use bb_runtime::bus::{OpError, OpErrorKind};
14use bb_runtime::framework::Address;
15use bb_runtime::ids::PeerId;
16use bb_runtime::runtime::RuntimeResourceRef;
17use bb_runtime::slot_value::SlotValue;
18use bb_runtime::syscall::values::{AddressValue, PeerIdValue};
19
20/// `(domain, op_type)` registration key.
21pub const DOMAIN: &str = "ai.bytesandbrains.address_book";
22/// Op type name.
23pub const OP_TYPE: &str = "Insert";
24
25/// Invoke fn - merge the address into the AddressBook.
26///
27/// New peer → `add_peer` (entry created with `ref_count = 1`).
28/// Known peer → `register_address` (idempotent append, no
29/// `ref_count` change). Returns `Immediate(vec![])` on success;
30/// missing or mistyped inputs surface as `OpError` so the recording
31/// surface notices the wiring mistake.
32pub fn invoke(
33    _node: &NodeProto,
34    inputs: &[(&str, &dyn SlotValue)],
35    ctx: &mut RuntimeResourceRef<'_>,
36) -> Result<DispatchResult, OpError> {
37    let peer = downcast_peer(inputs)?;
38    let addr = downcast_addr(inputs)?;
39    let result = if ctx.peers.addresses.lookup(peer).is_some() {
40        ctx.peers.addresses.register_address(peer, addr)
41    } else {
42        ctx.peers.addresses.add_peer(peer, vec![addr])
43    };
44    match result {
45        Ok(()) => Ok(DispatchResult::Immediate(Vec::new())),
46        Err(e) => Err(OpError {
47            kind: OpErrorKind::ExecutionFailed,
48            reason: "address_book_insert_failed",
49            detail: format!("AddressBook::Insert: {e}"),
50        }),
51    }
52}
53
54fn downcast_peer(inputs: &[(&str, &dyn SlotValue)]) -> Result<PeerId, OpError> {
55    let (_, value) = inputs
56        .iter()
57        .find(|(n, _)| *n == "peer")
58        .ok_or_else(|| OpError {
59            kind: OpErrorKind::MissingSlot,
60            reason: "missing_peer",
61            detail: "AddressBook::Insert: required input `peer` is absent".into(),
62        })?;
63    value
64        .as_any()
65        .downcast_ref::<PeerIdValue>()
66        .map(|p| p.0)
67        .ok_or_else(|| OpError {
68            kind: OpErrorKind::TypeMismatch,
69            reason: "expected_peer_id",
70            detail: "AddressBook::Insert: input `peer` is not a PeerId".into(),
71        })
72}
73
74fn downcast_addr(inputs: &[(&str, &dyn SlotValue)]) -> Result<Address, OpError> {
75    let (_, value) = inputs
76        .iter()
77        .find(|(n, _)| *n == "addr")
78        .ok_or_else(|| OpError {
79            kind: OpErrorKind::MissingSlot,
80            reason: "missing_addr",
81            detail: "AddressBook::Insert: required input `addr` is absent".into(),
82        })?;
83    value
84        .as_any()
85        .downcast_ref::<AddressValue>()
86        .map(|a| a.0.clone())
87        .ok_or_else(|| OpError {
88            kind: OpErrorKind::TypeMismatch,
89            reason: "expected_multiaddress",
90            detail: "AddressBook::Insert: input `addr` is not a Multiaddress".into(),
91        })
92}
93
94
95bb_derive::register_op! {
96    domain: "ai.bytesandbrains.address_book",
97    op_type: "Insert",
98    invoke: invoke,
99}