How to store data inside server received from method POST?


#24

Futures in Rust don’t run on their own - they need an executor to run them. When you create a future inside call(), it doesn’t do anything yet - it’s merely a recipe of what to do once it does run. It only starts running after you’ve returned it to hyper; hyper gives it to tokio, which serves as the executor. This part has nothing to do with you removing future impl from Store.

But here’s the deal - as it stands, you don’t need to make add() perform the addition inside a future - it doesn’t do anything asynchronously. Instead, make add() perform the update via normal code (ie no futures there).

The data should be there - you’re not seeing it because of how you’re inspecting this, as mentioned above.


#25

Ok, delete using futures. Could you explain how to process POST which add item to vector (field of server) and then do something with added item inside another POST? For me it’s difficult to understand without simple example.


#26

Have you tried issuing a second POST request after the first one added the item? I think it’s there but you’re just not seeing it because of how you’re inspecting things in the first POST.


#27

No, it’s not here. I have a client which send batch of data to store it inside server and then try to find (in other POST) necessary data which should be store inside of server. In second case of searching my client received StatusCode::NotFound, because store is still empty.


#28

Can you paste all of the relevant code (including struct definitions)?


#29

Server:

extern crate hyper;
extern crate futures;
extern crate tokio_core;
extern crate serde;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use futures::future::Future;
use futures::{Async, Stream};
use hyper::header::ContentLength;
use hyper::server::{Http, Request, Response, Service};
use hyper::{Method, StatusCode, Body, Chunk};
use std::io;
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Block {
	id1: String,
	id2: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Need {
	pub id: usize,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Batch {
	data: Vec<Block>, 
}

impl Batch {
	fn get(&mut self) -> &mut Vec<Block> {
		 &mut self.data
	}
}

#[derive(Debug)]
struct Store {
	data: Vec<Block>, 
}


impl Store {
	fn new() -> Store {
		Store{data: Vec::new()}
	}

	fn add(&mut self, batch: &mut Batch) {
		self.data.append(batch.get());
	}

	fn get(&mut self, ind: usize) -> Option<&Block> {
		self.data.get(ind)
	}
}

struct Server {
	store: Rc<RefCell<Store>>,
}

impl Service for Server {
	
    type Request  = Request;
    type Response = Response;
    type Error    = hyper::Error;
    type Future   = Box<Future<Item=Self::Response, Error=Self::Error>>;

    fn call(&self, req: Request) -> Self::Future {

         match (req.method(), req.path()) {            

            (&Method::Post, "/add") => {
            	let send = insert(self.store.clone(), req);
            	send
            } 

            (&Method::Post, "/search") => {
            	let send = search(self.store.clone(), req);
            	send                       
            }                      

            _ => {
                Box::new(futures::future::ok(
                    Response::new().with_status(StatusCode::BadRequest)
                ))
            }
            
        }
    }
}

fn insert(store: Rc<RefCell<Store>>, req: Request) -> Box<Future<Item=Response, Error=hyper::Error>> {

	let send = req.body().concat2().map(move |b| {

		println!("Start to process...");

	    if let Ok(mut batch) = serde_json::from_slice::<Batch>(b.as_ref()) {

	    	println!("Batch is received by server.");
		    		
		    (*store.borrow_mut()).add(&mut batch);
		    				    
		    Response::new().with_status(StatusCode::Ok)						    						    					   					    				  
	    } else {
	    	println!("No received data.");
	    	Response::new().with_status(StatusCode::NoContent)
	    }					 
    });
                
	Box::new(send)           
}

fn search(store: Rc<RefCell<Store>>, req: Request) -> Box<Future<Item=Response, Error=hyper::Error>> {

	let send = req.body().concat2().map(move |b| {

	    if let Ok(need) = serde_json::from_slice::<Need>(b.as_ref()) {
		    		
		    println!("Request to search is received by server.");
		
		    let mut store = store.borrow_mut();

		    println!("Store in search {:?}", *store);

		    if let Some(solution) = (*store).get(need.id) {

    			println!("Path of tockets is done.");

    			Response::new().with_status(StatusCode::Ok)
                               .with_body(serde_json::to_vec(&solution).unwrap())
    		} else {
    			println!("No found.");
    			Response::new().with_status(StatusCode::NotFound)
    		}				
		    				    
	    } else {
	    	println!("Request to search is NOT received by server.");
	    	Response::new().with_status(StatusCode::NoContent)
	    }					 
    });

    Box::new(send)
}

pub fn run_server() {

	let addr = "127.0.0.1:8080".parse().unwrap();

    let server = Http::new().bind(&addr, move || Ok(
		Server{store: Rc::new(RefCell::new(Store::new()))}
    )).unwrap();

    server.run().unwrap();
}

fn main() {
	run_server();
}

#30

Client:

extern crate futures;
extern crate hyper;
extern crate tokio_core;

extern crate serde;
#[macro_use]
extern crate serde_json;

use std::io::{self, Write};
use futures::{Future, Stream};
use tokio_core::reactor::Core;
use hyper::{Method, Request, Client, Body};
use hyper::header::{ContentLength, ContentType};
use std::convert::From;
use serde_json::Value;

fn run_client() {

	let batch = json!({
						"data": [
						    {
						      "id1": "11",
						      "id2": "12",
						    },
						    {
						      "id1": "21",
						      "id2": "22",
						    }],			
					}
	);

	let need = json!({
						"id": 1,						
					}
	);

	let mut core = Core::new().unwrap();
	let client = Client::new(&core.handle());

	// let uri = "http://127.0.0.1:8080/add".parse().unwrap();
	let uri = "http://127.0.0.1:8080/search".parse().unwrap();

	let mut req = Request::new(Method::Post, uri);

	req.headers_mut().set(ContentType::json());
	// req.set_body(serde_json::to_vec(&batch).unwrap());
	req.set_body(serde_json::to_vec(&need).unwrap());

	let post = client.request(req).and_then(|res| {
	    println!("POST: {}", res.status());

	    res.body().concat2()
	});

	core.run(post).unwrap();
}

fn main() {
    run_client();
}

#31

You made a crucial mistake here:

let addr = "127.0.0.1:8080".parse().unwrap();

    let server = Http::new().bind(&addr, move || Ok(
		Server{store: Rc::new(RefCell::new(Store::new()))}
    )).unwrap();

Note the code I showed you earlier has the Rc<RefCell<Store> outside the closure:

As it stands, each client connection gets its own Rc<RefCell<Store>>, and that explains what you’re seeing.


#32

You are the best teacher :slight_smile: Thank you! I will correct my code.


#33

May I ask what is the difference of using Service trait and NewService Trait? Thank you.