Skip to content

Commit 4fad20c

Browse files
committed
separate functions that use proxy and make JoinOpts a thing
1 parent 0c2c44e commit 4fad20c

File tree

7 files changed

+202
-106
lines changed

7 files changed

+202
-106
lines changed

azalea-client/src/client.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,11 @@ impl Client {
242242
entity
243243
};
244244

245-
let conn = Connection::new(resolved_address, proxy).await?;
245+
let conn = if let Some(proxy) = proxy {
246+
Connection::new_with_proxy(resolved_address, proxy).await?
247+
} else {
248+
Connection::new(resolved_address).await?
249+
};
246250
let (conn, game_profile) =
247251
Self::handshake(ecs_lock.clone(), entity, conn, account, address).await?;
248252

azalea-client/src/ping.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
use azalea_protocol::{
44
connect::{Connection, ConnectionError, Proxy},
55
packets::{
6-
handshaking::client_intention_packet::ClientIntentionPacket,
6+
handshaking::{
7+
client_intention_packet::ClientIntentionPacket, ClientboundHandshakePacket,
8+
ServerboundHandshakePacket,
9+
},
710
status::{
811
clientbound_status_response_packet::ClientboundStatusResponsePacket,
912
serverbound_status_request_packet::ServerboundStatusRequestPacket,
@@ -45,14 +48,31 @@ pub enum PingError {
4548
/// ```
4649
pub async fn ping_server(
4750
address: impl TryInto<ServerAddress>,
48-
proxy: Option<Proxy>
4951
) -> Result<ClientboundStatusResponsePacket, PingError> {
5052
let address: ServerAddress = address.try_into().map_err(|_| PingError::InvalidAddress)?;
51-
5253
let resolved_address = resolver::resolve_address(&address).await?;
54+
let conn = Connection::new(&resolved_address).await?;
55+
ping_server_with_connection(address, conn).await
56+
}
5357

54-
let mut conn = Connection::new(&resolved_address, proxy).await?;
58+
/// Ping a Minecraft server through a Socks5 proxy.
59+
pub async fn ping_server_with_proxy(
60+
address: impl TryInto<ServerAddress>,
61+
proxy: Proxy,
62+
) -> Result<ClientboundStatusResponsePacket, PingError> {
63+
let address: ServerAddress = address.try_into().map_err(|_| PingError::InvalidAddress)?;
64+
let resolved_address = resolver::resolve_address(&address).await?;
65+
let conn = Connection::new_with_proxy(&resolved_address, proxy).await?;
66+
ping_server_with_connection(address, conn).await
67+
}
5568

69+
/// Ping a Minecraft server after we've already created a [`Connection`]. The
70+
/// `Connection` must still be in the handshake state (which is the state it's
71+
/// in immediately after it's created).
72+
pub async fn ping_server_with_connection(
73+
address: ServerAddress,
74+
mut conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>,
75+
) -> Result<ClientboundStatusResponsePacket, PingError> {
5676
// send the client intention packet and switch to the status state
5777
conn.write(
5878
ClientIntentionPacket {

azalea-protocol/src/connect.rs

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ use socks5_impl::protocol::UserKey;
262262
#[derive(Debug, Clone)]
263263
pub struct Proxy {
264264
pub addr: SocketAddr,
265-
pub auth: Option<UserKey>
265+
pub auth: Option<UserKey>,
266266
}
267267

268268
impl Proxy {
@@ -273,29 +273,35 @@ impl Proxy {
273273

274274
impl Connection<ClientboundHandshakePacket, ServerboundHandshakePacket> {
275275
/// Create a new connection to the given address.
276-
pub async fn new(address: &SocketAddr, proxy: Option<Proxy>) -> Result<Self, ConnectionError> {
277-
let (read_stream, write_stream) = match proxy {
278-
Some(proxy) => {
279-
let proxy_stream = TcpStream::connect(proxy.addr).await?;
280-
let mut stream = BufStream::new(proxy_stream);
281-
let auth = match proxy.auth {
282-
Some(user_key) => Some(user_key),
283-
None => None,
284-
};
285-
286-
let _ = socks5_impl::client::connect(&mut stream, address, auth).await
287-
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
288-
stream.into_inner()
289-
},
290-
None => {
291-
let stream = TcpStream::connect(address).await?;
276+
pub async fn new(address: &SocketAddr) -> Result<Self, ConnectionError> {
277+
let stream = TcpStream::connect(address).await?;
292278

293-
// enable tcp_nodelay
294-
stream.set_nodelay(true)?;
279+
// enable tcp_nodelay
280+
stream.set_nodelay(true)?;
295281

296-
stream
297-
},
298-
}.into_split();
282+
Self::new_from_stream(stream).await
283+
}
284+
285+
/// Create a new connection to the given address and Socks5 proxy. If you're
286+
/// not using a proxy, use [`Self::new`] instead.
287+
pub async fn new_with_proxy(
288+
address: &SocketAddr,
289+
proxy: Proxy,
290+
) -> Result<Self, ConnectionError> {
291+
let proxy_stream = TcpStream::connect(proxy.addr).await?;
292+
let mut stream = BufStream::new(proxy_stream);
293+
294+
let _ = socks5_impl::client::connect(&mut stream, address, proxy.auth)
295+
.await
296+
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
297+
298+
Self::new_from_stream(stream.into_inner()).await
299+
}
300+
301+
/// Create a new connection from an existing stream. Useful if you want to
302+
/// set custom options on the stream. Otherwise, just use [`Self::new`].
303+
pub async fn new_from_stream(stream: TcpStream) -> Result<Self, ConnectionError> {
304+
let (read_stream, write_stream) = stream.into_split();
299305

300306
Ok(Connection {
301307
reader: ReadConnection {

azalea/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ bevy_log = "0.13.0"
4444
azalea-entity = { version = "0.9.0", path = "../azalea-entity" }
4545
bevy_time = "0.13.0"
4646
rustc-hash = "1.1.0"
47-
rand = "0.8.5"
4847

4948
[dev-dependencies]
5049
criterion = "0.5.1"
50+
rand = "0.8.5"
5151

5252
[features]
5353
default = ["log"]

azalea/examples/testbot/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,12 @@ async fn swarm_handle(
181181
_state: SwarmState,
182182
) -> anyhow::Result<()> {
183183
match &event {
184-
SwarmEvent::Disconnect(account) => {
184+
SwarmEvent::Disconnect(account, join_opts) => {
185185
println!("bot got kicked! {}", account.username);
186186
tokio::time::sleep(Duration::from_secs(5)).await;
187-
swarm.add_and_retry_forever(account, State::default()).await;
187+
swarm
188+
.add_and_retry_forever_with_opts(account, State::default(), join_opts)
189+
.await;
188190
}
189191
SwarmEvent::Chat(chat) => {
190192
if chat.message().to_string() == "The particle was not visible for anybody" {

azalea/src/lib.rs

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub use azalea_world as world;
3838
pub use bot::*;
3939
use ecs::component::Component;
4040
use futures::{future::BoxFuture, Future};
41+
use protocol::connect::Proxy;
4142
use protocol::{resolver::ResolverError, ServerAddress};
4243
use swarm::SwarmBuilder;
4344
use thiserror::Error;
@@ -185,30 +186,26 @@ where
185186
account: Account,
186187
address: impl TryInto<ServerAddress>,
187188
) -> Result<!, StartError> {
188-
self.swarm.accounts = vec![account];
189+
self.swarm.accounts = vec![(account, JoinOpts::default())];
189190
if self.swarm.states.is_empty() {
190191
self.swarm.states = vec![S::default()];
191192
}
192193
self.swarm.start(address).await
193194
}
194195

195-
/// Do the same as [`Self::start`], but allow passing in a custom resolved
196-
/// address. This is useful if the address you're connecting to doesn't
197-
/// resolve to anything, like if the server uses the address field to pass
198-
/// custom data (like Bungeecord or Forge).
199-
pub async fn start_with_custom_resolved_address(
196+
/// Do the same as [`Self::start`], but allow passing in custom join
197+
/// options.
198+
pub async fn start_with_opts(
200199
mut self,
201200
account: Account,
202201
address: impl TryInto<ServerAddress>,
203-
resolved_address: SocketAddr,
202+
opts: JoinOpts,
204203
) -> Result<!, StartError> {
205-
self.swarm.accounts = vec![account];
204+
self.swarm.accounts = vec![(account, opts.clone())];
206205
if self.swarm.states.is_empty() {
207206
self.swarm.states = vec![S::default()];
208207
}
209-
self.swarm
210-
.start_with_custom_resolved_address(address, resolved_address)
211-
.await
208+
self.swarm.start_with_default_opts(address, opts).await
212209
}
213210
}
214211
impl Default for ClientBuilder<NoState> {
@@ -224,3 +221,55 @@ impl Default for ClientBuilder<NoState> {
224221
/// [`SwarmBuilder`]: swarm::SwarmBuilder
225222
#[derive(Component, Clone, Default)]
226223
pub struct NoState;
224+
225+
/// Optional settings when adding an account to a swarm or client.
226+
#[derive(Clone, Debug, Default)]
227+
#[non_exhaustive]
228+
pub struct JoinOpts {
229+
/// The Socks5 proxy that this bot will use.
230+
pub proxy: Option<Proxy>,
231+
/// Override the server address that this specific bot will send in the
232+
/// handshake packet.
233+
pub custom_address: Option<ServerAddress>,
234+
/// Override the socket address that this specific bot will use to connect
235+
/// to the server.
236+
pub custom_resolved_address: Option<SocketAddr>,
237+
}
238+
239+
impl JoinOpts {
240+
pub fn new() -> Self {
241+
Self::default()
242+
}
243+
244+
pub fn update(&mut self, other: &Self) {
245+
if let Some(proxy) = other.proxy.clone() {
246+
self.proxy = Some(proxy);
247+
}
248+
if let Some(custom_address) = other.custom_address.clone() {
249+
self.custom_address = Some(custom_address);
250+
}
251+
if let Some(custom_resolved_address) = other.custom_resolved_address {
252+
self.custom_resolved_address = Some(custom_resolved_address);
253+
}
254+
}
255+
256+
/// Set the proxy that this bot will use.
257+
#[must_use]
258+
pub fn proxy(mut self, proxy: Proxy) -> Self {
259+
self.proxy = Some(proxy);
260+
self
261+
}
262+
/// Set the custom address that this bot will send in the handshake packet.
263+
#[must_use]
264+
pub fn custom_address(mut self, custom_address: ServerAddress) -> Self {
265+
self.custom_address = Some(custom_address);
266+
self
267+
}
268+
/// Set the custom resolved address that this bot will use to connect to the
269+
/// server.
270+
#[must_use]
271+
pub fn custom_resolved_address(mut self, custom_resolved_address: SocketAddr) -> Self {
272+
self.custom_resolved_address = Some(custom_resolved_address);
273+
self
274+
}
275+
}

0 commit comments

Comments
 (0)