Solstice client.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

198 lines
4.7 KiB

use crate::core::{
ValueDecode, ValueDecodeError, ValueDecoder, ValueEncode, ValueEncodeError,
ValueEncoder,
};
/*=========*
* MESSAGE *
*=========*/
const CODE_PIERCE_FIREWALL: u32 = 0;
const CODE_PEER_INIT: u32 = 1;
/// This enum contains all the possible messages peers can exchange.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Message {
PierceFirewall(u32),
PeerInit(PeerInit),
Unknown(u32),
}
impl ValueDecode for Message {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let position = decoder.position();
let code: u32 = decoder.decode()?;
let message = match code {
CODE_PIERCE_FIREWALL => {
let val = decoder.decode()?;
Message::PierceFirewall(val)
}
CODE_PEER_INIT => {
let peer_init = decoder.decode()?;
Message::PeerInit(peer_init)
}
_ => {
return Err(ValueDecodeError::InvalidData {
value_name: "peer message code".to_string(),
cause: format!("unknown value {}", code),
position: position,
})
}
};
Ok(message)
}
}
impl ValueEncode for Message {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
match *self {
Message::PierceFirewall(token) => {
encoder.encode_u32(CODE_PIERCE_FIREWALL)?;
encoder.encode_u32(token)?;
}
Message::PeerInit(ref request) => {
encoder.encode_u32(CODE_PEER_INIT)?;
request.encode_to(encoder)?;
}
Message::Unknown(_) => unreachable!(),
}
Ok(())
}
}
/// The type of a connection to a peer.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PeerConnectionType {
/// File transfer connection.
File,
/// Any other connection.
Peer,
}
const CONNECTION_TYPE_FILE: &'static str = "F";
const CONNECTION_TYPE_PEER: &'static str = "P";
impl ValueEncode for PeerConnectionType {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
let string = match *self {
Self::File => CONNECTION_TYPE_FILE,
Self::Peer => CONNECTION_TYPE_PEER,
};
encoder.encode_string(string)?;
Ok(())
}
}
impl ValueDecode for PeerConnectionType {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let position = decoder.position();
let string: String = decoder.decode()?;
match string.as_ref() {
CONNECTION_TYPE_FILE => Ok(Self::File),
CONNECTION_TYPE_PEER => Ok(Self::Peer),
_ => Err(ValueDecodeError::InvalidData {
value_name: "peer connection type".to_string(),
cause: format!("unknown value {:?}", string),
position: position,
}),
}
}
}
// TODO: Rename to PeerInitMessage.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PeerInit {
pub user_name: String,
pub connection_type: PeerConnectionType,
pub token: u32,
}
impl ValueEncode for PeerInit {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.user_name)?;
encoder.encode(&self.connection_type)?;
encoder.encode_u32(self.token)?;
Ok(())
}
}
impl ValueDecode for PeerInit {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let user_name = decoder.decode()?;
let connection_type = decoder.decode()?;
let token = decoder.decode()?;
Ok(PeerInit {
user_name,
connection_type,
token,
})
}
}
#[cfg(test)]
mod tests {
use bytes::BytesMut;
use crate::core::testing::roundtrip;
use crate::core::{ValueDecodeError, ValueDecoder};
use super::*;
#[test]
fn invalid_code() {
let mut bytes = BytesMut::new();
bytes.extend_from_slice(&[57, 5, 0, 0]);
let result = ValueDecoder::new(&bytes).decode::<Message>();
assert_eq!(
result,
Err(ValueDecodeError::InvalidData {
value_name: "peer message code".to_string(),
cause: "unknown value 1337".to_string(),
position: 0,
})
);
}
#[test]
fn invalid_peer_connection_type() {
let mut bytes = BytesMut::new();
ValueEncoder::new(&mut bytes).encode("bleep").unwrap();
let result = ValueDecoder::new(&bytes).decode::<PeerConnectionType>();
assert_eq!(
result,
Err(ValueDecodeError::InvalidData {
value_name: "peer connection type".to_string(),
cause: "unknown value \"bleep\"".to_string(),
position: 0,
})
);
}
#[test]
fn roundtrip_pierce_firewall() {
roundtrip(Message::PierceFirewall(1337))
}
#[test]
fn roundtrip_peer_init() {
roundtrip(Message::PeerInit(PeerInit {
user_name: "alice".to_string(),
connection_type: PeerConnectionType::Peer,
token: 1337,
}));
}
}