# Post Office
this is a light weight tcp connection manager, including client and server side functions to communicate at high speed long living stable connctions with message que written in Rust.
## Installation
put carte name and version in your cargo.toml file under dependencies.
```bash
postoffice = "*"
```
# Api layers
- TCP connection - Module : client,server
- Json Request Result handler - Module : resp
- Json Scheme Validation on server Side for request handling - Module : check
# Tcp Connection
base tcp connection use custom utf string as request seprated by \r\n and transferred as bytes
## client Requests
### simple request
```bash
SMPL sdf67sf678sd6f sdf78sd6f78sdfsdfsdf+=\r\n
```
here first term is the request identifier then followed by the request id and the base64 encoded string
### encrypted request
```bash
SMPL sdf67sf678sd6f sdf87sd89fsd987f789sd7f8sd97f+:sdf78sd6f78sdfsdfsdf+=\r\n
```
here first term is the request identifier then followed by the request id and the base64 encoded nonce and cipher text seprated by ':'
## Server Responses
these responses are returned by the handler function as Response Struct and parsed as given below.
### Ok Response
```rust
//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());
}
}
```
```bash
OK sdf67sf678sd6f sdf87sd89fsd987f789sd7f8sd97f+:sdf78sd6f78sdfsdfsdf+=\r\n
```
here first term is the result identifier then followed by the request id and the base64 encoded nonce and cipher text seprated by ':' for encrypted messages and simple base64 encoded string on normal response;
### BAD Response
bad response are what they sound like they may carry errors and request identifier but if parsing fails then bad request dont identify the request by given id.
```bash
BAD parser-failed\r\n
```
this response occurs when parse fails to process the request data.
#### custom error by hanlder
```rust
return Ok(resp::error(req,"hanlder ran out of mem".to_string()));
```
```bash
BAD sdf67sf678sd6f "hanlder ran out of mem"\r\n
```
#### undefined error by hanlder
```rust
return Ok(resp::bad(req));
```
```bash
BAD sdf67sf678sd6f undefined\r\n
```
## Server Usage
```rust
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);
}
```
## Client Usage
```rust
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","gzbakku@gmail.com").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");
}
}
}
```
Please make sure to update tests as appropriate.
## License
MIT