Files
salmanoff/smocore/deviceManager/deviceManager.cpp
T
hayodea 816a047920 Async: new hierachy; manages reply posting and unlocking
Async: Use new [Non]PostedAsyncCont and callOriginalCb

This new hierarchy of classes gives us a central mechanism for
managing both reply-posting and lockSpec unlocking.

* callOriginalCb: Now uses a modern C++ variadic template design
  enabling it to handle both direct calling and std::bind()
  re-binding of an arbitrary number of arguments from the caller.

This enables us to mostly eliminate the repeated, bespoke
definitions of callOriginalCb littered throughout the codebase.

We've also propagated these changes throughout the codebase in
this patch.
2025-09-17 16:38:48 -04:00

152 lines
4.1 KiB
C++

#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
#include <opts.h>
#include <asynchronousContinuation.h>
#include <deviceManager/deviceManager.h>
#include <senseApis/senseApiManager.h>
#include <marionette/marionette.h>
namespace smo {
namespace device {
std::vector<std::shared_ptr<InteroceptorDevAttachmentSpec>>
DeviceManager::interoceptorDeviceSpecs;
std::vector<std::shared_ptr<ExtrospectorDevAttachmentSpec>>
DeviceManager::extrospectorDeviceSpecs;
std::vector<std::shared_ptr<DeviceAttachmentSpec>>
DeviceManager::deviceAttachmentSpecs;
std::vector<std::shared_ptr<Device>>
DeviceManager::devices;
const std::string DeviceManager::stringifyDeviceSpecs(void)
{
std::ostringstream oss;
for (const auto& spec : DeviceManager::interoceptorDeviceSpecs) {
oss << "Interoceptor " << spec->stringify();
}
for (const auto& spec : DeviceManager::extrospectorDeviceSpecs) {
oss << "Extrospector " << spec->stringify();
}
return oss.str();
}
class DeviceManager::NewDeviceAttachmentSpecInd
: public PostedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>
{
public:
NewDeviceAttachmentSpecInd(
std::shared_ptr<DeviceAttachmentSpec> s,
const std::shared_ptr<ComponentThread> &caller,
newDeviceAttachmentSpecIndCbFn cb)
: PostedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>(
caller, cb),
spec(s)
{}
public:
std::shared_ptr<DeviceAttachmentSpec> spec;
public:
void newDeviceAttachmentSpecInd1_posted(
[[maybe_unused]] std::shared_ptr<NewDeviceAttachmentSpecInd> context
)
{
sense_api::SenseApiManager::getInstance().attachSenseDeviceReq(
spec,
std::bind(
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd2,
context.get(), context,
std::placeholders::_1, std::placeholders::_2));
}
void newDeviceAttachmentSpecInd2(
[[maybe_unused]] std::shared_ptr<NewDeviceAttachmentSpecInd> context,
bool success,
std::shared_ptr<DeviceAttachmentSpec> deviceSpec
)
{
if (!success)
{
std::cerr << __func__ << ": Attach failed for device spec "
<< deviceSpec->stringify() << std::endl;
callOriginalCb(false, nullptr, deviceSpec);
return;
}
try {
/** EXPLANATION:
* Remember that deviceAttachmentSpecs don't refer to devices, but
* rather to roles that a device can enact when attached to in the
* described manner. Therefore, it's possible for multiple DA specs
* to refer to the same device.
*
* That's why we need to ensure that the device doesn't already
* exist before trying to create a new device for it.
*/
std::shared_ptr<Device> device = nullptr;
for (const auto& existingDevice : devices)
{
if (existingDevice->deviceIdentifier != spec->deviceIdentifier)
{ continue; }
device = existingDevice;
break;
}
// If device doesn't exist, create a new one and add it
if (!device)
{
device = std::make_shared<Device>(spec->deviceIdentifier);
devices.push_back(device);
}
// Add DeviceAttachmentSpec to device's list
device->deviceAttachmentSpecs.push_back(spec);
// Add DeviceAttachmentSpec to DeviceManager's list
deviceAttachmentSpecs.push_back(spec);
// Callback with success
callOriginalCb(true, device, spec);
} catch (const std::exception& e) {
// Attach failed, callback with error
callOriginalCb(false, nullptr, spec);
}
}
};
void DeviceManager::newDeviceAttachmentSpecInd(
std::shared_ptr<DeviceAttachmentSpec> spec,
newDeviceAttachmentSpecIndCbFn callback)
{
// Check if a DeviceAttachmentSpec already matches
for (const auto& existingSpec : deviceAttachmentSpecs)
{
if (!(*existingSpec == *spec)) { continue; }
// Already exists, callback with error
callback(false, nullptr, spec);
return;
}
// Create async continuation
const auto& caller = ComponentThread::getSelf();
auto continuation = std::make_shared<NewDeviceAttachmentSpecInd>(
spec, caller, callback);
mrntt::mrntt.thread->getIoService().post(
std::bind(
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd1_posted,
continuation.get(), continuation));
}
} // namespace device
} // namespace smo