A review of potentially useful libraries and utilities.
The material here is usually way out of date and frequently wrong. It should be treated as a bunch of hints likely to point the reader in the correct direction, so that the reader can do his homework on the appropriate library. It should not be taken as gospel.
Most important work in blockchains these days appears to be on rust.
I am behind the times.
Rust is most ways the best system for large projects that can be worked on by many people and installed easily by many people, but it has the huge defect of a almost endless learning curve, and that its compile on very large programs takes a very long time. With C++, if you change one file, it recompiles very quickly. Since Rust link basically does not work, it has to recompile everything, which makes coding on large programs very slow. This is a killer if you are generating an executable that does a lot of things. And anything with a gui does do a lot of things.
So if you try to create a gui program in Rust you wind up using a rust wrapper around a gui written in some other language, which results in a gui that sucks. Rust however, is best for a daemon running in the background that does networking.
All my writings on scaling have been rendered obsolte by rapid progress
The library that appears to have the solution as of 2025-05-25 is Rust: arkworks-rs (used in Nova/Spartan), to implement folding over a tree of posiedon hashes.
This allows one to prove things about all the leaves of the root in a single proof, albeit the big problem being that what one can prove is a lot more restrictive than what one can prove with recursive snarks.
I think that to do it with only folding, have prove the equivalent thing about every leaf of the tree. You wind up needing some snarks and recursive snarks are not going to work with ordinary elliptic curves – so have to use BabyJubJub, the curve developed by Zcash.
So the question is, how to have a system of transactions such that conservation of money can be proven by arkwors-rs over a tree of unlimited size.
Fri successfully implemented recursive snarks, but the very large size of snarks inevitably leads to the administration of the blockchain being done in a few big data centers, not by individuals, so you inevitably get a centralised solution .
GossipSub is specifically designed for efficient broadcast / multicast of messages to all (or most) interested peers in a topic. Peers subscribe to a topic (e.g., “mempool-txs” or “blockchain-transactions”). When a peer publishes a new item (e.g., a new transaction), it gets gossiped efficiently across the network with bounded fan-out, mesh maintenance, and scoring to penalize bad peers.
Trouble with this is no history – you miss out on everything that happened earlier.
However gossipsub is specifically designed to allow further extensions.
Cgo calls are slow and cumbersome. However, one can implement a buffered channel between C and go. Can one implement many channels, with a channel to C that can pass a request to C and get a channel back? Maybe. I don’t know enough about go. If its reasonably doable, a library should provide it. If no library provides it, probably hard.
Assume we are following the bitmessage protocol where the cost of publishing is irrecoverable work, and sufficienty old material is kept only by those interested, if you were off for x days, you miss out.
So, each new bitmessage is broadcast and has a commitment to an ordered history. Largest and Longest sequence of ordered histories wins.
So everyone publishes their current height, the latest message, their latest total order that is committed to, and the rank weight of that total order.
If the other guys total order outweighs yours, then you sync. You go back to where the order starts to differ,and sync.
This section out of date and irrelevant, for we now have better libraries derived from IPFS and written in Go
The primary peer-to-peer networking library is go-libp2p, rendering freenet irrelevant and obsolete, and for blockchains, gossipsub
Freenet has long intended to be, and perhaps is, the social application that you have long intended to write, and has an enormous coldstart advantage over anything you could write, no matter how great.
It also relies on udp, to enable hole punching, and routinely does hole punching.
So the only way to go, to compete, is to write a better freenet within freenet.
One big difference is that I think that we want to go after the visible net, where network addresses are associated with public keys - that the backbone should be ips that have a well known and stable relationship to public keys.
Which backbone transports encrypted information authored by people whose public key is well known, but the network address associated with that public key cannot easily be found.
Freenet, by design, chronically loses data. We need reliable backup, paid for in services or crypto currency. filecoin provides this, but is useless for frequent small incremental backups.
This is a general purpose library, not all that married to bittorrent
It is available of as an MSYS2 library , MSYS2 being a fork of the semi abandoned mingw libary, with the result that the name of the very dead project Mingw-w64 is all over it.
Its pacman name is mingw-w64-dht, but it has repos all over the place under its own name
It is async, driven by being called on a timer, and called when data arrives. It contains a simple example program, that enables you to publish any data you like.
http3 libraries built on udp. Designed for async use – build your own event loop. They supply two priority queues for the event loop.
The generically named p2p does exactly what you want to do. It is a thin wrapper around libp2p to allow participants in the Kademlia cloud to find each other and send each other private messages. Unfortunately Kademlia is broken and extremely vulnerable to hostile action, and libp2p has only encryption operations around a broken name system which they are making even more user hostile than it already is because they don’t want anyone using it (because broken), uses encryption libraries for which there is strong reason to suspect enemy activity, and does not support Schnorr keys, nor Ristretto, which is an obstacle to scriptless scripts and joint signatures.
The reason they do not support Schnorr is that they are using nonprime groups, and doing a Schnorr signature safely in a non prime group is incomprehensibly hard and very easy to get subtly wrong. The great strength of Ristretto is that it is prime, which makes a whole lot of clever cryptography available to do clever things, Schnorr signatures, scriptless scripts, lightning locks, and compact joint signatures among them.
libp2p have a small set of name systems and public key systems, and it should not be too hard to add yet another to that set. It appears to be extensible, because it has to support no end of old obsolete stuff. Obviously new stuff has been added from time to time, so it should be possible to find the additions in git and follow their example.
libp2p supports multiple transport schemes, and can support a set of peers using heterogeneous transport. So you just have to add another transport scheme, and not everyone has to update simultaneously. They use TCP and web, but there is a plugin point for new transport schemes, so just plug in UDP under an encryption and reliability layer.
libp2p should make it possible to access the IPFS both to write and read stuff, though that might be far from trivial.
You could perhaps publish stuff on IPFS that looks like a normal html document, but contains embedded cryptographic data giving it more forms of interaction when viewed on your browser, than viewed on brave.
Replacing Kademlia for finding peers in the face of enemy entryist action is a big project, though libp2p seems to have taken the essential step of identifying peers by their public key, rather than IP and port address.
Their distributed hash table (kad-dht) seems to be very much a work in progress. Checking their implementations page for the status of various libp2p components, everything seems to be very much a work in progress. Some things are implemented in some languages which are not implemented in other languages. Rust has hole punching, C++ does not. But C++ has a whole lot of stuff that Rust does not. And their documentation on kad-dht has its page blank. On the other hand, ipfs works, and Polkadot works. So, something is usable. libp2p-peer not implemented in C++, but is implemented in rust, and is implemented in browser javascript.
Their rendezvous protocol presupposes a single central and known server which simply records everyone’s ID and network address. Unacceptable. Anyone using this is fake and an enemy. Should be disabled in our fork.
libp2p is a pile of odds and ends and a framework for gluing them together.
But everything they do is crippled by the fact that you don’t know the likely uptime, downtime, or IP stability of an entity. Which cannot in fact be known, but you can form probability of a probability estimates.
What is needed is that everyone forms their own probability of a probability. And they compare what they know (they have a high probability of a probability) with other party’s estimates, and rate the other party’s reliability accordingly If we add to that probability of probability estimate of IP and port stability and use it to govern ping time and keep around time, that goes a large way to solving the problems with Kademlia
We can adapt it to the problem by having them preferentially keep around the data for peers that have stable ip and a stable port, and, somewhat less preferentially, keep around peers that have a stable nat penetration or tracking relationship with a peer that has a stable ip and stable port. Selective pinging. You rarely ping peers that have been around for a very long time with stable IP, and you ping a peer that has a nat penetration relationship by not pinging it, and instead asking the gateway peer how the relationship is going, at infrequent intervals. Thus, a peer with stable IP or stable relationship becomes very widely known.
Well, becomes widely known assuming shills do not register one billion addresses that happen to be near him.
libp2p is something between actual code, and set of standards - which standards you comply with so that you can use other people’s code. Someone writes something ad hoc for his use case, stuffs it into libp2p somewhere somehow so that he can use other people’s code. Then other people use his code.
It is a pile of standards (many of them irritatingly stupid, incomplete, ad hoc, or workarounds for using defective tools) that enable a whole lot of people writing this sort of thing to copy a whole lot of each other’s code.
Their NAT discovery algorithm Is particularly idiotic and broken. It is not a nat discovery algorithm, but a closed port discovery algorithm, and a ludicrously laborious, costly, indirect, error prone, and inefficient closed port discover algorithm.
NAT means the other guy sees your network address different from what you see. In which case your port is probably closed, but could well be open. If he sees the same network address as you, your port might be open, but you don’t know that, and talking to the other guy might well temporarily open your port, with the result that he might tell you that you are not behind a NAT, when in fact you are, and your ports are normally closed. The guys writing this stuff are dumb as posts, and a whole lot of what they write is garbage. But, nonetheless, a whole lot of people are using libp2p, and a whole lot of people are doing a whole lot of work on it – not all of which is ready for prime time.
Wireguard is a secure vpn.
Tailwind is peer to peer built on Oauth2 and Wireguard. Lacks peering through NAT facilities, though this is probably not hard to fix or add. The Tailwind server just tells both peers to start pinging each other simultaneously, and tells each peer when the other peer has acked a meeting time. With most nats, the first ping to arrive after a ping has been sent will get through. Wireguard has a provision to keep on pinging.
If a peer has a stable IP and port accessible from the internet, it does not ping. The other guy has to ping. If he does not ping for a while, the connection may stop working. If the peer with the stable IP and port finds it cannot get through, discards the connection information, but if it never attempts to use that information, it may hang around for a very long time.
Oauth is a generic interface to identity protocols. Anyone can implement Oauth in any way.
The Zooko identity model is that each party has his own mapping between non unique Zooko human readable, typeable, and memorable names, and globally unique non human memorable, non human typeable, public keys.
We put on top of that a consensus mapping, which is mutable. The end user sees his local name for an identity, that identity’s name for itself, and a recent consensus human readable human typeable name for that identity.
For major and important widely known identities these should all be the same, and the end user should see a single short human readable name. If the end user sees two or three different human readable names for a counterparty, there is likely to be an issue. If he sees three different human readable names, plus the public key, definitely an issue.
The end user’s mapping from local petnames to global keys is locally unique, and mutable at the end user’s discretion.
The consensus mapping is mutable by consensus.
For friends who are well known to himself, but not well known to others, the global consensus name may merely be a distraction, and he may turn it off. If someone is on his buddy list, people whitelisted the global consensus name is turned off, unless it is the same, in which case it is turned on, and if the consensus changes, the end user sees that change.
Maverick says:
If looking for something to try out that begins to have the right shape, see Manyverse that uses the Scuttlebutt protocol. Jim is fond of Bitmessage and it is quite secure, but it has a big weakness in that it needs to flood every message to all nodes in the world so everyone can try their private key to see if it works for decryption. That won’t scale. (Can’t avoid passing every message on to all callers even if you know it’s yours, as you don’t want to let someone snooping see that you absorbed a message which is an information disclosure.)
Instead Manyverse and Scuttlebutt allow for publishing and reputation for a public key. The world can see what a key (its author really) publishes. Can publish public posts like a blog, signed by the private key for authenticity and verifiability. Also can publish private messages (DMs), visible to the world but whose contents are encrypted. Weakness in private messages is that the recipient public key is visible on the message - good for routing and avoiding testing every message, bad for privacy. Would be better to have a 3rd mode, private for “someone” but you have to test your private key to see if it’s for you. That should not be hard to add to Scuttlebutt and Manyverse.
Reputation is similar to what Jim has proposed: You can specify a list of primary keys/people (friends) you want to listen to and watch. You can also in the interface specify how many degrees of separation you want to see outward from your friends - the public messages from their friends and friends’ friends. Presumably specifying 6 degrees gets you Kevin Bacon and the rest of the Manyverse. You can also block friends’ friends so their connections are not visible to you - so if you don’t like a friend’s friend you at least don’t have to listen any more.
Another advantage is that Manyverse works in a sometimes-connected universe: Turn off your computer or phone for days, turn back on, catch up to messages. You realy don’t even have to be on the public Internet, you could sneakernet or local/private-net messages which is nice for, say, messaging in a disaster or SHTF scenario where you have a local wifi network while the main network connections are down. Bitmessage has a decay/lifetime for messages that means you need to be connected at least every 2-3 days.
Biggest weakness is hosting. Your service can be hosted by 3rd parties like any service, and you can host your own. Given the legal landscape as well as susceptibility to censorship via DDoS and hack attacks, you want to have your own server. There are some public servers but sensibly they don’t want a rando or glowie from the net jumping on there to drop dank memes. But hosting is nontrivial to carve out your own network bubble that can see the Internet (at least periodically) while being fully patched and DDoS resistant.
Of course missing from this from Jim’s long list of plans are DDoS protection, a name service that provides name mapping to key hierarchies for messaging and direct communications, and a coin tie-in. But Manyverse at least has the right shape for passing someone a message with a payment inside, while using a distributed network and sometimes connection with store-and-forward to let you avoid censorship-as-network-damage. A sovereign corporation can also message publicly or privately using its own sovereign name and key hierarchy and private ledger-coin.
The net is vast and deep. Maybe we need to start cobbling these pieces together. The era of centralized censorship needs to end. Musk will likely lose either way, and he’s only one man against the might of so many paper tigers that happen to be winning the information war.
rust-lightning is a general purpose library for writing lightning nodes, running under Tokio, that is used in one actual lightning node implementation.
It is intended to be integrated into on-chain wallets.
It provides the channel state as “a binary blob that you can store any way you want” – which is to say, ready to be backed up onto the social net.
I have no end of smart ideas about how a blockchain should work, but no actual blockchain. Smart ideas are worth two cents a bale, but only if already baled. Need to port in someone else’s blockchain code, with a bridge to their blockchain.
Then I can make a start on implementing my bright ideas as part of working code.
Near is actually implementing no end of things that I have been thinking about, so seems like a good fit.
Truly distributed git, git submodules, and git subtrees # Passphrases
Grammatically correct passphrases # Polkadot, Near, substack and gitcoin
It has become painfully apparent that building a blockchain is a very large project.
Polkadot is a blockchain ecosystem, and substack a family of libraries for constructing blockchains. It is a lot a easier to refactor an existing blockchain than to start entirely from scratch. Near is way ahead of me, because not suffering from not invented here syndrome.
Polkadot is designed to make its ecosystem subordinate to the primary blockchain, which I do not want - but it also connects its ecosystem to bitcoin by De-Fi (or promises to do so, I don’t know how well it works) so accepting that subordination is a liquidity event. We can fix things so that the tail will wag the dog once the tail gets big enough, as China licensed from ARM, then formed a joint venture with ARM, then hijacked the joint venture, once it felt it no longer needed to keep buying the latest ARM intellectual property. Licensing was a fully subordinate relationship, the joint venture was cooperation between unequal parties, and now ARM China is a fully independent and competing technology, based on the old ARM technology, but advancing it separately, independently, and in its own direction. China forked the ARM architecture.
Accepting a fully subordinate relationship to get connected, and then defecting on subordination when strong enough, is a sound strategy.
And talking about connections: Gitcoin
Gitcoin promises connection to money, and connection to a community of open source developers. It is Polkadot’s money funnel from VCs to developers. The amount of cash in play is rather meagre, but it provides a link to the real money, which is ICOs.
I suspect that its git hosting has been co-opted by the enemy, but that is OK, provided our primary repo is not co-opted by the enemy.
The standard gnu, cmake, deb, msi, NSIS, Wix, and Choco installers # Library Package managers
Cmake is the new source code package manager, obsoleting all others.
Secure compilation # Networking
notbit, Game Networking Sockets, Tokio, and wxWidgets networking # wxSqlite3
wxSqlite integrates a third free open source encryption library that appears to use libSodium encryption algorithms into Sqlite to provide encrypted databases, and integrates sqlite3 databases into one of the wxWidgets tools, but not, however, the one that I actually want, wGrid.
More layers lead to more attack surface, so it would be better to use wxSqlite as a model for the integration, rather than using it directly, and then use a fork of the third party library, rather than using it directly.
Safe maths, and handling protocol updates ## library commentary
My experience with Boost is that it is no damned good: They have an over elaborate pile of stuff on top of the underlying abstractions, which pile has high runtime cost, and specializes the underlying stuff in ways that only work with boost example programs and are not easily generalized to do what one actually wishes done.
Their abstractions leak.
Boost high precision arithmetic gmp_int A messy pile built on top of
GMP. Its primary benefit is that it makes gmp look like mpir Easier to use MPIR directly.
The major benefit of boost gmp is that it runs on some machines and
operating systems that mpir does not, and is for the most part source code
compatible with mpir.
A major difference is that boost gmp uses long integers, which are on sixty
four bit windows int32_t, where mpir uses mpir_ui and mpir_si, which are
on sixty four bit windows uint64_t and int64_t. This is apt to induce no
end of major porting issues between operating systems.
Boost gmp code running on windows is apt to produce radically different
results to the same boost gmp code running on linux. Long int is just not
portable, and should never be used. This kind of issue is absolutely typical
of boost.
In addition to the portability issue, it is also a typical example of boost abstractions denying you access to the full capability of the thing being abstracted away. It is silly to have a thirty two bit interface between sixty four bit hardware and unlimited arithmetic precision software.
The blockchain is a massively distributed database built on top of a pile of single machine, single disk, databases communicating over the network. If you want a single machine, single disk, database, go with SQLite, which in WAL mode implements synch interaction on top of hidden asynch.
SQLite have their own way of doing things, that does not play nice with Github.
The efficient and simple way to handle interaction with the network is via callbacks rather than multithreading, but you usually need to handle databases, and under the hood, all databases are multithreaded and blocking. If they implement callbacks, it is usually on top of a multithreaded layer, and the abstraction is apt to leak, apt to result in unexpected blocking on a supposedly asynchronous callback.
SQLite recommends at most one thread that writes to the database, and preferably only one thread that interacts with the database.
Comes with an I2P webserver, and the full api for streaming stuff. These appear as local ports on your system. They are not tcp ports, but higher level protocols, and UDP. (Sort of UDP - obviously you have to create a durable tunnel, and one end is the server, the other the client.)
Inconveniently, written in java.
QUIC UDP with flow control and reliability. Intimately married to http/2, https/2, and google chrome. Cannot call as library, have to analyze code, extract their ideas, and rewrite. And, looking at their code, I think they have written their way into a blind alley.
But QUIC is http/2, and there is a gigantic ecosystem supporting http/2.
We really have no alternative but to somehow interface to that ecosystem.
QUIC is UDP with flow control, reliability, and SSL/TLS encryption, but no DDoS resistance, and total insecurity against CA attack.)
Boost implements event oriented multithreading in IO service, but don’t like it because it fails to interface with Microsoft’s implementation of asynch internet protocol, WSAAsync, and WSAEvent. Also because brittle, incomprehensible, and their example programs do not easily generalize to anything other than that particular example.
To the extent that you need to interact with a database, you need to process
connections from clients in many concurrent threads. Connection handlers are
run in thread, that called io_service::run().
You can create a pool of threads processing connection handlers (and waiting
for finalizing database connection), by running io_service::run() from
multiple threads. See Boost.Asio docs.
I tried boost asio, and concluded it was broken, trying to do stuff that cannot be done, and hide stuff that cannot be hidden in abstractions that leak horribly.
But Asio by itself (comes with MSYS2) might work.
SQLite nominally has synchronous access, and the use of one read/write thread, many read threads is recommended. But under the hood, if you enable WAL mode, access is asynchronous. The nominal synchrony sometimes leaks into the underlying asynchrony.
By default, each INSERT is its own transaction, and transactions are
excruciatingly slow. Wal normal mode fixes this. All writes are writes to the
writeahead file, which gets cleaned up later.
The authors of SQLite recommend against multithreading writes, but we do not want the network waiting on the disk, nor the disk waiting on the network, therefore, one thread with asynch for the network, one purely synchronous thread for the SQLite database, and a few number crunching threads for encryption, decryption, and hashing. This implies shared nothing message passing between threads.
Facebook Folly library provides many tools, with such documentation as
exists amounting to “read the f*****g header files”. They are reputed
to have the highest efficiency queuing for interthread communication, and it
is plausible that they do, because facebook views efficiency as critical.
Their [queuing header file]
(https://github.com/facebook/folly/blob/master/folly/MPMCQueue.h) gives us
MPMCQueue.
On the other hand, boost gives us a lockless interthread queue, which should be very efficient. Assuming each thread is an event handler, rather than pseudo synchronous, we queue up events in the boost queue, and handle all unhandled exceptions from the event handler before getting the next item from the queue. We keep enough threads going that we do not mind threads blocking sometimes. The queue owns objects not currently being handled by a particular thread. Objects are allocated in a particular thread, and freed in a particular thread, which process very likely blocks briefly. Graphic events are passed to the master thread by the wxWindows event code, but we use our own mutltithreaded event code to handle everything else. Posting an event to the gui code will block briefly.
I was looking at boost’s queues and lockless mechanisms from the point of view of implementing my own thread pool, but this is kind of stupid, since boost already has a thread pool mechanism written to handle the asynch IO problem. Thread pools are likely overkill. Node.js does not need them, because its single thread does memory to memory operations.
Boost provides us with an io_service and boost::thread group, used to
give effect to asynchronous IO with a thread pool. io_service was specifically written to perform io, but can be used for any
thread pool activity whatsoever. You can “post” tasks to the io_service,
which will get executed by one of the threads in the pool. Each such task has
to be a functor.
Since supposedly nonblocking operations always leak and block, all we can do is try to have blocking minimal. For example nonblocking database operations always block. Thus our threadpool needs to be many times larger than our set of hardware threads, because we will always wind up doing blocking operations.
The C++11 multithreading model assumes you want to do some task in parallel,
for example you are multiplying two enormous matrices, so you spawn a bunch
of threads, then you wait for them all to complete using join, or all to
deliver their payload using futures and promises. This does not seem all that
useful, since the major practical issue is that you want your system to
continue to be responsive while it is waiting for some external hardware to
reply. When you are dealing with external events, rather than grinding a
matrix in parallel, event oriented architecture, rather than futures,
promises, and joins is what you need.
Futures, promises, and joins are useful in the rather artificial case that responding to an remote procedure call requires you to make two or more remote procedure calls, and wait for them to complete, so that you then have the data to respond to a remote procedure call.
Futures, promises, and joins are useful on a server that launches one thread per client, which is often a sensible way to do things, but does not fit that well to the request response pattern, where you don’t have a great deal of client state hanging around, and you may well have ten thousand clients If you can be pretty sure you are only going to have a reasonably small number of clients at any one time, or and significant interaction between clients, one thread per client may well make a lot of sense.
I was planning to use boost asynch, but upon reading the boost user threads, sounds fragile, a great pile of complicated unintelligible code that does only one thing, and if you attempt to do something slightly different, everything falls apart, and you have to understand a lot of arcane details, and rewrite them.
Nanomsg is a socket library, that provides a layer on top of everything that makes everything look like sockets, and provides sockets specialized to various communication patterns, avoiding the roll your own problem. In the zeroMQ thread, people complained that a simple hello world TCP-IP program tended to be disturbingly large and complex Looks to me that Nanomsg wraps a lot of that complexity.
Sockets # Tcl
Tcl # Time
After spending far too much time on this issue, which is has sucked in far too many engineers and far too much thought, and generated far too many libraries, I found the solution was c++11 Chrono: For short durations, we use the steady time in milliseconds, where each machine has its own epoch, and no two machines have exactly the same milliseconds. For longer durations, we use the system time in seconds, where all machines are expected to be within a couple of seconds of each other. For the human readable system time in seconds to be displayed on a particular machine, we use the ISO format 2012‑01‑14_15:39:34+10:00 (timezone with 10 hour offset equivalent to Greenwich time 2012‑01‑14_05:39:34+00:00)
Windows and Unix both use time in seconds, but accessed and manipulated in incompatible ways. The C++11 Chrono libraries imposes a uniform sanity on them all.
Boost has numerous different and not altogether compatible time libraries, all of them overly clever and all of them overly complicated.
wxWidgets has OS independent time based on milliseconds past the epoch which however fails to compress under Cap'n Proto.
I was favourably impressed by the approach to time taken in tcp packets, that the time had to be approximately linear, and in milliseconds or larger, but they were entirely relaxed about the two ends of a tcp connection using different clocks with different, and variable, speeds.
It turns out you can go a mighty long way without a global time, and to the extent that you do need a global time, should be equivalent to that used in email, which magically hides the leap seconds issue.
UTF‑8 strings and UTF8-CPP # Cap'n Proto
Designed for a download from github and run cmake install. As all software should be.
But for mere serialization to of data to a form invariant between machine architectures and different compilers and different compilers on the same machine, overkill for our purposes. Too much capability.
Awesome C++ A curated list of awesome C/C++ frameworks, libraries, resources, and shiny things
“A curated list of awesome C/C++ frameworks, libraries, resources, and shiny things” {target=“_blank”}
I encountered this when looking at the Wt C++ Web framework, which seems to be mighty cool except I don’t think I have any use for a web framework. But Awesome C++ has a very pile of things that I might use.
Wt has the interesting design principle that every open web page maps to a windows class, every widget on the web page, maps to a windows class, every row in the sql table maps to a windows class. Cool design.
reaction.la gpg key 154588427F2709CD9D7146B01C99BB982002C39F
This work is licensed under the Creative Commons Attribution 4.0 International License.