blob: 2feb7f64ab3b43ee379ade5267c9918a20859357 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use libp2p::{Multiaddr, PeerId, multiaddr::Protocol};
use super::PeerError;
pub(super) fn address_with_expected_peer(
address: &Multiaddr,
expected_peer: PeerId,
) -> Result<Multiaddr, PeerError> {
match peer_id_from_address(address) {
Some(actual) if actual != expected_peer => Err(PeerError::new(
"peer_identity_mismatch",
"route hint names a different peer identity",
)),
Some(_) => Ok(address.clone()),
None => Ok(address.clone().with(Protocol::P2p(expected_peer))),
}
}
pub(super) fn address_with_peer(address: Multiaddr, peer_id: PeerId) -> Multiaddr {
if peer_id_from_address(&address) == Some(peer_id) {
address
} else {
address.with(Protocol::P2p(peer_id))
}
}
pub(super) fn peer_id_from_address(address: &Multiaddr) -> Option<PeerId> {
address.iter().find_map(|protocol| match protocol {
Protocol::P2p(peer_id) => Some(peer_id),
_ => None,
})
}
pub(super) fn coordination_relay_peer_id(address: &Multiaddr) -> Result<PeerId, PeerError> {
let mut peer_id = None;
for protocol in address.iter() {
match protocol {
Protocol::P2p(_) if peer_id.is_some() => {
return Err(PeerError::new(
"coordination_unavailable",
"coordination relay address must name exactly one peer",
));
}
Protocol::P2p(value) => peer_id = Some(value),
Protocol::P2pCircuit => {
return Err(PeerError::new(
"coordination_unavailable",
"coordination relay address must be a base relay address",
));
}
_ => {}
}
}
match (peer_id, address.iter().last()) {
(Some(peer_id), Some(Protocol::P2p(terminal))) if peer_id == terminal => Ok(peer_id),
_ => Err(PeerError::new(
"coordination_unavailable",
"coordination relay address must end with its peer identity",
)),
}
}
pub(super) fn is_relayed_address(address: &Multiaddr) -> bool {
address
.iter()
.any(|protocol| matches!(protocol, Protocol::P2pCircuit))
}