-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: support redis-server network layer
- Loading branch information
1 parent
c09d28b
commit fd8be0b
Showing
10 changed files
with
700 additions
and
16 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
mod backend; | ||
pub mod cmd; | ||
pub mod network; | ||
mod resp; | ||
|
||
pub use backend::*; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,30 @@ | ||
fn main() { | ||
println!("Hello, world!"); | ||
use anyhow::Result; | ||
use tokio::net::TcpListener; | ||
use tracing::{error, info}; | ||
|
||
use simple_redis::{network, Backend}; | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<()> { | ||
// Initialize tracing library | ||
tracing_subscriber::fmt::init(); | ||
|
||
let addr = "0.0.0.0:6379"; | ||
info!("Simple-Redis-Server is listening on {}", addr); | ||
|
||
let listener = TcpListener::bind(addr).await?; | ||
let backend = Backend::new(); | ||
loop { | ||
let (stream, raddr) = listener.accept().await?; | ||
info!("Accepted connection from: {}", raddr); | ||
let cloned_backend = backend.clone(); // 克隆一个 backend 供子任务使用 | ||
tokio::spawn(async move { | ||
match network::handle_connection(stream, cloned_backend).await { | ||
Ok(_) => info!("Connection from {} exited", raddr), | ||
Err(e) => error!("Error handling connection for {}: {:?}", raddr, e), | ||
} | ||
}); | ||
} | ||
#[allow(unreachable_code)] | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
use anyhow::Result; | ||
use bytes::BytesMut; | ||
use futures::SinkExt; | ||
use tokio::net::TcpStream; | ||
use tokio_stream::StreamExt; | ||
use tokio_util::codec::{Decoder, Encoder, Framed}; | ||
use tracing::info; | ||
|
||
use crate::cmd::{Command, CommandExecutor}; | ||
use crate::{Backend, RespDecode, RespEncode, RespError, RespFrame}; | ||
|
||
#[derive(Debug)] | ||
struct RespFrameCodec; | ||
|
||
#[derive(Debug)] | ||
struct RedisRequest { | ||
frame: RespFrame, | ||
backend: Backend, | ||
} | ||
#[derive(Debug)] | ||
struct RedisResponse { | ||
frame: RespFrame, | ||
} | ||
|
||
pub async fn handle_connection(stream: TcpStream, backend: Backend) -> Result<()> { | ||
// how to get a frame from the stream | ||
// call request_handler to handle the request | ||
// send the response back to the stream | ||
let mut framed = Framed::new(stream, RespFrameCodec); | ||
|
||
loop { | ||
let cloned_backend = backend.clone(); // Clone 一个 backend 供子任务使用 | ||
match framed.next().await { | ||
Some(Ok(frame)) => { | ||
info!("Received frame: {:?}", frame); | ||
let request = RedisRequest { | ||
frame, | ||
backend: cloned_backend, | ||
}; | ||
let response = request_handler(request).await?; | ||
info!("Sending response: {:?}", response); | ||
// 向 stream 发送响应 | ||
framed.send(response.frame).await? | ||
} | ||
Some(Err(err)) => return Err(err), | ||
None => return Ok(()), | ||
} | ||
} | ||
} | ||
|
||
// 处理一个请求并返回响应 | ||
async fn request_handler(request: RedisRequest) -> Result<RedisResponse> { | ||
let (frame, backend) = (request.frame, request.backend); | ||
let cmd = Command::try_from(frame)?; | ||
info!("Executing command: {:?}", cmd); | ||
let frame = cmd.execute(&backend); | ||
Ok(RedisResponse { frame }) | ||
} | ||
|
||
impl Encoder<RespFrame> for RespFrameCodec { | ||
type Error = anyhow::Error; | ||
|
||
fn encode( | ||
&mut self, | ||
item: RespFrame, | ||
dst: &mut BytesMut, | ||
) -> std::result::Result<(), Self::Error> { | ||
let encoded = item.encode(); | ||
dst.extend_from_slice(&encoded); // 转化成 bytes 并贝到 dst | ||
Ok(()) | ||
} | ||
} | ||
impl Decoder for RespFrameCodec { | ||
type Item = RespFrame; | ||
type Error = anyhow::Error; | ||
|
||
fn decode( | ||
&mut self, | ||
src: &mut BytesMut, | ||
) -> std::result::Result<Option<Self::Item>, Self::Error> { | ||
match RespFrame::decode(src) { | ||
Ok(frame) => Ok(Some(frame)), | ||
Err(RespError::NotComplete) => Ok(None), | ||
Err(err) => Err(err.into()), | ||
} | ||
} | ||
} |
Oops, something went wrong.