summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2025-09-19 22:59:22 +0800
committerlittleblack111 <littleblack11111@gmail.com>2025-09-20 23:34:15 +0800
commitc7a2788158628d3445f0f3574a0d7adfabd0a755 (patch)
tree0c0e973b70f07cd4797b60bd17ca6d4b8e0f348d /src/server
parent6511f6aaf68c3ab3bce10cdd743936b28e45dfa9 (diff)
init
Diffstat (limited to 'src/server')
-rw-r--r--src/server/main.rs6
-rw-r--r--src/server/server.rs9
-rw-r--r--src/server/server/tcpserver.rs2
-rw-r--r--src/server/server/tcpserver/server.rs146
-rw-r--r--src/server/server/tcpserver/tasks.rs20
5 files changed, 183 insertions, 0 deletions
diff --git a/src/server/main.rs b/src/server/main.rs
new file mode 100644
index 0000000..a8bbad8
--- /dev/null
+++ b/src/server/main.rs
@@ -0,0 +1,6 @@
+pub(crate) mod server;
+
+#[tokio::main]
+async fn main() {
+ todo!();
+}
diff --git a/src/server/server.rs b/src/server/server.rs
new file mode 100644
index 0000000..fcc6e7f
--- /dev/null
+++ b/src/server/server.rs
@@ -0,0 +1,9 @@
+use remote_control_rs::tasks::Task;
+
+pub mod tcpserver;
+
+pub trait Server<'a> {
+ fn update(&mut self, task: Task);
+
+ async fn listen(&mut self) -> !;
+}
diff --git a/src/server/server/tcpserver.rs b/src/server/server/tcpserver.rs
new file mode 100644
index 0000000..1af118c
--- /dev/null
+++ b/src/server/server/tcpserver.rs
@@ -0,0 +1,2 @@
+pub mod server;
+pub mod tasks;
diff --git a/src/server/server/tcpserver/server.rs b/src/server/server/tcpserver/server.rs
new file mode 100644
index 0000000..551aea1
--- /dev/null
+++ b/src/server/server/tcpserver/server.rs
@@ -0,0 +1,146 @@
+use std::{
+ cell::RefCell,
+ net::SocketAddr,
+ sync::{Arc, Weak},
+};
+
+use remote_control_rs::{client, tasks::Task};
+use tokio::{
+ io::{self, AsyncReadExt},
+ net::{TcpListener, TcpStream},
+};
+
+use crate::server::{
+ Server,
+ tcpserver::tasks::{Request, RequestType},
+};
+
+struct TCPServer<'a> {
+ this: RefCell<Weak<Self>>,
+ task: Option<Task>,
+ listener: TcpListener,
+ clients: RefCell<Vec<Client<'a>>>,
+}
+
+impl<'a> TCPServer<'a> {
+ fn new(listener: TcpListener) -> Arc<Self> {
+ let s = Arc::new(Self { this: RefCell::new(Weak::new()), listener, task: None, clients: RefCell::new(Vec::new()) });
+ *s.this.borrow_mut() = Arc::downgrade(&s);
+ s
+ }
+
+ fn remove(&self, client: &Client<'a>) {
+ self.clients.borrow_mut().retain(|c| c != client);
+ }
+}
+
+impl<'a> Server<'a> for TCPServer<'a> {
+ fn update(&mut self, task: Task) {
+ self.task = Some(task);
+ }
+
+ async fn listen(&mut self) -> ! {
+ loop {
+ match self.listener.accept().await {
+ Ok((socket, addr)) => self.clients.borrow_mut().push(Client::new(self.this.borrow().upgrade().unwrap(), socket, addr)), // the unwrap shouldn't panics, self has to be alive
+ Err(e) => eprintln!("Failed to accept connection: {e}"),
+ };
+ }
+ }
+}
+
+struct Client<'a> {
+ server: Arc<TCPServer<'a>>,
+ stream: TcpStream,
+ addr: SocketAddr,
+ data: Option<client::Client<'a>>,
+}
+
+impl<'a> Client<'a> {
+ fn new(server: Arc<TCPServer<'a>>, stream: TcpStream, addr: SocketAddr) -> Self {
+ Self { server, stream, addr, data: None }
+ }
+
+ fn handle_read(&mut self, buf: io::Result<usize>) -> bool {
+ match buf {
+ Ok(0) => self.server.remove(self),
+ Ok(_) => {}
+ Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return false,
+ Err(e) => {
+ eprintln!("Failed to read from client: {e}");
+ return false;
+ }
+ }
+ true
+ }
+
+ // TODO: use framed
+ async fn read(&mut self) -> Option<(Vec<u8>, usize)> {
+ const usize: usize = std::mem::size_of::<usize>();
+ let mut len = vec![0; usize]; // vec! only take usize
+ if !self.handle_read(self.stream.try_read(&mut len)) {
+ false;
+ }
+ let len = usize::from_be_bytes(match len.try_into() {
+ Ok(n) => n,
+ Err(e) => {
+ eprintln!("Failed to convert length bytes to length usize: {:?}", e);
+ return None;
+ }
+ }); // TODO: move to a shared fn with client to ensure we use same endian
+ let mut buf = vec![0; len];
+ let read = self.stream.read_exact(&mut buf).await;
+ if !self.handle_read(read) {
+ return None;
+ }
+ Some((buf, len))
+ }
+
+ async fn poll(&mut self) -> ! {
+ loop {
+ if let Err(e) = self.stream.readable().await {
+ eprintln!("Failed waiting for client to be readable: {e}");
+ continue;
+ }
+ if let Some((buf, len)) = self.read().await {
+ let req: RequestType = match bincode::serde::decode_from_slice(buf.as_slice(), bincode::config::standard()) {
+ Ok((decoded, size)) => {
+ if size != len {
+ eprintln!("Decoded size {size} does not match expected size {len}, decode succeeded anyways?");
+ }
+ decoded
+ }
+ Err(e) => {
+ eprintln!("Failed to decode request from client {}: {e}", self.addr);
+ continue;
+ }
+ };
+ match req {
+ // TODO: seperate send and respond
+ RequestType::Send(req) => match req {
+ Request::Get(req) => {
+ todo!()
+ }
+ Request::Post(req) => {
+ todo!()
+ }
+ },
+ RequestType::Respond(res) => match res {
+ Request::Get(req) => {
+ todo!()
+ }
+ Request::Post(req) => {
+ todo!()
+ }
+ },
+ }
+ }
+ }
+ }
+}
+
+impl<'a> PartialEq for Client<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ self.data == other.data
+ }
+}
diff --git a/src/server/server/tcpserver/tasks.rs b/src/server/server/tcpserver/tasks.rs
new file mode 100644
index 0000000..23e6f9e
--- /dev/null
+++ b/src/server/server/tcpserver/tasks.rs
@@ -0,0 +1,20 @@
+use remote_control_rs::tasks::{CompletedTask, Name};
+use serde::Deserialize;
+
+#[derive(Deserialize)]
+pub enum RequestType {
+ Send(Request),
+ Respond(Request),
+}
+
+#[derive(Deserialize)]
+pub enum Request {
+ Get(TaskType),
+ Post(TaskType),
+}
+
+#[derive(Deserialize)]
+pub enum TaskType {
+ Completed(CompletedTask),
+ Pending(Name),
+}