Allow creating handlers to have different behavior
This commit is contained in:
Родитель
b4f7feda03
Коммит
6abbe4d282
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,79 +1,89 @@
|
|||
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
|
||||
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 (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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl CheatEngineServer {
|
||||
pub fn new() -> Self {
|
||||
CheatEngineServer::new_port(DEFAULT_PORT)
|
||||
}
|
||||
pub struct CheatEngineConnection(TcpStream);
|
||||
|
||||
pub fn new_port(port: u16) -> Self {
|
||||
CheatEngineServer {port}
|
||||
}
|
||||
// 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();
|
||||
|
||||
pub async fn run(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let listener = TcpListener::bind(("127.0.0.1", self.port)).await?;
|
||||
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 (mut socket, addr) = listener.accept().await?;
|
||||
info!("New socket opened: {}", addr);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut buf = [0; 1024];
|
||||
|
||||
// In a loop, read data from the socket and write the data back.
|
||||
loop {
|
||||
let n = match socket.read(&mut buf).await {
|
||||
// socket closed
|
||||
Ok(n) if n == 0 => return,
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
error!("failed to read from socket; err = {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let request = &buf[..n];
|
||||
debug!("incoming data({}): {:?}", request[0], request);
|
||||
|
||||
// Write the data back
|
||||
let response = Self::handle(request);
|
||||
if let Err(e) = socket.write_all(&response[..]).await {
|
||||
error!("failed to write to socket; err = {:?}", e);
|
||||
return;
|
||||
}
|
||||
let n = match socket.read(&mut buf).await {
|
||||
// socket closed
|
||||
Ok(n) if n == 0 => return,
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
error!("failed to read from socket; err = {:?}", e);
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let request = &buf[..n];
|
||||
debug!("incoming data({}): {:?}", request[0], request);
|
||||
|
||||
// Write the data back
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче