#include "GattProperty.h"
#include "DBusInterface.h"
#include "GattService.h"
#include "DBusObject.h"
#include "Utils.h"
#include "GattUuid.h"
#include "Logger.h"
namespace ggk {
DBusObject::DBusObject(const DBusObjectPath &path, bool publish)
: publish(publish), path(path), pParent(nullptr)
{
}
DBusObject::DBusObject(DBusObject *pParent, const DBusObjectPath &pathElement)
: publish(pParent->publish), path(pathElement), pParent(pParent)
{
}
bool DBusObject::isPublished() const
{
return publish;
}
const DBusObjectPath &DBusObject::getPathNode() const
{
return path;
}
DBusObjectPath DBusObject::getPath() const
{
DBusObjectPath path = getPathNode();
const DBusObject *pCurrent = pParent;
while(nullptr != pCurrent)
{
path = pCurrent->getPathNode() + path;
pCurrent = pCurrent->pParent;
}
return path;
}
DBusObject &DBusObject::getParent()
{
return *pParent;
}
const std::list<DBusObject> &DBusObject::getChildren() const
{
return children;
}
DBusObject &DBusObject::addChild(const DBusObjectPath &pathElement)
{
children.push_back(DBusObject(this, pathElement));
return children.back();
}
const DBusObject::InterfaceList &DBusObject::getInterfaces() const
{
return interfaces;
}
GattService &DBusObject::gattServiceBegin(const std::string &pathElement, const GattUuid &uuid)
{
DBusObject &child = addChild(DBusObjectPath(pathElement));
GattService &service = *child.addInterface(std::make_shared<GattService>(child, "org.bluez.GattService1"));
service.addProperty<GattService>("UUID", uuid);
service.addProperty<GattService>("Primary", true);
return service;
}
std::shared_ptr<const DBusInterface> DBusObject::findInterface(const DBusObjectPath &path, const std::string &interfaceName, const DBusObjectPath &basePath) const
{
if ((basePath + getPathNode()) == path)
{
for (std::shared_ptr<const DBusInterface> interface : interfaces)
{
if (interfaceName == interface->getName())
{
return interface;
}
}
}
for (const DBusObject &child : getChildren())
{
std::shared_ptr<const DBusInterface> pInterface = child.findInterface(path, interfaceName, basePath + getPathNode());
if (nullptr != pInterface)
{
return pInterface;
}
}
return nullptr;
}
bool DBusObject::callMethod(const DBusObjectPath &path, const std::string &interfaceName, const std::string &methodName, GDBusConnection *pConnection, GVariant *pParameters, GDBusMethodInvocation *pInvocation, gpointer pUserData, const DBusObjectPath &basePath) const
{
if ((basePath + getPathNode()) == path)
{
for (std::shared_ptr<const DBusInterface> interface : interfaces)
{
if (interfaceName == interface->getName())
{
if (interface->callMethod(methodName, pConnection, pParameters, pInvocation, pUserData))
{
return true;
}
}
}
}
for (const DBusObject &child : getChildren())
{
if (child.callMethod(path, interfaceName, methodName, pConnection, pParameters, pInvocation, pUserData, basePath + getPathNode()))
{
return true;
}
}
return false;
}
void DBusObject::tickEvents(GDBusConnection *pConnection, void *pUserData) const
{
for (std::shared_ptr<const DBusInterface> interface : interfaces)
{
interface->tickEvents(pConnection, pUserData);
}
for (const DBusObject &child : getChildren())
{
child.tickEvents(pConnection, pUserData);
}
}
std::string DBusObject::generateIntrospectionXML(int depth) const
{
std::string prefix;
prefix.insert(0, depth * 2, ' ');
std::string xml = std::string();
if (depth == 0)
{
xml += "<?xml version='1.0'?>\n";
xml += "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN' 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n";
}
xml += prefix + "<node name='" + getPathNode().toString() + "'>\n";
xml += prefix + " <annotation name='" + TheServer->getServiceName() + ".DBusObject.path' value='" + getPath().toString() + "' />\n";
for (std::shared_ptr<const DBusInterface> interface : interfaces)
{
xml += interface->generateIntrospectionXML(depth + 1);
}
for (DBusObject child : getChildren())
{
xml += child.generateIntrospectionXML(depth + 1);
}
xml += prefix + "</node>\n";
if (depth == 0)
{
Logger::debug("Generated XML:");
Logger::debug(xml);
}
return xml;
}
void DBusObject::emitSignal(GDBusConnection *pBusConnection, const std::string &interfaceName, const std::string &signalName, GVariant *pParameters)
{
GError *pError = nullptr;
gboolean result = g_dbus_connection_emit_signal
(
pBusConnection,
NULL,
getPath().c_str(),
interfaceName.c_str(),
signalName.c_str(),
pParameters,
&pError
);
if (0 == result)
{
Logger::error(SSTR << "Failed to emit signal named '" << signalName << "': " << (nullptr == pError ? "Unknown" : pError->message));
}
}
};