Asynchronous input/output of files

We now have to create a chain to read all incoming chunks and write them to the created file. As you might remember, File::create returns a Future that returns a File instance. We won't take the result immediately, because I/O operations take some time and can cause the current running thread to be blocked. We have to use the Future::and_then method to move the result (when it is ready) to other Future instance that will send all chunks to the file. To do that, we will use a Body instance that we get with the into_body method call of the Request that is stored in the req variable. The Body implements a Stream of the Chunk instances, but it can produce a hyper::Error. Since File::create can produce an io::Error, we have to convert the hyper::Error to an io::Error using the other function call as follows:

fn other<E>(err: E) -> Error
where
E: Into<Box<std::error::Error + Send + Sync>>,
{
Error::new(ErrorKind::Other, err)
}

The preceding function creates an io::Error with ErrorKind::Other based on any Error provided with the single argument. We use the other function with the map_err of the StreamExt to convert failures of the stream to io::Error. When the Stream of the Body is compatible with the type of error, we can create a Future that will move incoming binary data to the file. To do that, we can use a fold method of a StreamExt trait. If you are familiar with functional programming, you might know how this works already. The fold function takes two arguments—an initial value, which will be reused in every iteration, and a function, which carries out some processing with the initial value. Processing functions have to return a Future instance on every call, with one condition—the Future has to return the same type as the type of the initial value.

We will provide a File instance as an initial value and we will call tokio::io::write_all to write an incoming chunk of the request's body to a file. The write_all function expects an output stream and a binary slice. It returns a Future, which returns a tuple with an output stream and a provided slice on success. We have to use the map method of the returned Future to drop the slice and keep the file. The resultant chain will fold the whole Stream to a Future, which will return a filled File instance when all chunks are written to the file. We store this Future to write a variable and use the map method of FutureExt to drop the file instance (the real file with the written data will remain on the drive), and return a Response with the name of the stored file.

We have now successfully implemented file uploading. We should now discuss how to upload files using HTML forms and add a downloading feature to our service.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.218.226