You are here

Rust implementation of GNUnet with GSoC - Final-term

This is the final week of the gnunet-rs project with Google Summer of Code. It has been challenging but also exceptionally rewarding. I hope to explain the final product and then touch on the future work. The repository can be found here, and my previous blog post here.

During the first half of GSoC working period, I changed the peerinfo service to use asynchronous IO (using gjio). I continued on that path and added two more services to make use of asynchronous IO - identity and GNS. I won't cover the complete API in this blog post since their usage can be found in the documentation comments in the code (cargo doc can be used to generate html docs); there are also a lot of examples. But I will highlight one of them because it demonstrates the strengths of a promise based API.

async::EventLoop::top_level(|wait_scope| -> Result {
    // set up and configuration code omitted
    let mut gns = GNS::connect(&config, &network)
            .wait(wait_scope, &mut event_port).unwrap();
    let promises = vec!["gnu.org", "gnunet.org", "freebsd.org"]
            .into_iter().map(|d| {
        gns.lookup(::std::rc::Rc::new(d.to_string()),
                   public_key,
                   gns::RecordType::A,
                   gns::LocalOptions::LocalMaster,
                   None)
    });
    let addresses = async::Promise::all(promises)
            .wait(wait_scope, &mut event_port).unwrap();
    println!("{:?}", addresses);
    Ok(())
}).expect("top_level");

This piece of code creates a vector of promises to the GNS lookup results, and then the all function transforms it into a promise to a vector of the results. Finally we wait for all the promises to resolve.

The all function is useful for aggregating the result of multiple promises, methods such as then and map (not demonstrated here) give the user a composible way to chain promises together. Overall, using these functions and the promise API, we arrive at an elegant and safe way to write asynchronous code.

Moving the original blocking API into an asynchronous API is certainly a step forward. However, Rust is evolving rapidly (impl Trait return just landed in Nightly), especially regarding asynchronous IO libraries (recently futures-rs was announced which feature "zero-cost futures and streams"). So there is still a lot to be explored regarding the API design.

I'd like to thank Jeff for being my mentor. Completing this project would not have been possible without his guidance and the insightful discussions.