Today I'm announcing GNUnet++. An experimentable yet sensable C++ wrapper for GNUnet services. You can find my introduction to GNUnet in my older articles [1][2]. TL;DR GNUnet is GNU's version of IPFS and libp2p. It has some pros and cons over `libp2p`. Like built-in trafic covering, firewall bypass, etc.. But has (much) lower adoption rate and stablity. In any case, it's a fun project and I see potential in it. The pure C API is a pain point I can help fix - with GNUnet++.
[1]: Thinking About Pratical Web3.0 and GNUNet as Infrastructure
[2]: GNUnet File Sharing Tutorial and an Alternative to IPFS
GNUnet++ aims to provide a RAII-style API for GNUnet. At least make managing GNUnet object lifetime not as painful. And high level function calls for commonly used functions. Currently basic capablitites of the following subsystems are wrapped:
And more is to come. I shall demonstrate what GNUnet++ can do with a simple example. Let's say we want to query the GNS system for the IP address of gnunet.org. We can do this with the following code.
auto gns = std::make_shared<gnunetpp::GNS>(cfg); gns->lookup("gnunet.org", [](auto result) { if(result.empty()) std::cout << "No result found" << std::endl; else { for(auto& record : result) std::cout << "Found record: " << record << std::endl; } });
Likewise, to publish file to GNUnet's file share system, we can do this:
gnunetpp::FS::publish(cfg, "/path/to/the/file.txt", {} , [](auto status, const std::string& uri, const std::string& namespace_uri) { if(status == gnunetpp::FS::PublishResult::Success) std::cout << "Published " << filename << " at " << uri << std::endl; else std::cout << "Publish failed" << std::endl; });
Contrast to what GNUnet's official thousand line utility to publich files. I think GNUnet++ is a lot more reasonable and easier to use. Sure, there's lots of functions missing. I'm adding them as I need. And more importantly, contributions are always welcome.
Source code of gnunet-publish, GNUnet's official utility to publish files.
GNUnet++ replements a subset of GNUnet's CLI tools as examples of how to use GNUnet++. These tools are better organized with subcommands and with better help messages. It shoes what's required parameters and the default of optional parameters. For example, the help message of `gnunetpp-dht put` is:
❯ ./examples/gnunetpp-dht put --help Put a key-value pair into the GNUnet DHT Usage: ./examples/gnunetpp-dht put [OPTIONS] Options: -h,--help Print this help message and exit -k,--key TEXT REQUIRED Key of the key value pair -v,--value TEXT REQUIRED Value of the key value pair -e,--expiration UINT [3600] Expiration time for the value in seconds -r,--replication UINT [5] Estimation of how many nearest peer this request reaches (not data replication count)
While the oginal `gnunet-dht-put` is more cryptic:
❯ gnunet-dht-put -h gnunet-dht-put Issue a PUT request to the GNUnet DHT insert DATA under KEY. Arguments mandatory for long options are also mandatory for short options. -c, --config=FILENAME use configuration file FILENAME -d, --data=DATA the data to insert under the key -e, --expiration=EXPIRATIONhow long to store this entry in the dht (in seconds) -h, --help print this help -k, --key=KEY the query key -L, --log=LOGLEVEL configure logging to use LOGLEVEL -l, --logfile=FILENAME configure logging to write logs to FILENAME -R, --record use DHT's record route option -r, --replication=LEVEL how many replicas to create -t, --type=TYPE the type to insert data as -V, --verbose be verbose -v, --version print the version number -x, --demultiplex use DHT's demultiplex everywhere option
Like I said above, GNUnet++ is a high level library. This means that it's not as flexible as the original GNUnet API. For example, GNUnet++ doesn't expose the routing information along with the DHT query result. However, I think this is a reasonable tradeoff as that information is rarely used. And it's not hard to add it back if you really need it. Also, GNunet++ is not as "efficient" as using the raw C API as it has to do some extra work to manage object lifetime. Again, I think this is a reasonable tradeoff for very obvious reasons.
I decide to announce GNUnet++ at it's current form for a few reasons. 1. The callback hell is getting out of hands and I'll be turning them into coroutines. But that will take some serious problem solving for lifetime management. 2. It's good enough to be slightly useful and I want to get some feedback if anyone happens to find it.
The main thing missing now is CADET and namestore support. Looking at their APIs. I rather implement them after coroutines are done. I'm also debating myself if I should support the chat and auction subsystems. They are such high level that I'm not sure if anyone would use them programmatically.
I haven't come up with a good pratical use case for GNUnet++ yet (at least something I'd spend time to build). Decentralized p2p is very attractive. But is also hard. In the sense that the traditional client-server archicture is easy to build, low latency and low noise. Decentralizing means you gave up all that and have to deal with a lot of new problems. Like easy DoS attacks, unreliable network, and so on.
I'm working hard on it though. I truely believe in the power of p2p networks.
===
Find the source code at the following link.