stasher::currentbaseObj<classptr>: virtual superclass for stasher::create_manage_object()'s functors

The following example is an alternate version of showinventory.C that uses stasher::currentBaseObj:

#include <stasher/client.H>
#include <stasher/manager.H>
#include <stasher/currentbase.H>

#include "inventory.H"

class subscriptionObj : public stasher::currentBaseObj<inventoryptr> {

public:
	subscriptionObj() {}
	~subscriptionObj() {}

	void update(const inventoryptr &newvalue, bool isinitial) override;

	void connection_update(stasher::req_stat_t) override;
};

void update(const inventoryptr &ptr, bool initial);

void showinventory(int argc, char **argv)
{
	if (argc < 2)
		return;

	auto client=stasher::client::base::connect();
	auto manager=stasher::manager::create();

	std::cout << "Showing current inventory, press Enter to stop"
		  << std::endl;

	auto subscriber=x::ref<subscriptionObj>::create();
	x::ref<x::obj> mcguffin=subscriber->manage(manager, client,
						   argv[1]);

	std::string dummy;

	std::getline(std::cin, dummy);
}

void subscriptionObj::update(const inventoryptr &ptr, bool initial)
{
	std::cout << (initial ? "Current inventory:":"Updated inventory:")
		  << std::endl;

	if (ptr.null())
	{
		std::cout << "    (none)" << std::endl;
	}
	else
	{
		std::cout << "    "
			  << std::setw(30) << std::left
			  << "Item"
			  << "   "
			  << std::setw(8) << std::right
			  << "Count" << std::setw(0)
			  << std::endl;

		std::cout << "    "
			  << std::setfill('-') << std::setw(30)
			  << ""
			  << "   "
			  << std::setw(8)
			  << "" << std::setw(0) << std::setfill(' ')
			  << std::endl;

		for (auto &item:ptr->stock)
		{
			std::cout << "    "
				  << std::setw(30) << std::left
				  << item.first
				  << "   "
				  << std::setw(8) << std::right
				  << item.second << std::setw(0)
				  << std::endl;
		}
		std::cout << std::setw(75) << std::setfill('=') << ""
			  << std::setw(0) << std::setfill(' ') << std::endl;
	}

}

void subscriptionObj::connection_update(stasher::req_stat_t status)
{
	std::cout << "Connection update: "
		  << x::tostring(status) << std::endl;
}

int main(int argc, char **argv)
{
	try {
		showinventory(argc, argv);
	} catch (const x::exception &e)
	{
		std::cerr << e << std::endl;
		return 1;
	}
	return 0;
}

The stasher::currentBaseObj<classptr> template defines a class with two virtual methods, update() and connection_update(); and a manage() method. manage() takes a manager object, and client connection object, and an object name as parameters; it invokes stasher::create_managed_object with functors that invoke the update() and connection_update() methods, then calls the manager's manage_object() method, like showinventory.C does, and returns the managed object's mcguffin.

To summarize:

Note

The functors created by manage(), then get incorporated into the instantiated managed object, hold a strong reference to the stasher::currentBaseObj and its subclass. The subclass should not store the mcguffin in the class instance, that creates a circular reference. If an execution thread is running the subclass, it's generally fine to store the mcguffin on the executing thread's stack, which will go out of scope and get destroyed when the executing thread returns.

Also note that update() and connection_update() are invoked by the functors with certain limitations, described in showinventory.C typically invoked by the client connection thread, and they have certain limitations, see stasher::create_managed_object for more information.