Implement plugin with the new lib

This commit is contained in:
jussi 2020-03-18 01:39:44 +02:00
parent 8eb738b9ff
commit 32b3321a33
12 changed files with 212 additions and 154 deletions

View File

@ -1,6 +1,8 @@
project('tuxclocker', 'c', 'cpp')
project('tuxclocker', 'c', 'cpp',
default_options : ['cpp_std=c++17'])
cc = meson.get_compiler('c')
cppc = meson.get_compiler('cpp')
incdir = include_directories('src/include', 'src/include/deps')

View File

@ -1,6 +1,6 @@
# By default, library and modules (except interfaces) are built
option('daemon', type: 'boolean', value: 'false', description: 'Build daemon')
option('modules', type: 'boolean', value: 'true', description: 'Build modules')
option('plugins', type: 'boolean', value: 'true', description: 'Build plugins')
option('interfaces', type: 'boolean', value: 'false', description: 'Build interfaces')
option('library', type: 'boolean', value: 'true', description: 'Build library')

View File

@ -1,5 +1,7 @@
#pragma once
#include <functional>
#include <optional>
#include <string>
#include <variant>
#include <vector>
@ -7,6 +9,14 @@
namespace TuxClocker {
namespace Device {
enum class AssignmentError {
InvalidArgument
};
enum class ReadError {
UnknownError
};
template <typename T>
struct Range {
Range();
@ -20,15 +30,43 @@ struct Enumeration {
uint key;
};
using AssignmentArgument = std::variant<int, double, uint>;
using ReadableValue = std::variant<int, double>;
using RangeInfo = std::variant<Range<int>, Range<double>>;
using AssignableInfo = std::variant<RangeInfo, std::vector<Enumeration>>;
class Assignable {
public:
Assignable();
Assignable(const std::function<std::optional<AssignmentError>(AssignmentArgument)> assignmentFunc) {
m_assignmentFunc = assignmentFunc;
}
std::optional<AssignmentError> assign(AssignmentArgument arg) {
return m_assignmentFunc(arg);
}
private:
std::function<std::optional<AssignmentError>(AssignmentArgument)> m_assignmentFunc;
};
class DynamicReadable {
public:
DynamicReadable(const std::function<std::variant<ReadError, ReadableValue>()> readFunc) {
m_readFunc = readFunc;
}
std::variant<ReadError, ReadableValue> read() {
return m_readFunc();
}
private:
std::function<std::variant<ReadError, ReadableValue>()> m_readFunc;
};
// DeviceNode has a name, and optionally implements one of [Assignable, DynamicReadable]
using DeviceInterface = std::variant<Assignable, DynamicReadable>;
struct DeviceNode {
std::string name;
std::optional<DeviceInterface> interface;
};
};
};

View File

@ -1,9 +1,48 @@
#pragma once
#include <boost/config.hpp>
#include <boost/dll/import.hpp>
#include <optional>
#include <string>
#include "Device.hpp"
#include "Tree.hpp"
#define TUXCLOCKER_PLUGIN_EXPORT(PluginType) \
extern "C" BOOST_SYMBOL_EXPORT PluginType __plugin; \
PluginType __plugin;
#define TUXCLOCKER_PLUGIN_SYMBOL_NAME "__plugin"
namespace TuxClocker {
namespace Plugin {
namespace dll = boost::dll;
enum class InitializationError {
UnknownError
};
using namespace TuxClocker::Device;
class Plugin {
public:
static std::string pluginDirName() {return "plugins";}
// Full path is efined at compile time
static std::string pluginPath();
};
class DevicePlugin {
public:
// Communicate plugin initialization success in this way since constructors cannot communicate it.
virtual std::optional<InitializationError> initializationError() = 0;
virtual void foo() = 0;
virtual TreeNode<DeviceNode> deviceRootNode() = 0;
virtual ~DevicePlugin() {}
// Helper for loading all DevicePlugin's
static std::optional<std::vector<boost::shared_ptr<DevicePlugin>>> loadPlugins();
};
};
};

View File

@ -17,9 +17,14 @@ class FlatTree {
template <typename T>
class TreeNode {
public:
TreeNode() {};
TreeNode(T value) {m_value = value;}
void appendChild(T value) {m_children.push_back(TreeNode{value});}
std::vector<TreeNode<T>> children() {return m_children;}
private:
T value;
std::vector<TreeNode<T>> children;
T m_value;
std::vector<TreeNode<T>> m_children;
};
};

28
src/lib/Plugin.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <Plugin.hpp>
#include <filesystem>
#include <sstream>
using namespace TuxClocker::Plugin;
namespace fs = std::filesystem;
std::string Plugin::pluginPath() {
return TC_PLUGIN_PATH;
}
std::optional<std::vector<boost::shared_ptr<DevicePlugin>>> DevicePlugin::loadPlugins() {
std::vector<boost::shared_ptr<DevicePlugin>> retval;
for (const fs::directory_entry &entry : fs::directory_iterator(Plugin::pluginPath())) {
// Bleh, have to catch this unless I do more manual checks
try {
auto plugin = dll::import<DevicePlugin>(entry.path().string(), TUXCLOCKER_PLUGIN_SYMBOL_NAME);
retval.push_back(plugin);
}
catch (boost::system::system_error &e) {}
}
if (retval.empty()) return std::nullopt;
return retval;
}

View File

@ -7,14 +7,14 @@
int main(int argc, char **argv) {
// Load an interface here
tc_module_t *mod = tc_module_find(TC_CATEGORY_INTERFACE, "qt");
/*tc_module_t *mod = tc_module_find(TC_CATEGORY_INTERFACE, "qt");
if (mod != NULL) {
printf("successful load for %s\n", mod->name);
mod->init_callback(argc, argv);
tc_module_close(mod);
}
}*/
return 0;
}

View File

@ -5,27 +5,46 @@ openssl_dep = dependency('openssl')
# Jansson is used for module database
jansson_dep = dependency('jansson')
# For posix only
dl = cppc.find_library('dl')
boost_dep = dependency('boost',
modules : ['system',
'filesystem'])
libtuxclocker_posix_sources = ['lib/posix/module.c',
'lib/posix/filesystem.c']
libtuxclocker_posix_libs = [cc.find_library('dl')]
# Compile time definition for module path
module_path_def_template = '-DTC_MODULE_PATH="@0@/@1@/tuxclocker/modules"'
module_path_def = module_path_def_template.format(get_option('prefix'), get_option('libdir'))
plugin_path_def_template = '-DTC_PLUGIN_PATH="@0@/@1@/tuxclocker/plugins"'
plugin_path_def = plugin_path_def_template.format(get_option('prefix'), get_option('libdir'))
libtuxclocker = shared_library('libtuxclocker',
['lib/tc_assignable.c',
'lib/tc_module.c',
'lib/tc_readable.c',
'lib/tc_common.c',
libtuxclocker_posix_sources],
#libtuxclocker = shared_library('libtuxclocker',
# ['lib/tc_assignable.c',
# 'lib/tc_module.c',
# 'lib/tc_readable.c',
# 'lib/tc_common.c',
# libtuxclocker_posix_sources],
# include_directories : incdir,
# dependencies : [libtuxclocker_posix_libs, openssl_dep, jansson_dep],
# c_args : module_path_def,
# install : true)
libtuxclocker = shared_library('tuxclocker',
['lib/Plugin.cpp'],
override_options : ['cpp_std=c++17'],
include_directories : incdir,
dependencies : [libtuxclocker_posix_libs, openssl_dep, jansson_dep],
c_args : module_path_def,
dependencies : [boost_dep, dl],
cpp_args : plugin_path_def,
install : true)
subdir('modules')
if get_option('plugins')
subdir('plugins')
endif
subdir('main')
if get_option('library')

View File

@ -1 +1,34 @@
#include <Plugin.hpp>
#include <iostream>
using namespace TuxClocker::Plugin;
using namespace TuxClocker::Device;
using namespace TuxClocker;
class AMDPlugin : public DevicePlugin {
public:
AMDPlugin();
std::optional<InitializationError> initializationError() {return std::nullopt;}
void foo() {std::cout << "hi from AMD plugin\n";}
TreeNode<DeviceNode> deviceRootNode();
~AMDPlugin() {}
private:
TreeNode<DeviceNode> m_rootNode;
};
AMDPlugin::AMDPlugin() {
/*Assignable a([](auto arg) {
return std::nullopt;
});
DeviceNode root{"AMD", a};
m_rootNode.appendChild(root);*/
}
TreeNode<DeviceNode> AMDPlugin::deviceRootNode() {
;
return m_rootNode;
}
TUXCLOCKER_PLUGIN_EXPORT(AMDPlugin)

5
src/plugins/meson.build Normal file
View File

@ -0,0 +1,5 @@
shared_library('amd', 'AMD.cpp',
override_options : ['cpp_std=c++17'],
include_directories : incdir,
install_dir : get_option('libdir') / 'tuxclocker' / 'plugins',
install : true)

View File

@ -3,136 +3,28 @@
#include <QDBusError>
#include <QDBusMetaType>
#include <QDebug>
#include <tc_module.h>
#include <Plugin.hpp>
#include "AssignableAdaptorFactory.h"
#include "EnumData.h"
#include "Result.h"
#include "ReadableAdaptorFactory.h"
void registerMetatypes() {
//qRegisterMetaType<Result<QDBusVariant>>();
qDBusRegisterMetaType<Result<QDBusVariant>>();
//qRegisterMetaType<EnumData>();
qDBusRegisterMetaType<EnumData>();
qDBusRegisterMetaType<QList<EnumData>>();
}
void registerReadables(QObject *parent, QDBusConnection conn) {
uint16_t count;
auto modules = tc_module_find_all_from_category(TC_CATEGORY_READABLE, &count);
QList <tc_readable_module_data_t> dataList;
for (uint16_t i = 0; i < count; i++) {
auto mod = modules[i];
/*if (modules[i]->init_callback && modules[i]->init_callback() == TC_SUCCESS) {
auto &module = modules[i];
// Module was initialized successfully
// TODO : make a function in the lib to get a list of category specific data
for (auto i = 0; i < module->category_info.num_categories; i++) {
if (module->category_info.category_data_list[i].category == TC_READABLE) {
dataList.append(module->category_info.category_data_list[i].readable_data());
break;
}
}
}*/
for (uint16_t i = 0; i < mod->category_info.num_categories; i++) {
if (mod->category_info.category_data_list[i].category == TC_READABLE
&& mod->category_info.category_data_list[i].init
&& mod->category_info.category_data_list[i].init() == TC_SUCCESS) {
dataList.append(mod->category_info.category_data_list[i].readable_data());
break;
}
}
}
std::function<void (tc_readable_node_t*, tc_readable_module_data_t, QString, int)> traverse;
traverse = [=, &traverse, &conn](tc_readable_node_t *node, tc_readable_module_data_t data, QString path, int n) {
if (node->name) {
qDebug() << node->name;
}
path = path + "/" + QString::number(n);
qDebug() << path;
auto obj = new QObject(parent);
//new ReadableDynamicVariantAdaptor(obj);
ReadableAdaptorFactory::readableAdaptor(obj, node);
conn.registerObject(path, obj);
for (uint16_t i = 0; i < node->children_count; i++) {
traverse(node->children_nodes[i], data, path, n + i);
}
};
QString p = "/Readable";
for (auto data : dataList) {
for (uint16_t i = 0; i < data.root_node->children_count; i++) {
traverse(data.root_node->children_nodes[i], data, p, 0);
}
}
}
void registerAssignables(QObject *parent, QDBusConnection conn) {
uint16_t count;
auto modules = tc_module_find_all_from_category(TC_CATEGORY_ASSIGNABLE, &count);
QList <tc_assignable_module_data_t> dataList;
for (uint16_t i = 0; i < count; i++) {
/*if (modules[i]->init_callback && modules[i]->init_callback() == TC_SUCCESS) {
auto &module = modules[i];
for (uint16_t i = 0; i < module->category_info.num_categories; i++) {
if (module->category_info.category_data_list[i].category == TC_ASSIGNABLE) {
dataList.append(module->category_info.category_data_list[i].assignable_data());
break;
}
}
}*/
auto mod = modules[i];
for (uint16_t i = 0; i < mod->category_info.num_categories; i++) {
if (mod->category_info.category_data_list[i].category == TC_ASSIGNABLE
&& mod->category_info.category_data_list[i].init
&& mod->category_info.category_data_list[i].init() == TC_SUCCESS) {
dataList.append(mod->category_info.category_data_list[i].assignable_data());
break;
}
}
}
std::function <void (tc_assignable_node_t*, tc_assignable_module_data_t, QString, int)> traverse;
traverse = [=, &traverse, &conn](tc_assignable_node_t *node, tc_assignable_module_data_t data, QString path, int n) {
//path = path + "/" + QString::number(n);
path = path + "/" + QString(node->name).replace(" ", "");
auto obj = new QObject(parent);
AssignableAdaptorFactory::assignableAdaptor(obj, node);
if (!conn.registerObject(path, obj)) {
qDebug() << "unable to register object";
}
for (uint16_t i = 0; i < node->children_count; i++) {
traverse(node->children_nodes[i], data, path, n + i);
}
};
QString path ="/Assignable";
for (auto data : dataList) {
for (uint16_t i = 0; i < data.root_node->children_count; i++) {
traverse(data.root_node->children_nodes[i], data, path, 0);
}
}
}
using namespace TuxClocker;
int main(int argc, char **argv) {
QCoreApplication a(argc, argv);
registerMetatypes();
auto plugins = Plugin::DevicePlugin::loadPlugins();
if (plugins.has_value()) {
qDebug() << "found " << plugins.value().size() << " plugins";
for (auto &plugin : plugins.value()) {
plugin->foo();
plugin->deviceRootNode();
}
}
/*registerMetatypes();
QObject root;
@ -144,7 +36,7 @@ int main(int argc, char **argv) {
if (!connection.registerService("org.tuxclocker")) {
qDebug() << "unable to register:" << connection.lastError().message();
}
}*/
return a.exec();
}

View File

@ -2,23 +2,20 @@ qt5 = import('qt5')
qt5_dep = dependency('qt5',
modules : ['DBus'])
moc_files = qt5.preprocess(moc_headers : ['ReadableDynamicVariantAdaptor.h',
'AssignableEnumAdaptor.h',
'AssignableVariantRangeAdaptor.h'],
dependencies : qt5_dep)
boost_dep = dependency('boost', modules : ['system'])
#moc_files = qt5.preprocess(moc_headers : #['ReadableDynamicVariantAdaptor.h',
# 'AssignableEnumAdaptor.h',
# 'AssignableVariantRangeAdaptor.h'],
# dependencies : qt5_dep)
sources = ['main.cpp']
sources = ['main.cpp',
'AssignableAdaptorFactory.cpp',
'AssignableEnumAdaptor.cpp',
'AssignableVariantRangeAdaptor.cpp',
'ReadableAdaptorFactory.cpp',
'ReadableDynamicVariantAdaptor.cpp']
executable('tuxclockerd',
moc_files,
sources,
override_options : ['cpp_std=c++17'],
include_directories : incdir,
dependencies : qt5_dep,
dependencies : [qt5_dep, boost_dep, dl],
link_with : libtuxclocker,
install : true)