#tcp-connection #client-server #tcp-client #connection-manager #tcp #message #server

bin+lib postoffice

这是一个轻量级的 TCP 连接管理器,包括客户端和服务器端功能,用于通过消息队列以高速、长连接稳定地通信。

16 个版本

0.0.26 2020年8月24日
0.0.25 2020年8月22日
0.0.19 2020年2月18日

#672 in HTTP 服务器

Download history 7/week @ 2024-04-01

每月 51 次下载

自定义许可

135KB
3.5K SLoC

邮政局

这是一个轻量级的 TCP 连接管理器,包括客户端和服务器端功能,用于通过消息队列以高速、长连接稳定地通信,使用 Rust 编写。

安装

将 crate 名称和版本放入您的 cargo.toml 文件中的依赖项部分。

postoffice = "*"

API 层

  • TCP 连接 - 模块:client,server
  • Json 请求结果处理器 - 模块:resp
  • 服务器端请求的 Json 方案验证 - 模块:check

Tcp 连接

基础 TCP 连接使用自定义的 UTF 字符串作为请求分隔符,以字节的形式传输。

客户端请求

简单请求

SMPL sdf67sf678sd6f sdf78sd6f78sdfsdfsdf+=\r\n

这里第一个术语是请求标识符,然后是请求 ID 和 base64 编码的字符串。

加密请求

SMPL sdf67sf678sd6f sdf87sd89fsd987f789sd7f8sd97f+:sdf78sd6f78sdfsdfsdf+=\r\n

这里第一个术语是请求标识符,然后是请求 ID、base64 编码的 nonce 和密文,由 ':' 分隔。

服务器响应

这些响应由处理函数作为 Response 结构返回,并按以下方式解析。

成功响应

//encrypted
match Response::new(req,"secure message".to_string(),true) {
    Ok(res)=>{
        return Ok(res);
    },
    Err()=>{
        return Resp::error(req,"parser failed".to_string());
    }
}

//simple
match Response::new(req,"unsecure message".to_string(),false) {
    Ok(res)=>{
        return Ok(res);
    },
    Err()=>{
        return Resp::error(req,"parser failed".to_string());
    }
}
OK sdf67sf678sd6f sdf87sd89fsd987f789sd7f8sd97f+:sdf78sd6f78sdfsdfsdf+=\r\n

这里第一个术语是结果标识符,然后是请求 ID 和由 ':' 分隔的 base64 编码的 nonce 和密文(用于加密消息)以及普通的 base64 编码字符串(用于正常响应)。

错误响应

错误响应正如其名,它们可能携带错误和请求标识符,但如果解析失败,则错误响应不会通过给定的 ID 识别请求。

BAD parser-failed\r\n

此响应发生在解析请求数据失败时。

处理函数的自定义错误

return Ok(resp::error(req,"hanlder ran out of mem".to_string()));
BAD sdf67sf678sd6f "hanlder ran out of mem"\r\n

处理函数的未定义错误

return Ok(resp::bad(req));
BAD sdf67sf678sd6f undefined\r\n

服务器使用


use postoffice::{server,resp,common};
use postoffice::check::{Field,Format};
use json::JsonValue;

fn handler(req: Request) -> Result<Response,String> {

  let mut new_format = Format::new();
    new_format.field_builder(vec![
        Field::new("string",false,"type",vec!["write","read","collection_check","collection_insert"],Field::no_format(),0,0,false),
        Field::new("object",false,"data",Field::no_options(),Field::no_format(),0,0,false)
    ]);

    let body:JsonValue;
    match check::check_request(req.clone(),new_format) {
        Ok(parsed)=>{
            body = parsed;
        },
        Err(e)=>{
            let error = format!("check request failed error : {:?}",e);
            return Ok(resp::error(req,error));
        }
    }

    let child_format = Format::builder(vec![
        Field::new("string",false,"id",Field::no_options(),Field::no_format(),0,0,false),
        Field::new("string",false,"path",Field::no_options(),Field::no_format(),0,0,false),
        Field::new("array",false,"users",Field::no_options(),Field::no_format(),0,100,true)
    ]);

    match check::check_children(&body["data"], "object".to_string(), Field::no_options(), child_format, false, true) {
        Ok(_)=>{},
        Err(e)=>{
            let error = format!("check children failed error : {:?}",e);
            return Ok(resp::error(req,error));
        }
    }

    let mut user_format = Format::new();
    user_format.field_builder(vec![
        Field::new("string",false,"name",Field::no_options(),Field::no_format(),0,0,false),
        Field::new("string",false,"email",Field::no_options(),Field::no_format(),0,0,false),
        Field::new("string",false,"company",Field::no_options(),Field::no_format(),2,50,true)
    ]);

    for entry in body["data"].entries() {

        let data = entry.1;
        let users = &data["users"];

        match check::check_array(&users, "object".to_string(), Field::no_options(), &user_format) {
            Ok(_)=>{},
            Err(e)=>{
                let error = format!("check array failed error : {:?}",e);
                return Ok(resp::error(req,error));
            }
        }

    }

    return Ok(resp::ok(req));

}

fn auth(token:server::auth::Token) -> bool {
    println!("token : {:?}",token);
    return true;
}

fn main(){
    let key = "8cfb30b34977529853bbe46afdbbd5ae".to_string();
    let address = String::from("127.0.0.1:5200");
    server::init(address,key,handler,auth);
}

客户端使用


use postoffice::client::{get_random_connection_id,start_connection,send_message};
use postoffice::resp;

fn main(){

  let key = "8cfb30b34977529853bbe46afdbbd5ae".to_string();
  let connection_id = client::get_random_connection_id();
  let addr = "127.0.0.1:5200".to_string();

  match start_connection(&connection_id,addr,key) {
     Ok(_)=>{
         //println!("connection establishged");
     },
     Err(_)=>{
         common::error("failed start connection");
     }
  }

  let mut user = JsonValue::new_object();
  user.insert("name","akku").unwrap();
  user.insert("email","[email protected]").unwrap();
  user.insert("company","daachi.in").unwrap();

  let mut users = JsonValue::new_array();
  users.push(user);

  let mut request = JsonValue::new_object();
  request.insert("collection","1a62c37cf70a74cfeb69aba742643613").unwrap();
  request.insert("path","/users/");
  request.insert("users",users);

  send(connection_id,request);

}

fn send(connection_id:String,data:json::JsonValue){

    let mut request_object = json::JsonValue::new_object();

    match request_object.insert("type","write") {
        Ok(_)=>{},
        Err(_)=>{}
    }

    match request_object.insert("data",data) {
        Ok(_)=>{},
        Err(_)=>{}
    }

    let request_string = request_object.dump();

    match client::send_message(&connection_id,request_string,false) {
        Ok(response)=>{
            match resp::parse_response(response) {
                Ok(result)=>{
                    println!("result : {:?}",result);
                },
                Err(e)=>{
                    println!("error parse response strucft : {:?}",e);
                }
            }
        },
        Err(_)=>{
            println!("request failed");
        }
    }

}

请确保适当更新测试。

许可

MIT

依赖

~5MB
~79K SLoC