pub fn deserialize_packet<P: ProtocolPacket + Debug>(
stream: &mut Cursor<&[u8]>,
) -> Result<P, Box<ReadPacketError>>Examples found in repository?
azalea-protocol/examples/packet_logger.rs (lines 360-362)
205async fn proxy_conn(
206 mut client_conn: Connection<ServerboundLoginPacket, ClientboundLoginPacket>,
207) -> Result<(), Box<dyn Error>> {
208 // resolve TARGET_ADDR
209 let parsed_target_addr = ServerAddr::try_from(TARGET_ADDR).unwrap();
210 let resolved_target_addr = resolve_address(&parsed_target_addr).await?;
211
212 let mut server_conn = Connection::new(&resolved_target_addr).await?;
213
214 let account = if ACCOUNT.contains('@') {
215 Account::microsoft(ACCOUNT).await?
216 } else {
217 Account::offline(ACCOUNT)
218 };
219 println!("got account: {:?}", account);
220
221 server_conn
222 .write(ServerboundIntention {
223 protocol_version: PROTOCOL_VERSION,
224 hostname: parsed_target_addr.host,
225 port: parsed_target_addr.port,
226 intention: ClientIntention::Login,
227 })
228 .await?;
229 let mut server_conn = server_conn.login();
230
231 // login
232 server_conn
233 .write(ServerboundHello {
234 name: account.username().to_owned(),
235 profile_id: account.uuid(),
236 })
237 .await?;
238
239 let (server_conn, login_finished) = loop {
240 let packet = server_conn.read().await?;
241
242 println!("got packet: {:?}", packet);
243
244 match packet {
245 ClientboundLoginPacket::Hello(p) => {
246 debug!("Got encryption request");
247 let e = azalea_crypto::encrypt(&p.public_key, &p.challenge).unwrap();
248
249 if let Some(access_token) = account.access_token() {
250 // keep track of the number of times we tried
251 // authenticating so we can give up after too many
252 let mut attempts: usize = 1;
253
254 while let Err(e) = {
255 server_conn
256 .authenticate(&access_token, &account.uuid(), e.secret_key, &p, None)
257 .await
258 } {
259 if attempts >= 2 {
260 // if this is the second attempt and we failed
261 // both times, give up
262 return Err(e.into());
263 }
264 if matches!(
265 e,
266 ClientSessionServerError::InvalidSession
267 | ClientSessionServerError::ForbiddenOperation
268 ) {
269 // uh oh, we got an invalid session and have
270 // to reauthenticate now
271 account.refresh().await?;
272 } else {
273 return Err(e.into());
274 }
275 attempts += 1;
276 }
277 }
278
279 server_conn
280 .write(ServerboundKey {
281 key_bytes: e.encrypted_public_key,
282 encrypted_challenge: e.encrypted_challenge,
283 })
284 .await?;
285
286 server_conn.set_encryption_key(e.secret_key);
287 }
288 ClientboundLoginPacket::LoginCompression(p) => {
289 debug!("Got compression request {:?}", p.compression_threshold);
290 server_conn.set_compression_threshold(p.compression_threshold);
291 }
292 ClientboundLoginPacket::LoginFinished(p) => {
293 debug!(
294 "Got profile {:?}. handshake is finished and we're now switching to the configuration state",
295 p.game_profile
296 );
297 // server_conn.write(ServerboundLoginAcknowledged {}).await?;
298 break (server_conn.config(), p);
299 }
300 ClientboundLoginPacket::LoginDisconnect(p) => {
301 error!("Got disconnect {p:?}");
302 return Err("Disconnected".into());
303 }
304 ClientboundLoginPacket::CustomQuery(p) => {
305 debug!("Got custom query {:?}", p);
306 // replying to custom query is done in
307 // packet_handling::login::process_packet_events
308 }
309 ClientboundLoginPacket::CookieRequest(p) => {
310 debug!("Got cookie request {:?}", p);
311
312 server_conn
313 .write(packets::login::ServerboundCookieResponse {
314 key: p.key,
315 // cookies aren't implemented
316 payload: None,
317 })
318 .await?;
319 }
320 }
321 };
322
323 // give the client the login_finished
324 println!("got the login_finished: {:?}", login_finished);
325 client_conn.write(login_finished).await?;
326 let client_conn = client_conn.config();
327
328 info!("started direct bridging");
329
330 // bridge packets
331 let listen_raw_reader = client_conn.reader.raw;
332 let listen_raw_writer = client_conn.writer.raw;
333
334 let target_raw_reader = server_conn.reader.raw;
335 let target_raw_writer = server_conn.writer.raw;
336
337 let packet_logs_txt = Arc::new(tokio::sync::Mutex::new(
338 File::create("combined.txt").await.unwrap(),
339 ));
340
341 let packet_logs_txt_clone = packet_logs_txt.clone();
342 let copy_listen_to_target = tokio::spawn(async move {
343 let mut listen_raw_reader = listen_raw_reader;
344 let mut target_raw_writer = target_raw_writer;
345
346 let packet_logs_txt = packet_logs_txt_clone;
347
348 let mut serverbound_parsed_txt = File::create("serverbound.txt").await.unwrap();
349
350 loop {
351 let packet = match listen_raw_reader.read().await {
352 Ok(p) => p,
353 Err(e) => {
354 error!("Error reading packet from listen: {e}");
355 return;
356 }
357 };
358
359 // decode as a game packet
360 let decoded_packet = azalea_protocol::read::deserialize_packet::<ServerboundGamePacket>(
361 &mut Cursor::new(&packet),
362 );
363
364 if let Ok(decoded_packet) = decoded_packet {
365 let timestamp = chrono::Utc::now();
366 let _ = serverbound_parsed_txt
367 .write_all(format!("{timestamp} {:?}\n", decoded_packet).as_bytes())
368 .await;
369 let _ = packet_logs_txt
370 .lock()
371 .await
372 .write_all(format!("{timestamp} <- {:?}\n", decoded_packet).as_bytes())
373 .await;
374 }
375
376 match target_raw_writer.write(&packet).await {
377 Ok(_) => {}
378 Err(e) => {
379 error!("Error writing packet to target: {e}");
380 return;
381 }
382 }
383 }
384 });
385
386 // write to clientbound.txt in a separate task so it doesn't block receiving
387 // packets
388 let (clientbound_tx, mut clientbound_rx) = tokio::sync::mpsc::unbounded_channel::<Box<[u8]>>();
389 let copy_clientbound_to_file = tokio::spawn(async move {
390 let mut clientbound_parsed_txt = File::create("clientbound.txt").await.unwrap();
391
392 loop {
393 let Some(packet) = clientbound_rx.recv().await else {
394 return;
395 };
396
397 // decode as a game packet
398 let decoded_packet = azalea_protocol::read::deserialize_packet::<ClientboundGamePacket>(
399 &mut Cursor::new(&packet),
400 );
401
402 if let Ok(decoded_packet) = decoded_packet {
403 let timestamp = chrono::Utc::now();
404 let _ = clientbound_parsed_txt
405 .write_all(format!("{timestamp} {decoded_packet:?}\n").as_bytes())
406 .await;
407 let _ = packet_logs_txt
408 .lock()
409 .await
410 .write_all(format!("{timestamp} -> {decoded_packet:?}\n").as_bytes())
411 .await;
412 }
413 }
414 });
415
416 let copy_remote_to_local = tokio::spawn(async move {
417 let mut target_raw_reader = target_raw_reader;
418 let mut listen_raw_writer = listen_raw_writer;
419
420 loop {
421 let packet = match target_raw_reader.read().await {
422 Ok(p) => p,
423 Err(e) => {
424 error!("Error reading packet from target: {e}");
425 return;
426 }
427 };
428
429 clientbound_tx.send(packet.clone()).unwrap();
430
431 match listen_raw_writer.write(&packet).await {
432 Ok(_) => {}
433 Err(e) => {
434 error!("Error writing packet to listen: {e}");
435 return;
436 }
437 }
438 }
439 });
440
441 tokio::try_join!(
442 copy_listen_to_target,
443 copy_remote_to_local,
444 copy_clientbound_to_file
445 )?;
446
447 Ok(())
448}