Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Battlefield 3 support and restructurized how the Connection and Packets work #16

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

cdecompilador
Copy link

@cdecompilador cdecompilador commented Dec 27, 2020

First of all probably we will need to change some thing before merge because I haven't tested factorio and minecraft.

Overview of changes

  1. Creation of two important traits Connection and Packet, doing this I try to add extensibility to the project and let people add support to more layouts without the overhead of being careful to not break other implementations (removed builder).
/// NOTE: the `#[async_trait]` macro is to be able to declare async functions
/// NOTE: The connection at least must contain two fields
///     - stream: TcpStream
///     - id: i32
/// Representation of an Rcon Connection, in the high level it con `connect` 
/// with or without password and the it can send commnands `cmd` and it can 
/// `receive_response`, also some low level functions like `receive_packet` and
/// `send_packet` are needed to them be wrapped inside the high level ones
trait Connection {
#[async_trait]
pub trait Connection: Sized {
    type Packet;
    /// Connects to a rcon server, if the password is mandatory is implementation
    /// specific, but ensure in the implementation to allow empty string `""` 
    /// for no password provided and no auth needed
    async fn connect<T: ToSocketAddrs + Send>(address: T, password: &str) -> Result<Self>;

    /// Send a certain command, in the implementation the `command` should be
    /// parsed to a packet ready bytes buffer and sended via `send_packet`
    async fn cmd(&mut self, command: &str) -> Result<String>;

    /// Receives a response from the rcon server, in the implementation it must
    /// call receive packet as many times it requires parse the body and present
    /// it as a clear response String
    async fn receive_response(&mut self) -> io::Result<String>;

    /// Low level function that send a Packet, returns the `id` of the sended 
    /// packet to be incremented
    async fn send_packet(&mut self, packet: Self::Packet) -> io::Result<i32>;

    /// Low level function that receives a Packet
    async fn receive_packet(&mut self) -> io::Result<Self::Packet>;
}
/// NOTE: The `#[async_trait]` macro is to be able to declare async functions 
/// inside the trait. Maybe in the future is its stabilized remove the
/// dependency
#[async_trait]
pub trait Packet: Sized {
    /// Checks if the packet is an error, probably just useful for Responses
    fn is_error(&self) -> bool;

    /// Serializes de packets, aka convert and send
    async fn serialize<T: Unpin + AsyncWrite + Send>(&self, w: &mut T) -> io::Result<()>;

    /// Deserializes de packets, aka receive and convert
    async fn deserialize<T: Unpin + AsyncRead + Send>(r: &mut T) -> io::Result<Self>;

    /// Gets the body of the packet
    fn get_body(&self) -> &str; 
    /// Gets the packet type
    fn get_type(&self) -> PacketType;

    /// Returns the id of the packet and also increments it
    fn get_id(&self) -> i32;
}
  1. The implementation of the metioned traits define the behaviour of the for example MinecraftConnection
  2. Generalized the PacketType to just 3 variants Request, Response and Custom with an asociated number, this a weak point of the PR that maybe we should change a lot.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PacketType {
    Request(i32),
    Response(i32),
    Custom(i32),
}
  1. Also I added lots of comments in the project, even how to packet layout in BTF3 works to make it easier to get started to that component of the project.
/// ### The Battlefield packets are designed in this way:
///      i32 (le)        i32 (le)       i32 (le)   [u8; packet_size - sizeof(i32)*3]
/// -------------------------------------------------------------------------
/// |  sequence  |  packet_size  |  word_count  |           body            |
/// ------------------------------------------------------------------------
/// 
/// Knowing that there are also two special fields:
/// 
/// #### SEQUENCE:
/// 0                 29               30              31    (i32 bits)
/// ----------------------------------------------------
/// |       id        |      type      |     origin    |
/// ----------------------------------------------------
///     id: number that grows apart from the client and the server, the spec
///         doesn't say initial number so we will be using 1 in this 
///         implementation 
///     origin: if this bit = 0, its originated from the server, if its = 1
///             its originated from the client (us) 
///     type: 0 = Request, 1 = Response, ussually we are the request and the 
///           server just response
/// 
/// #### BODY: 
/// The body is composed by a determined number of words and each word 
/// have the following design
///        i32 (le)            [u8; word_size]         u8
/// ------------------------------------------------------------
/// |      word_size    |         word           |    null     |
/// -----------------------------------------------------------
///     NOTE: note that word can only contain ASCII characters and the null
///           terminator is not counted in the word_siz
  1. Added the async-trait dependency for async traits (Connection and Packet)
  2. Added the BTF3 example, I have tested it with lots of commands and situtations and works fine, but factotio and minecraft not sure.

Final words

For the moment the use of async capabilities we are doing are slower than syncronous io but that could change in the future. Hope you like the design and merry christmas! 🎄


This change is Reviewable

@cdecompilador
Copy link
Author

I fixed some minecraft stuff and minecraft works, the only thing remains is factorio and maybe some redesign of how the id works because now is messy.

image

@panicbit
Copy link
Owner

Thanks for the PR! I will do a preliminary review once I get around to it (hopefully within the next 2 days). Let me know when you think the code is ready to be merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants