pub struct Connection<R: ProtocolPacket, W: ProtocolPacket> {
pub reader: ReadConnection<R>,
pub writer: WriteConnection<W>,
}
Expand description
A connection that can read and write packets.
§Examples
Join an offline-mode server and go through the handshake.
use azalea_protocol::{
resolver,
connect::Connection,
packets::{
ClientIntention, PROTOCOL_VERSION,
login::{
ClientboundLoginPacket,
serverbound_hello_packet::ServerboundHelloPacket,
serverbound_key_packet::ServerboundKeyPacket
},
handshaking::client_intention_packet::ClientIntentionPacket
}
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resolved_address = resolver::resolve_address(&"localhost".try_into().unwrap()).await?;
let mut conn = Connection::new(&resolved_address).await?;
// handshake
conn.write(
ClientIntentionPacket {
protocol_version: PROTOCOL_VERSION,
hostname: resolved_address.ip().to_string(),
port: resolved_address.port(),
intention: ClientIntention::Login,
}
.get(),
)
.await?;
let mut conn = conn.login();
// login
conn.write(
ServerboundHelloPacket {
name: "bot".to_string(),
profile_id: uuid::Uuid::nil(),
}
.get(),
)
.await?;
let (conn, game_profile) = loop {
let packet = conn.read().await?;
match packet {
ClientboundLoginPacket::Hello(p) => {
let e = azalea_crypto::encrypt(&p.public_key, &p.challenge).unwrap();
conn.write(
ServerboundKeyPacket {
key_bytes: e.encrypted_public_key,
encrypted_challenge: e.encrypted_challenge,
}
.get(),
)
.await?;
conn.set_encryption_key(e.secret_key);
}
ClientboundLoginPacket::LoginCompression(p) => {
conn.set_compression_threshold(p.compression_threshold);
}
ClientboundLoginPacket::LoginFinished(p) => {
break (conn.configuration(), p.game_profile);
}
ClientboundLoginPacket::LoginDisconnect(p) => {
eprintln!("login disconnect: {}", p.reason);
return Err("login disconnect".into());
}
ClientboundLoginPacket::CustomQuery(p) => {}
ClientboundLoginPacket::CookieRequest(_) => {}
}
};
Ok(())
}
Fields§
§reader: ReadConnection<R>
§writer: WriteConnection<W>
Implementations§
Source§impl<R, W> Connection<R, W>
impl<R, W> Connection<R, W>
Sourcepub async fn read(&mut self) -> Result<R, Box<ReadPacketError>>
pub async fn read(&mut self) -> Result<R, Box<ReadPacketError>>
Read a packet from the other side of the connection.
Sourcepub fn try_read(&mut self) -> Result<Option<R>, Box<ReadPacketError>>
pub fn try_read(&mut self) -> Result<Option<R>, Box<ReadPacketError>>
Try to read a packet from the other side of the connection, or return Ok(None) if there’s no packet to read.
Sourcepub async fn write(&mut self, packet: W) -> Result<()>
pub async fn write(&mut self, packet: W) -> Result<()>
Write a packet to the other side of the connection.
Sourcepub fn into_split(self) -> (ReadConnection<R>, WriteConnection<W>)
pub fn into_split(self) -> (ReadConnection<R>, WriteConnection<W>)
Split the reader and writer into two objects. This doesn’t allocate.
Source§impl Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>
impl Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>
Sourcepub async fn new(address: &SocketAddr) -> Result<Self, ConnectionError>
pub async fn new(address: &SocketAddr) -> Result<Self, ConnectionError>
Create a new connection to the given address.
Sourcepub async fn new_with_proxy(
address: &SocketAddr,
proxy: Proxy,
) -> Result<Self, ConnectionError>
pub async fn new_with_proxy( address: &SocketAddr, proxy: Proxy, ) -> Result<Self, ConnectionError>
Create a new connection to the given address and Socks5 proxy. If you’re
not using a proxy, use Self::new
instead.
Sourcepub async fn new_from_stream(stream: TcpStream) -> Result<Self, ConnectionError>
pub async fn new_from_stream(stream: TcpStream) -> Result<Self, ConnectionError>
Create a new connection from an existing stream. Useful if you want to
set custom options on the stream. Otherwise, just use Self::new
.
Sourcepub fn login(self) -> Connection<ClientboundLoginPacket, ServerboundLoginPacket>
pub fn login(self) -> Connection<ClientboundLoginPacket, ServerboundLoginPacket>
Change our state from handshake to login. This is the state that is used for logging in.
Sourcepub fn status(
self,
) -> Connection<ClientboundStatusPacket, ServerboundStatusPacket>
pub fn status( self, ) -> Connection<ClientboundStatusPacket, ServerboundStatusPacket>
Change our state from handshake to status. This is the state that is used for pinging the server.
Source§impl Connection<ClientboundLoginPacket, ServerboundLoginPacket>
impl Connection<ClientboundLoginPacket, ServerboundLoginPacket>
Sourcepub fn set_compression_threshold(&mut self, threshold: i32)
pub fn set_compression_threshold(&mut self, threshold: i32)
Set our compression threshold, i.e. the maximum size that a packet is allowed to be without getting compressed. If you set it to less than 0 then compression gets disabled.
Sourcepub fn set_encryption_key(&mut self, key: [u8; 16])
pub fn set_encryption_key(&mut self, key: [u8; 16])
Set the encryption key that is used to encrypt and decrypt packets. It’s the same for both reading and writing.
Sourcepub fn configuration(
self,
) -> Connection<ClientboundConfigurationPacket, ServerboundConfigurationPacket>
pub fn configuration( self, ) -> Connection<ClientboundConfigurationPacket, ServerboundConfigurationPacket>
Change our state from login to configuration. This is the state where the server sends us the registries and resource pack and stuff.
Sourcepub async fn authenticate(
&self,
access_token: &str,
uuid: &Uuid,
private_key: [u8; 16],
packet: &ClientboundHelloPacket,
) -> Result<(), ClientSessionServerError>
pub async fn authenticate( &self, access_token: &str, uuid: &Uuid, private_key: [u8; 16], packet: &ClientboundHelloPacket, ) -> Result<(), ClientSessionServerError>
Authenticate with Minecraft’s servers, which is required to join
online-mode servers. This must happen when you get a
ClientboundLoginPacket::Hello
packet.
§Examples
use azalea_auth::AuthResult;
use azalea_protocol::connect::Connection;
use azalea_protocol::packets::login::{
ClientboundLoginPacket,
serverbound_key_packet::ServerboundKeyPacket
};
use uuid::Uuid;
let AuthResult { access_token, profile } = azalea_auth::auth(
"[email protected]",
azalea_auth::AuthOpts::default()
).await.expect("Couldn't authenticate");
let mut conn = Connection::new(&resolved_address).await?;
// transition to the login state, in a real program we would have done a handshake first
let mut conn = conn.login();
match conn.read().await? {
ClientboundLoginPacket::Hello(p) => {
// tell Mojang we're joining the server & enable encryption
let e = azalea_crypto::encrypt(&p.public_key, &p.challenge).unwrap();
conn.authenticate(
&access_token,
&profile.id,
e.secret_key,
&p
).await?;
conn.write(
ServerboundKeyPacket {
key_bytes: e.encrypted_public_key,
encrypted_challenge: e.encrypted_challenge,
}.get()
).await?;
conn.set_encryption_key(e.secret_key);
}
_ => {}
}
Source§impl Connection<ServerboundHandshakePacket, ClientboundHandshakePacket>
impl Connection<ServerboundHandshakePacket, ClientboundHandshakePacket>
Sourcepub fn login(self) -> Connection<ServerboundLoginPacket, ClientboundLoginPacket>
pub fn login(self) -> Connection<ServerboundLoginPacket, ClientboundLoginPacket>
Change our state from handshake to login. This is the state that is used for logging in.
Sourcepub fn status(
self,
) -> Connection<ServerboundStatusPacket, ClientboundStatusPacket>
pub fn status( self, ) -> Connection<ServerboundStatusPacket, ClientboundStatusPacket>
Change our state from handshake to status. This is the state that is used for pinging the server.
Source§impl Connection<ServerboundLoginPacket, ClientboundLoginPacket>
impl Connection<ServerboundLoginPacket, ClientboundLoginPacket>
Sourcepub fn set_compression_threshold(&mut self, threshold: i32)
pub fn set_compression_threshold(&mut self, threshold: i32)
Set our compression threshold, i.e. the maximum size that a packet is allowed to be without getting compressed. If you set it to less than 0 then compression gets disabled.
Sourcepub fn set_encryption_key(&mut self, key: [u8; 16])
pub fn set_encryption_key(&mut self, key: [u8; 16])
Set the encryption key that is used to encrypt and decrypt packets. It’s the same for both reading and writing.
Sourcepub fn game(self) -> Connection<ServerboundGamePacket, ClientboundGamePacket>
pub fn game(self) -> Connection<ServerboundGamePacket, ClientboundGamePacket>
Change our state from login to game. This is the state that’s used when the client is actually in the game.
Sourcepub async fn authenticate(
&self,
username: &str,
public_key: &[u8],
private_key: &[u8; 16],
ip: Option<&str>,
) -> Result<GameProfile, ServerSessionServerError>
pub async fn authenticate( &self, username: &str, public_key: &[u8], private_key: &[u8; 16], ip: Option<&str>, ) -> Result<GameProfile, ServerSessionServerError>
Verify connecting clients have authenticated with Minecraft’s servers.
This must happen after the client sends a ServerboundLoginPacket::Key
packet.
Sourcepub fn configuration(
self,
) -> Connection<ServerboundConfigurationPacket, ClientboundConfigurationPacket>
pub fn configuration( self, ) -> Connection<ServerboundConfigurationPacket, ClientboundConfigurationPacket>
Change our state back to configuration.
Source§impl Connection<ServerboundConfigurationPacket, ClientboundConfigurationPacket>
impl Connection<ServerboundConfigurationPacket, ClientboundConfigurationPacket>
Sourcepub fn game(self) -> Connection<ServerboundGamePacket, ClientboundGamePacket>
pub fn game(self) -> Connection<ServerboundGamePacket, ClientboundGamePacket>
Change our state from configuration to game. This is the state that’s used when the client is actually in the world.
Source§impl Connection<ClientboundConfigurationPacket, ServerboundConfigurationPacket>
impl Connection<ClientboundConfigurationPacket, ServerboundConfigurationPacket>
Sourcepub fn game(self) -> Connection<ClientboundGamePacket, ServerboundGamePacket>
pub fn game(self) -> Connection<ClientboundGamePacket, ServerboundGamePacket>
Change our state from configuration to game. This is the state that’s used when the client is actually in the world.
Source§impl Connection<ClientboundGamePacket, ServerboundGamePacket>
impl Connection<ClientboundGamePacket, ServerboundGamePacket>
Sourcepub fn configuration(
self,
) -> Connection<ClientboundConfigurationPacket, ServerboundConfigurationPacket>
pub fn configuration( self, ) -> Connection<ClientboundConfigurationPacket, ServerboundConfigurationPacket>
Change our state back to configuration.
Source§impl<R1, W1> Connection<R1, W1>
impl<R1, W1> Connection<R1, W1>
Sourcepub fn from<R2, W2>(connection: Connection<R1, W1>) -> Connection<R2, W2>
pub fn from<R2, W2>(connection: Connection<R1, W1>) -> Connection<R2, W2>
Creates a Connection
of a type from a Connection
of another type.
Useful for servers or custom packets.
Sourcepub fn wrap(stream: TcpStream) -> Connection<R1, W1>
pub fn wrap(stream: TcpStream) -> Connection<R1, W1>
Convert an existing TcpStream
into a Connection
. Useful for servers.
Auto Trait Implementations§
impl<R, W> Freeze for Connection<R, W>
impl<R, W> RefUnwindSafe for Connection<R, W>where
R: RefUnwindSafe,
W: RefUnwindSafe,
impl<R, W> Send for Connection<R, W>
impl<R, W> Sync for Connection<R, W>
impl<R, W> Unpin for Connection<R, W>
impl<R, W> UnwindSafe for Connection<R, W>where
R: UnwindSafe,
W: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: AsAny + ?Sized,
impl<T> Downcast for Twhere
T: AsAny + ?Sized,
§fn downcast_ref<T>(&self) -> Option<&T>where
T: AsAny,
fn downcast_ref<T>(&self) -> Option<&T>where
T: AsAny,
Any
.§fn downcast_mut<T>(&mut self) -> Option<&mut T>where
T: AsAny,
fn downcast_mut<T>(&mut self) -> Option<&mut T>where
T: AsAny,
Any
.§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.