How to create a Logos Module - logos-co/logos-core-poc GitHub Wiki
Note: WIP and subject to change
Navigate to the modules/ directory and create a new folder for your module:
cd modules
mkdir my_new_module
cd my_new_moduleNote: The module can be in a separate repo
Create a file named my_new_module_interface.h. This defines the API your module exposes.
#pragma once
#include <QtCore/QObject>
#include "../../core/interface.h"
class MyNewModuleInterface : public PluginInterface
{
public:
virtual ~MyNewModuleInterface() {}
Q_INVOKABLE virtual bool foo(const QString &bar) = 0;
signals:
// Required for event communication
void eventResponse(const QString& eventName, const QVariantList& data);
};
#define MyNewModuleInterface_iid "org.logos.MyNewModuleInterface"
Q_DECLARE_INTERFACE(MyNewModuleInterface, MyNewModuleInterface_iid)- Change
fooandbarto your desired method and parameter names. - Update the IID string to match your module.
- Include the
eventResponsesignal for event-based communication.
Note: An #include "interface.h" is needed for the module to have an interface the core understands. One can just include this directly in the project. Here it's relative since it's in the same repo and we want to take advantage of any changes to the core without having to copy interface files.
Create my_new_module_plugin.h:
#pragma once
#include <QtCore/QObject>
#include "my_new_module_interface.h"
#include "../../SDK/cpp/logos_api.h"
class MyNewModulePlugin : public QObject, public MyNewModuleInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID MyNewModuleInterface_iid FILE "metadata.json")
Q_INTERFACES(MyNewModuleInterface PluginInterface)
public:
MyNewModulePlugin();
~MyNewModulePlugin();
Q_INVOKABLE bool foo(const QString &bar) override;
QString name() const override { return "my_new_module"; }
QString version() const override { return "1.0.0"; }
signals:
// Required for event communication
void eventResponse(const QString& eventName, const QVariantList& data);
private:
LogosAPI* logosAPI;
};Note: The plugin now includes the LogosAPI header and has a private LogosAPI pointer for interacting with the Logos Core system.
Create my_new_module_plugin.cpp:
#include "my_new_module_plugin.h"
#include <QDebug>
#include <QCoreApplication>
#include <QVariantList>
#include <QDateTime>
MyNewModulePlugin::MyNewModulePlugin() : logosAPI(nullptr)
{
qDebug() << "MyNewModulePlugin: Initializing...";
// Initialize the Logos API
logosAPI = new LogosAPI("core_registry", this);
qDebug() << "MyNewModulePlugin: Initialized successfully";
}
MyNewModulePlugin::~MyNewModulePlugin()
{
// Clean up resources
if (logosAPI) {
delete logosAPI;
logosAPI = nullptr;
}
}
bool MyNewModulePlugin::foo(const QString &bar)
{
qDebug() << "MyNewModulePlugin::foo called with:" << bar;
// Create event data with the bar parameter
QVariantList eventData;
eventData << bar; // Add the bar parameter to the event data
eventData << QDateTime::currentDateTime().toString(Qt::ISODate); // Add timestamp
// Trigger the event using LogosAPI
if (logosAPI) {
qDebug() << "MyNewModulePlugin: Triggering event 'fooTriggered' with data:" << eventData;
logosAPI->onEventResponse(this, "fooTriggered", eventData);
qDebug() << "MyNewModulePlugin: Event 'fooTriggered' triggered with data:" << eventData;
} else {
qWarning() << "MyNewModulePlugin: LogosAPI not available, cannot trigger event";
}
return true;
}Note: The implementation now uses LogosAPI to interact with the Logos Core system and emit events.
Create metadata.json:
{
"name": "my_new_module",
"version": "1.0.0",
"description": "Describe your module here",
"author": "Your Name or Team",
"type": "core",
"category": "custom",
"main": "my_new_module_plugin",
"dependencies": [],
"capabilities": [
"custom_capability"
]
}Create CMakeLists.txt:
set(CMAKE_AUTOMOC ON)
# Find Qt RemoteObjects (needed for LogosAPI)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core RemoteObjects)
# Plugin sources
set(PLUGIN_SOURCES
my_new_module_plugin.cpp
my_new_module_plugin.h
my_new_module_interface.h
${CMAKE_SOURCE_DIR}/../core/interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../SDK/cpp/logos_api.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../SDK/cpp/logos_api.h
)
# Create the plugin library
add_library(my_new_module_plugin SHARED ${PLUGIN_SOURCES})
# Set output name without lib prefix
set_target_properties(my_new_module_plugin PROPERTIES
PREFIX "")
# Link Qt libraries
target_link_libraries(my_new_module_plugin PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::RemoteObjects
)
# Include directories
target_include_directories(my_new_module_plugin PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/../core
${CMAKE_CURRENT_SOURCE_DIR}/../../SDK/cpp
)
# Set common properties for both platforms
set_target_properties(my_new_module_plugin PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/modules"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/modules"
BUILD_WITH_INSTALL_RPATH TRUE
SKIP_BUILD_RPATH FALSE)
if(APPLE)
set_target_properties(my_new_module_plugin PROPERTIES
INSTALL_RPATH "@loader_path"
INSTALL_NAME_DIR "@rpath"
BUILD_WITH_INSTALL_NAME_DIR TRUE)
add_custom_command(TARGET my_new_module_plugin POST_BUILD
COMMAND install_name_tool -id "@rpath/my_new_module_plugin.dylib" $<TARGET_FILE:my_new_module_plugin>
COMMENT "Updating library paths for macOS"
)
else()
set_target_properties(my_new_module_plugin PROPERTIES
INSTALL_RPATH "$ORIGIN"
INSTALL_RPATH_USE_LINK_PATH FALSE)
endif()Note: The CMake file now includes Qt RemoteObjects as a dependency and includes the LogosAPI source files.
Edit modules/CMakeLists.txt and add:
add_subdirectory(my_new_module)From the root of your project:
./scripts/clean.sh && ./scripts/run_app.sh all- Start the Logos Core app.
- Your module should be detected and loaded.
- Check the logs for
"MyNewModulePlugin: Initializing..."and"MyNewModulePlugin: Initialized successfully"messages. - When your module's API is called, you should see
"MyNewModulePlugin::foo called with:"and event triggering messages.
The LogosAPI provides several useful methods for interacting with the Logos Core system:
-
requestObject(objectName): Get a remote object by name -
callRemoteMethod(objectName, methodName, args): Call a method on a remote object -
onEvent(originObject, destinationObject, eventName, callback): Register an event listener -
onEventResponse(replica, eventName, data): Trigger an event
Example of calling a method on another module:
// Get a result from another module
QVariant result = logosAPI->callRemoteMethod("other_module", "someMethod", QVariantList() << "param1" << "param2");
// Listen for events from another module
logosAPI->onEvent(otherModuleObject, this, "someEvent", [this](const QString& eventName, const QVariantList& data) {
qDebug() << "Received event:" << eventName << "with data:" << data;
// Handle the event
});- Add more methods to your interface and implementation as needed.
- Update metadata and capabilities to reflect your module's features.
- Use LogosAPI to interact with other modules in the Logos Core system.
See modules/template_module for a working example.