Allow creating handlers to have different behavior

This commit is contained in:
HoLLy 2020-11-13 23:39:14 +01:00
Родитель b4f7feda03
Коммит 6abbe4d282
5 изменённых файлов: 118 добавлений и 83 удалений

Просмотреть файл

@ -8,8 +8,7 @@ fn main() {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let server = server::CheatEngineServer::new();
server.run().await.unwrap();
server::run::<server::TestHandler>().await.unwrap();
})
}

Просмотреть файл

@ -1,17 +1,15 @@
use std::fmt::Debug;
use bytes::Buf;
use log::warn;
use super::{command::*, commands_response::*};
use super::command::Command;
pub trait CERequest : Debug {
type Response: CEResponse + Debug;
pub trait CERequest : Debug + Send {
type Response: CEResponse + Debug + Send;
const ID: Command;
fn read(buf: &mut dyn Buf) -> Self;
fn process(self) -> Self::Response;
}
#[derive(Debug)]
@ -31,13 +29,6 @@ impl CERequest for CreateToolHelp32SnapshotRequest {
process_id: buf.get_u32_le(),
}
}
fn process(self) -> CreateToolHelp32SnapshotResponse {
warn!("Stubbed CreateToolHelp32SnapshotResponse::process"); // TODO
CreateToolHelp32SnapshotResponse {
handle: 0
}
}
}
#[derive(Debug)]
@ -55,11 +46,4 @@ impl CERequest for Process32FirstRequest {
handle: buf.get_u32_le(),
}
}
fn process(self) -> Process32FirstResponse {
warn!("Stubbed Process32FirstResponse::process"); // TODO
Process32FirstResponse {
result: false,
}
}
}

40
src/server/handler.rs Normal file
Просмотреть файл

@ -0,0 +1,40 @@
use log::warn;
use super::{commands_response::*, commands_request::*};
pub trait HandlerFactory<T: FullHandler> {
}
pub trait FullHandler
: Handler<CreateToolHelp32SnapshotRequest>
+ Handler<Process32FirstRequest> {
fn create() -> Self;
}
pub trait Handler<TReq: CERequest> {
fn handle(&self, req: TReq) -> TReq::Response;
}
pub struct TestHandler;
impl FullHandler for TestHandler {
fn create() -> TestHandler { TestHandler }
}
impl Handler<CreateToolHelp32SnapshotRequest> for TestHandler {
fn handle(&self, _req: CreateToolHelp32SnapshotRequest) -> CreateToolHelp32SnapshotResponse {
warn!("Stubbed CreateToolHelp32SnapshotResponse::process"); // TODO
CreateToolHelp32SnapshotResponse {
handle: 0
}
}
}
impl Handler<Process32FirstRequest> for TestHandler {
fn handle(&self, _req: Process32FirstRequest) -> Process32FirstResponse {
warn!("Stubbed Process32FirstResponse::process"); // TODO
Process32FirstResponse {
result: false,
}
}
}

Просмотреть файл

@ -2,5 +2,7 @@ mod server;
mod command;
mod commands_request;
mod commands_response;
mod handler;
pub use server::CheatEngineServer;
pub use server::run;
pub use handler::TestHandler;

Просмотреть файл

@ -1,36 +1,61 @@
use log::{info, debug, error};
use tokio::net::TcpListener;
use tokio::prelude::*;
use bytes::Buf;
use log::{info, debug, error};
use tokio::net::{TcpListener, TcpStream};
use tokio::prelude::*;
use super::{commands_request::*, commands_response::*};
use super::{handler::*, commands_request::*, commands_response::*};
const DEFAULT_PORT: u16 = 52736;
pub struct CheatEngineServer {
port: u16
}
impl CheatEngineServer {
pub fn new() -> Self {
CheatEngineServer::new_port(DEFAULT_PORT)
}
pub fn new_port(port: u16) -> Self {
CheatEngineServer {port}
}
pub async fn run(&self) -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind(("127.0.0.1", self.port)).await?;
pub async fn run<T: FullHandler + Send>() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind(("127.0.0.1", DEFAULT_PORT)).await?;
loop {
let (mut socket, addr) = listener.accept().await?;
let (socket, addr) = listener.accept().await?;
info!("New socket opened: {}", addr);
tokio::spawn(async move {
let conn = CheatEngineConnection(socket);
let handler = T::create();
conn.run(handler).await;
});
}
}
pub struct CheatEngineConnection(TcpStream);
// generics werent powerful enough
macro_rules! gen_request_dispatch {
($bytes: ident for $handler: ident, $($request: ty),*) => {
match $bytes.get_u8() {
$(
<$request>::ID => gen_request_dispatch!($request, $bytes, $handler),
)*
byte => todo!("Unimplemented packet byte {}", byte),
}
};
($request: ty, $bytes: ident, $handler: ident) => {
{
let mut buffer = Vec::new();
let request = <$request>::read(&mut $bytes);
debug!("Received item {:?}", request);
let response = $handler.handle(request);
debug!("... responding with {:?}", response);
response.serialize(&mut buffer);
buffer
}
};
}
impl CheatEngineConnection {
pub async fn run(self, handler: impl FullHandler) {
let mut buf = [0; 1024];
// In a loop, read data from the socket and write the data back.
let mut socket = self.0;
loop {
let n = match socket.read(&mut buf).await {
// socket closed
@ -46,34 +71,19 @@ impl CheatEngineServer {
debug!("incoming data({}): {:?}", request[0], request);
// Write the data back
let response = Self::handle(request);
let response = Self::handle(request, &handler);
if let Err(e) = socket.write_all(&response[..]).await {
error!("failed to write to socket; err = {:?}", e);
return;
}
}
});
}
}
fn handle(mut bytes: &[u8]) -> Vec<u8> {
match bytes.get_u8() {
CreateToolHelp32SnapshotRequest::ID => Self::handle_packet::<CreateToolHelp32SnapshotRequest>(&mut bytes),
Process32FirstRequest::ID => Self::handle_packet::<Process32FirstRequest>(&mut bytes),
_ => todo!(),
}
}
fn handle_packet<TReq: CERequest>(mut bytes: &[u8]) -> Vec<u8> {
let mut buffer = Vec::new();
let request = TReq::read(&mut bytes);
debug!("Received item {:?}", request);
let response = request.process();
debug!("... responding with {:?}", response);
response.serialize(&mut buffer);
buffer
fn handle(mut bytes: &[u8], handler: &impl FullHandler) -> Vec<u8> {
gen_request_dispatch!(
bytes for handler,
CreateToolHelp32SnapshotRequest,
Process32FirstRequest
)
}
}