Skip to content

Commit

Permalink
Made the PyDict conversion method generic.
Browse files Browse the repository at this point in the history
  • Loading branch information
fossum committed Jan 4, 2025
1 parent c13f286 commit 5adbdd5
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 38 deletions.
60 changes: 28 additions & 32 deletions crates/lib/src/games/minecraft/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@ pub mod types;
pub use protocol::*;
pub use types::*;

use crate::{GDErrorKind, GDResult};
use crate::{utils::convert_to_pydict, GDErrorKind, GDResult};
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyList};
use pyo3::types::PyDict;
use std::net::{IpAddr, SocketAddr};

/// The Minecraft package for the gamedig Python library.
///
/// # Example:
/// ```python
/// import gamedig
///
/// # Query a Minecraft server
/// response = gamedig.minecraft.py_query("127.0.0.1", 25565)
/// ```
#[pymodule]
pub fn minecraft(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(py_query, m)?)?;
Expand All @@ -37,49 +46,36 @@ pub fn query(address: &IpAddr, port: Option<u16>) -> GDResult<JavaResponse> {
Err(GDErrorKind::AutoQuery.into())
}

/// Query a Minecraft server.
///
/// # Parameters:
/// - address: str
/// - port: int
///
/// # Returns:
/// - dict: The server response.
///
/// # Example:
/// ```python
/// import gamedig
///
/// # Query a Minecraft server
/// response = gamedig.minecraft.py_query("
#[pyfunction]
pub fn py_query(address: &str, port: u16) -> PyResult<Py<PyDict>> {
let response = query(&address.parse().unwrap(), Some(port));
// None is the default port (which is 27015), could also be Some(27015)

match response { // Result type, must check what it is...
match response {
Err(error) => {
println!("Couldn't query, error: {}", error);
Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!("Couldn't query, error: {}", error)))
},
Ok(r) => {
Python::with_gil(|py| {
let dict = PyDict::new(py);

dict.set_item("game_version", r.game_version)?;
dict.set_item("protocol_version", r.protocol_version)?;
dict.set_item("players_maximum", r.players_maximum)?;
dict.set_item("players_online", r.players_online)?;
dict.set_item("description", r.description)?;
dict.set_item("favicon", r.favicon)?;
dict.set_item("previews_chat", r.previews_chat)?;
dict.set_item("enforces_secure_chat", r.enforces_secure_chat)?;
dict.set_item("server_type", format!("{:?}", r.server_type))?;

if let Some(players) = r.players {
let players_list = PyList::new(py, players.iter().map(|p| {
let player_dict = PyDict::new(py);
player_dict.set_item("name", &p.name).unwrap();
player_dict.set_item("id", &p.id).unwrap();
player_dict
}).collect::<Vec<_>>());
dict.set_item("players", players_list)?;
} else {
dict.set_item("players", py.None())?;
}

Ok(dict.into_py(py))
})
Python::with_gil(|py| convert_to_pydict(py, &r))
}
}
}


/// Query a Java Server.
pub fn query_java(
address: &IpAddr,
Expand Down
59 changes: 53 additions & 6 deletions crates/lib/src/games/minecraft/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
// https://github.com/thisjaiden/golden_apple/blob/master/src/lib.rs

use crate::{
buffer::Buffer,
protocols::{
buffer::Buffer, protocols::{
types::{CommonPlayer, CommonResponse, ExtraRequestSettings, GenericPlayer},
GenericResponse,
},
GDErrorKind::{InvalidInput, PacketBad, UnknownEnumCast},
GDResult,
}, utils::ToPyDict, GDErrorKind::{InvalidInput, PacketBad, UnknownEnumCast}, GDResult
};

use byteorder::ByteOrder;
use pyo3::{types::{PyDict, PyList}, IntoPy, Py, PyResult, Python};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -89,6 +87,36 @@ pub struct JavaResponse {
pub server_type: Server,
}

impl ToPyDict for JavaResponse {
fn to_pydict(&self, py: Python) -> PyResult<Py<PyDict>> {
let dict = PyDict::new(py);

dict.set_item("game_version", &self.game_version)?;
dict.set_item("protocol_version", self.protocol_version)?;
dict.set_item("players_maximum", self.players_maximum)?;
dict.set_item("players_online", self.players_online)?;
dict.set_item("description", &self.description)?;
dict.set_item("favicon", &self.favicon)?;
dict.set_item("previews_chat", self.previews_chat)?;
dict.set_item("enforces_secure_chat", self.enforces_secure_chat)?;
dict.set_item("server_type", format!("{:?}", self.server_type))?;

if let Some(players) = &self.players {
let players_list = PyList::new(py, players.iter().map(|p| {
let player_dict = PyDict::new(py);
player_dict.set_item("name", &p.name).unwrap();
player_dict.set_item("id", &p.id).unwrap();
player_dict
}).collect::<Vec<_>>());
dict.set_item("players", players_list)?;
} else {
dict.set_item("players", py.None())?;
}

Ok(dict.into_py(py))
}
}

/// Java-only additional request settings.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
Expand All @@ -102,7 +130,7 @@ pub struct RequestSettings {
}

impl Default for RequestSettings {
/// `hostname`: "gamedig"
/// `hostname`: "gamedig"
/// `protocol_version`: -1
fn default() -> Self {
Self {
Expand Down Expand Up @@ -174,6 +202,25 @@ pub struct BedrockResponse {
pub server_type: Server,
}

impl ToPyDict for BedrockResponse {
fn to_pydict(&self, py: Python) -> PyResult<Py<PyDict>> {
let dict = PyDict::new(py);

dict.set_item("edition", &self.edition)?;
dict.set_item("name", &self.name)?;
dict.set_item("game_version", &self.version_name)?;
dict.set_item("protocol_version", &self.protocol_version)?;
dict.set_item("players_maximum", self.players_maximum)?;
dict.set_item("players_online", self.players_online)?;
dict.set_item("id", &self.id)?;
dict.set_item("map", &self.map)?;
dict.set_item("game_mode", format!("{:?}", self.game_mode))?;
dict.set_item("server_type", format!("{:?}", self.server_type))?;

Ok(dict.into_py(py))
}
}

impl CommonResponse for BedrockResponse {
fn as_original(&self) -> GenericResponse { GenericResponse::Minecraft(VersionedResponse::Bedrock(self)) }

Expand Down
10 changes: 10 additions & 0 deletions crates/lib/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::GDErrorKind::{PacketOverflow, PacketReceive, PacketSend, PacketUnderflow};
use crate::GDResult;
use std::cmp::Ordering;
use pyo3::prelude::*;
use pyo3::types::PyDict;

pub fn error_by_expected_size(expected: usize, size: usize) -> GDResult<()> {
match size.cmp(&expected) {
Expand Down Expand Up @@ -29,6 +31,14 @@ pub fn retry_on_timeout<T>(mut retry_count: usize, mut fetch: impl FnMut() -> GD
Err(last_err)
}

pub trait ToPyDict {
fn to_pydict(&self, py: Python) -> PyResult<Py<PyDict>>;
}

pub fn convert_to_pydict<T: ToPyDict>(py: Python, value: &T) -> PyResult<Py<PyDict>> {
value.to_pydict(py)
}

/// Run gather_fn based on the value of gather_toggle.
///
/// # Parameters
Expand Down

0 comments on commit 5adbdd5

Please sign in to comment.