Announcing GNUnet++, experimental high level GNUnet C++ wrapper
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++.
GNUnet++
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:
- DHT
- File Share
- Identity
- Crypto
- GNS
- Scheduler
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.
New CLI Tools
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
Limitations
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.
Near future work
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.
Pratical Use
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.
Martin Chang
Systems software, HPC, GPGPU and AI. I mostly write stupid C++ code. Sometimes does AI research. Chronic VRChat addict
I run TLGS, a major search engine on Gemini. Used by Buran by default.
- marty1885 \at protonmail.com
- Matrix: @clehaxze:matrix.clehaxze.tw
- Jami: a72b62ac04a958ca57739247aa1ed4fe0d11d2df