refactor(upload): route upload commands to dedicated handler
This commit is contained in:
+42
-84
@@ -8,17 +8,12 @@ use tokio::{
|
|||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::{protocol::{
|
||||||
decode_header,
|
Command, HEADER_SIZE, Header, MAX_BODY_SIZE, decode_header,
|
||||||
Header,
|
}, upload};
|
||||||
HEADER_SIZE,
|
|
||||||
MAX_BODY_SIZE,
|
|
||||||
Command,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IncomingMessage {
|
struct IncomingMessage {
|
||||||
header: Header,
|
header: Header,
|
||||||
body: Vec<u8>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Connection {
|
pub struct Connection {
|
||||||
@@ -51,7 +46,7 @@ impl Connection {
|
|||||||
|
|
||||||
while let Some(message) = self.read_message().await? {
|
while let Some(message) = self.read_message().await? {
|
||||||
self.message_count += 1;
|
self.message_count += 1;
|
||||||
self.handle_message(message).await?;
|
self.print_message(message).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
@@ -69,13 +64,45 @@ impl Connection {
|
|||||||
let Some(header) = self.read_header().await? else {
|
let Some(header) = self.read_header().await? else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
//Заголовок скачен и валиден. Получаем команду из заголовка
|
||||||
|
match header.command() {
|
||||||
|
Command::Upload => {
|
||||||
|
println!("Команда UPLOAD");
|
||||||
|
let upl_result=
|
||||||
|
upload::handle(&mut self.stream, header).await.map_err(|error| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
format!("Ошибка UPLOAD:{error:}")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::Download => {
|
||||||
|
println!("Команда DOWNLOAD");
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::Delete => {
|
||||||
|
println!("Команда DELETE");
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::Stat => {
|
||||||
|
println!("Команда STAT");
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::FileData => {
|
||||||
|
println!("Команда FILEDATA");
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::Response => {
|
||||||
|
println!("Команда RESPONSE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let body = self.read_body(header.body_size()).await?;
|
//let body = self.read_body(header.body_size()).await?;
|
||||||
|
|
||||||
Ok(Some(IncomingMessage {
|
Ok(None)
|
||||||
header,
|
|
||||||
body,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_header(&mut self) -> io::Result<Option<Header>> {
|
async fn read_header(&mut self) -> io::Result<Option<Header>> {
|
||||||
@@ -100,59 +127,10 @@ impl Connection {
|
|||||||
format!("Ошибка разбора заголовка: {error:?}"),
|
format!("Ошибка разбора заголовка: {error:?}"),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
//Заголовок скачен и валиден. Получаем команду из заголовка
|
|
||||||
match header.command() {
|
|
||||||
Command::Upload => {
|
|
||||||
println!("Команда UPLOAD");
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::Download => {
|
|
||||||
println!("Команда DOWNLOAD");
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::Delete => {
|
|
||||||
println!("Команда DELETE");
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::Stat => {
|
|
||||||
println!("Команда STAT");
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::FileData => {
|
|
||||||
println!("Команда FILEDATA");
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::Response => {
|
|
||||||
println!("Команда RESPONSE");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(header))
|
Ok(Some(header))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_body( //todo: анахронизм, убрать после реализации storage
|
async fn print_message(
|
||||||
&mut self,
|
|
||||||
body_size: u64,
|
|
||||||
) -> io::Result<Vec<u8>> {
|
|
||||||
if body_size > MAX_BODY_SIZE {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::InvalidData,
|
|
||||||
format!(
|
|
||||||
"Размер тела {body_size} превышает лимит \
|
|
||||||
{MAX_BODY_SIZE}"
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut body = vec![0_u8; body_size as usize];
|
|
||||||
|
|
||||||
self.stream.read_exact(&mut body).await?;
|
|
||||||
|
|
||||||
Ok(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_message(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
message: IncomingMessage,
|
message: IncomingMessage,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
@@ -162,26 +140,6 @@ impl Connection {
|
|||||||
self.message_count,
|
self.message_count,
|
||||||
message.header
|
message.header
|
||||||
);
|
);
|
||||||
|
|
||||||
// Это знание конкретной команды.
|
|
||||||
// Позже этот код можно вынести в отдельный handler.rs.
|
|
||||||
let body_text = String::from_utf8_lossy(&message.body);
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Соединение {}: тело: {:?}",
|
|
||||||
self.id,
|
|
||||||
body_text
|
|
||||||
);
|
|
||||||
|
|
||||||
let response = format!(
|
|
||||||
"Соединение {}: запрос {} принят, cmd={:?}\n",
|
|
||||||
self.id,
|
|
||||||
message.header.request_id(),
|
|
||||||
message.header.command(),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.stream.write_all(response.as_bytes()).await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+7
-7
@@ -29,21 +29,21 @@
|
|||||||
|
|
||||||
### 2. Создать постоянный модуль загрузки
|
### 2. Создать постоянный модуль загрузки
|
||||||
|
|
||||||
- [ ] Создать `upload.rs`.
|
- [✔] Создать `upload.rs`.
|
||||||
- [ ] Подключить его в `main.rs`:
|
- [✔] Подключить его в `main.rs`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
mod upload;
|
mod upload;
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] Создать в нём асинхронную функцию `handle()`.
|
- [✔ Создать в нём асинхронную функцию `handle()`.
|
||||||
- [ ] Передать в неё:
|
- [✔] Передать в неё:
|
||||||
|
|
||||||
- `&mut` сетевой поток;
|
- `&mut` сетевой поток;
|
||||||
- проверенный `Header`.
|
- проверенный `Header`.
|
||||||
|
|
||||||
- [ ] Пока только вывести заголовок и вернуть `Ok(())`.
|
- [✔] Пока только вывести заголовок и вернуть `Ok(())`.
|
||||||
- [ ] Убедиться, что после вызова управление возвращается в цикл `Connection`.
|
- [✔] Убедиться, что после вызова управление возвращается в цикл `Connection`.
|
||||||
|
|
||||||
Первая форма может иметь такой смысл:
|
Первая форма может иметь такой смысл:
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ pub async fn handle(
|
|||||||
|
|
||||||
### 3. Убрать чтение всего тела в `Vec`
|
### 3. Убрать чтение всего тела в `Vec`
|
||||||
|
|
||||||
- [ ] Не вызывать текущий `read_body()` для команды `UPLOAD`.
|
- [✔] Не вызывать текущий `read_body()` для команды `UPLOAD`.
|
||||||
- [ ] Не создавать:
|
- [ ] Не создавать:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
mod connection; //модуль отвечающий за соединения
|
mod connection; //модуль отвечающий за соединения
|
||||||
mod protocol; //модуль отвечающий за протокол ...
|
mod protocol; //модуль отвечающий за протокол ...
|
||||||
|
mod upload; //Модуль отвечающий за загрузку файла
|
||||||
|
|
||||||
use tokio::net::{TcpListener};
|
use tokio::net::{TcpListener};
|
||||||
use tokio::io;
|
use tokio::io;
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
use tokio::{io, net::TcpStream, stream};
|
||||||
|
|
||||||
|
use crate::protocol::Header;
|
||||||
|
|
||||||
|
pub async fn handle(
|
||||||
|
stream: &mut TcpStream,
|
||||||
|
header: Header,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
println!("Обработчик UPLOAD получил заголовок: {header:?}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user