refactor: move PluginMeta to its own file (#6757)
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -95,6 +95,7 @@
|
|||||||
- Dev: Removed unused variables. (#6748)
|
- Dev: Removed unused variables. (#6748)
|
||||||
- Dev: Updated `miniaudio` to 0.11.24. (#6754)
|
- Dev: Updated `miniaudio` to 0.11.24. (#6754)
|
||||||
- Dev: Remove unused `reloadChannelAndSubscriberEmotes`. (#6756)
|
- Dev: Remove unused `reloadChannelAndSubscriberEmotes`. (#6756)
|
||||||
|
- Dev: Moved `PluginMeta` to its own file. (#6757)
|
||||||
|
|
||||||
## 2.5.4
|
## 2.5.4
|
||||||
|
|
||||||
|
|||||||
@@ -281,6 +281,8 @@ set(SOURCE_FILES
|
|||||||
controllers/plugins/PluginController.hpp
|
controllers/plugins/PluginController.hpp
|
||||||
controllers/plugins/Plugin.cpp
|
controllers/plugins/Plugin.cpp
|
||||||
controllers/plugins/Plugin.hpp
|
controllers/plugins/Plugin.hpp
|
||||||
|
controllers/plugins/PluginMeta.cpp
|
||||||
|
controllers/plugins/PluginMeta.hpp
|
||||||
controllers/plugins/PluginPermission.cpp
|
controllers/plugins/PluginPermission.cpp
|
||||||
controllers/plugins/PluginPermission.hpp
|
controllers/plugins/PluginPermission.hpp
|
||||||
controllers/plugins/SolTypes.cpp
|
controllers/plugins/SolTypes.cpp
|
||||||
|
|||||||
@@ -9,12 +9,8 @@
|
|||||||
# include "common/QLogging.hpp"
|
# include "common/QLogging.hpp"
|
||||||
# include "controllers/commands/CommandController.hpp"
|
# include "controllers/commands/CommandController.hpp"
|
||||||
# include "controllers/plugins/PluginPermission.hpp"
|
# include "controllers/plugins/PluginPermission.hpp"
|
||||||
# include "util/QMagicEnum.hpp"
|
|
||||||
|
|
||||||
# include <lua.h>
|
# include <lua.h>
|
||||||
# include <magic_enum/magic_enum.hpp>
|
|
||||||
# include <QJsonArray>
|
|
||||||
# include <QJsonObject>
|
|
||||||
# include <QLoggingCategory>
|
# include <QLoggingCategory>
|
||||||
# include <QUrl>
|
# include <QUrl>
|
||||||
# include <sol/sol.hpp>
|
# include <sol/sol.hpp>
|
||||||
@@ -25,174 +21,6 @@
|
|||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
PluginMeta::PluginMeta(const QJsonObject &obj)
|
|
||||||
{
|
|
||||||
auto homepageObj = obj.value("homepage");
|
|
||||||
if (homepageObj.isString())
|
|
||||||
{
|
|
||||||
this->homepage = homepageObj.toString();
|
|
||||||
}
|
|
||||||
else if (!homepageObj.isUndefined())
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(homepageObj.type());
|
|
||||||
this->errors.emplace_back(
|
|
||||||
QString("homepage is defined but is not a string (its type is %1)")
|
|
||||||
.arg(type));
|
|
||||||
}
|
|
||||||
auto nameObj = obj.value("name");
|
|
||||||
if (nameObj.isString())
|
|
||||||
{
|
|
||||||
this->name = nameObj.toString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(nameObj.type());
|
|
||||||
this->errors.emplace_back(
|
|
||||||
QString("name is not a string (its type is %1)").arg(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto descrObj = obj.value("description");
|
|
||||||
if (descrObj.isString())
|
|
||||||
{
|
|
||||||
this->description = descrObj.toString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(descrObj.type());
|
|
||||||
this->errors.emplace_back(
|
|
||||||
QString("description is not a string (its type is %1)").arg(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto authorsObj = obj.value("authors");
|
|
||||||
if (authorsObj.isArray())
|
|
||||||
{
|
|
||||||
auto authorsArr = authorsObj.toArray();
|
|
||||||
for (int i = 0; i < authorsArr.size(); i++)
|
|
||||||
{
|
|
||||||
const auto &t = authorsArr.at(i);
|
|
||||||
if (!t.isString())
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(t.type());
|
|
||||||
this->errors.push_back(
|
|
||||||
QString("authors element #%1 is not a string (it is a %2)")
|
|
||||||
.arg(i)
|
|
||||||
.arg(type));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this->authors.push_back(t.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(authorsObj.type());
|
|
||||||
this->errors.emplace_back(
|
|
||||||
QString("authors is not an array (its type is %1)").arg(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto licenseObj = obj.value("license");
|
|
||||||
if (licenseObj.isString())
|
|
||||||
{
|
|
||||||
this->license = licenseObj.toString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(licenseObj.type());
|
|
||||||
this->errors.emplace_back(
|
|
||||||
QString("license is not a string (its type is %1)").arg(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto verObj = obj.value("version");
|
|
||||||
if (verObj.isString())
|
|
||||||
{
|
|
||||||
auto v = semver::from_string_noexcept(verObj.toString().toStdString());
|
|
||||||
if (v.has_value())
|
|
||||||
{
|
|
||||||
this->version = v.value();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->errors.emplace_back("unable to parse version (use semver)");
|
|
||||||
this->version = semver::version(0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(verObj.type());
|
|
||||||
this->errors.emplace_back(
|
|
||||||
QString("version is not a string (its type is %1)").arg(type));
|
|
||||||
this->version = semver::version(0, 0, 0);
|
|
||||||
}
|
|
||||||
auto permsObj = obj.value("permissions");
|
|
||||||
if (!permsObj.isUndefined())
|
|
||||||
{
|
|
||||||
if (!permsObj.isArray())
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(permsObj.type());
|
|
||||||
this->errors.emplace_back(
|
|
||||||
QString("permissions is not an array (its type is %1)")
|
|
||||||
.arg(type));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto permsArr = permsObj.toArray();
|
|
||||||
for (int i = 0; i < permsArr.size(); i++)
|
|
||||||
{
|
|
||||||
const auto &t = permsArr.at(i);
|
|
||||||
if (!t.isObject())
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(t.type());
|
|
||||||
this->errors.push_back(QString("permissions element #%1 is not "
|
|
||||||
"an object (its type is %2)")
|
|
||||||
.arg(i)
|
|
||||||
.arg(type));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto parsed = PluginPermission(t.toObject());
|
|
||||||
if (parsed.isValid())
|
|
||||||
{
|
|
||||||
// ensure no invalid permissions slip through this
|
|
||||||
this->permissions.push_back(parsed);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (const auto &err : parsed.errors)
|
|
||||||
{
|
|
||||||
this->errors.push_back(
|
|
||||||
QString("permissions element #%1: %2").arg(i).arg(err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tagsObj = obj.value("tags");
|
|
||||||
if (!tagsObj.isUndefined())
|
|
||||||
{
|
|
||||||
if (!tagsObj.isArray())
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(tagsObj.type());
|
|
||||||
this->errors.emplace_back(
|
|
||||||
QString("tags is not an array (its type is %1)").arg(type));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tagsArr = tagsObj.toArray();
|
|
||||||
for (int i = 0; i < tagsArr.size(); i++)
|
|
||||||
{
|
|
||||||
const auto &t = tagsArr.at(i);
|
|
||||||
if (!t.isString())
|
|
||||||
{
|
|
||||||
auto type = qmagicenum::enumName(t.type());
|
|
||||||
this->errors.push_back(
|
|
||||||
QString("tags element #%1 is not a string (its type is %2)")
|
|
||||||
.arg(i)
|
|
||||||
.arg(type));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->tags.push_back(t.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Plugin::registerCommand(const QString &name,
|
bool Plugin::registerCommand(const QString &name,
|
||||||
sol::protected_function function)
|
sol::protected_function function)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,8 +7,7 @@
|
|||||||
#ifdef CHATTERINO_HAVE_PLUGINS
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||||
# include "controllers/plugins/api/EventType.hpp"
|
# include "controllers/plugins/api/EventType.hpp"
|
||||||
# include "controllers/plugins/api/HTTPRequest.hpp"
|
# include "controllers/plugins/api/HTTPRequest.hpp"
|
||||||
# include "controllers/plugins/LuaUtilities.hpp"
|
# include "controllers/plugins/PluginMeta.hpp"
|
||||||
# include "controllers/plugins/PluginPermission.hpp"
|
|
||||||
|
|
||||||
# include <boost/signals2/signal.hpp>
|
# include <boost/signals2/signal.hpp>
|
||||||
# include <QDir>
|
# include <QDir>
|
||||||
@@ -32,45 +31,6 @@ enum class LogLevel;
|
|||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
struct PluginMeta {
|
|
||||||
// for more info on these fields see docs/plugin-info.schema.json
|
|
||||||
|
|
||||||
// display name of the plugin
|
|
||||||
QString name;
|
|
||||||
|
|
||||||
// description shown to the user
|
|
||||||
QString description;
|
|
||||||
|
|
||||||
// plugin authors shown to the user
|
|
||||||
std::vector<QString> authors;
|
|
||||||
|
|
||||||
// license name
|
|
||||||
QString license;
|
|
||||||
|
|
||||||
// version of the plugin
|
|
||||||
semver::version version;
|
|
||||||
|
|
||||||
// optionally a homepage link
|
|
||||||
QString homepage;
|
|
||||||
|
|
||||||
// optionally tags that might help in searching for the plugin
|
|
||||||
std::vector<QString> tags;
|
|
||||||
|
|
||||||
std::vector<PluginPermission> permissions;
|
|
||||||
|
|
||||||
// errors that occurred while parsing info.json
|
|
||||||
std::vector<QString> errors;
|
|
||||||
|
|
||||||
bool isValid() const
|
|
||||||
{
|
|
||||||
return this->errors.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit PluginMeta(const QJsonObject &obj);
|
|
||||||
// This is for tests
|
|
||||||
PluginMeta() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Plugin
|
class Plugin
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 Contributors to Chatterino <https://chatterino.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||||
|
# include "controllers/plugins/PluginMeta.hpp"
|
||||||
|
|
||||||
|
# include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
|
# include <QJsonArray>
|
||||||
|
# include <QJsonObject>
|
||||||
|
# include <QJsonValue>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
// NOLINTBEGIN(clazy-reserve-candidates)
|
||||||
|
PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
auto homepageObj = obj.value("homepage");
|
||||||
|
if (homepageObj.isString())
|
||||||
|
{
|
||||||
|
this->homepage = homepageObj.toString();
|
||||||
|
}
|
||||||
|
else if (!homepageObj.isUndefined())
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(homepageObj.type());
|
||||||
|
this->errors.emplace_back(
|
||||||
|
QString("homepage is defined but is not a string (its type is %1)")
|
||||||
|
.arg(type));
|
||||||
|
}
|
||||||
|
auto nameObj = obj.value("name");
|
||||||
|
if (nameObj.isString())
|
||||||
|
{
|
||||||
|
this->name = nameObj.toString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(nameObj.type());
|
||||||
|
this->errors.emplace_back(
|
||||||
|
QString("name is not a string (its type is %1)").arg(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto descrObj = obj.value("description");
|
||||||
|
if (descrObj.isString())
|
||||||
|
{
|
||||||
|
this->description = descrObj.toString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(descrObj.type());
|
||||||
|
this->errors.emplace_back(
|
||||||
|
QString("description is not a string (its type is %1)").arg(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto authorsObj = obj.value("authors");
|
||||||
|
if (authorsObj.isArray())
|
||||||
|
{
|
||||||
|
auto authorsArr = authorsObj.toArray();
|
||||||
|
for (int i = 0; i < authorsArr.size(); i++)
|
||||||
|
{
|
||||||
|
const auto &t = authorsArr.at(i);
|
||||||
|
if (!t.isString())
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(t.type());
|
||||||
|
this->errors.push_back(
|
||||||
|
QString("authors element #%1 is not a string (it is a %2)")
|
||||||
|
.arg(i)
|
||||||
|
.arg(type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->authors.push_back(t.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(authorsObj.type());
|
||||||
|
this->errors.emplace_back(
|
||||||
|
QString("authors is not an array (its type is %1)").arg(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto licenseObj = obj.value("license");
|
||||||
|
if (licenseObj.isString())
|
||||||
|
{
|
||||||
|
this->license = licenseObj.toString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(licenseObj.type());
|
||||||
|
this->errors.emplace_back(
|
||||||
|
QString("license is not a string (its type is %1)").arg(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto verObj = obj.value("version");
|
||||||
|
if (verObj.isString())
|
||||||
|
{
|
||||||
|
auto v = semver::from_string_noexcept(verObj.toString().toStdString());
|
||||||
|
if (v.has_value())
|
||||||
|
{
|
||||||
|
this->version = v.value();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->errors.emplace_back("unable to parse version (use semver)");
|
||||||
|
this->version = semver::version(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(verObj.type());
|
||||||
|
this->errors.emplace_back(
|
||||||
|
QString("version is not a string (its type is %1)").arg(type));
|
||||||
|
this->version = semver::version(0, 0, 0);
|
||||||
|
}
|
||||||
|
auto permsObj = obj.value("permissions");
|
||||||
|
if (!permsObj.isUndefined())
|
||||||
|
{
|
||||||
|
if (!permsObj.isArray())
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(permsObj.type());
|
||||||
|
this->errors.emplace_back(
|
||||||
|
QString("permissions is not an array (its type is %1)")
|
||||||
|
.arg(type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto permsArr = permsObj.toArray();
|
||||||
|
for (int i = 0; i < permsArr.size(); i++)
|
||||||
|
{
|
||||||
|
const auto &t = permsArr.at(i);
|
||||||
|
if (!t.isObject())
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(t.type());
|
||||||
|
this->errors.push_back(QString("permissions element #%1 is not "
|
||||||
|
"an object (its type is %2)")
|
||||||
|
.arg(i)
|
||||||
|
.arg(type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto parsed = PluginPermission(t.toObject());
|
||||||
|
if (parsed.isValid())
|
||||||
|
{
|
||||||
|
// ensure no invalid permissions slip through this
|
||||||
|
this->permissions.push_back(parsed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto &err : parsed.errors)
|
||||||
|
{
|
||||||
|
this->errors.push_back(
|
||||||
|
QString("permissions element #%1: %2").arg(i).arg(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tagsObj = obj.value("tags");
|
||||||
|
if (!tagsObj.isUndefined())
|
||||||
|
{
|
||||||
|
if (!tagsObj.isArray())
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(tagsObj.type());
|
||||||
|
this->errors.emplace_back(
|
||||||
|
QString("tags is not an array (its type is %1)").arg(type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tagsArr = tagsObj.toArray();
|
||||||
|
for (int i = 0; i < tagsArr.size(); i++)
|
||||||
|
{
|
||||||
|
const auto &t = tagsArr.at(i);
|
||||||
|
if (!t.isString())
|
||||||
|
{
|
||||||
|
auto type = qmagicenum::enumName(t.type());
|
||||||
|
this->errors.push_back(
|
||||||
|
QString("tags element #%1 is not a string (its type is %2)")
|
||||||
|
.arg(i)
|
||||||
|
.arg(type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->tags.push_back(t.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// NOLINTEND(clazy-reserve-candidates)
|
||||||
|
|
||||||
|
} // namespace chatterino
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 Contributors to Chatterino <https://chatterino.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||||
|
# include "controllers/plugins/PluginPermission.hpp"
|
||||||
|
|
||||||
|
# include <QJsonObject>
|
||||||
|
# include <QString>
|
||||||
|
# include <semver/semver.hpp>
|
||||||
|
|
||||||
|
# include <vector>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
struct PluginMeta {
|
||||||
|
// for more info on these fields see docs/plugin-info.schema.json
|
||||||
|
|
||||||
|
// display name of the plugin
|
||||||
|
QString name;
|
||||||
|
|
||||||
|
// description shown to the user
|
||||||
|
QString description;
|
||||||
|
|
||||||
|
// plugin authors shown to the user
|
||||||
|
std::vector<QString> authors;
|
||||||
|
|
||||||
|
// license name
|
||||||
|
QString license;
|
||||||
|
|
||||||
|
// version of the plugin
|
||||||
|
semver::version version;
|
||||||
|
|
||||||
|
// optionally a homepage link
|
||||||
|
QString homepage;
|
||||||
|
|
||||||
|
// optionally tags that might help in searching for the plugin
|
||||||
|
std::vector<QString> tags;
|
||||||
|
|
||||||
|
std::vector<PluginPermission> permissions;
|
||||||
|
|
||||||
|
// errors that occurred while parsing info.json
|
||||||
|
std::vector<QString> errors;
|
||||||
|
|
||||||
|
bool isValid() const
|
||||||
|
{
|
||||||
|
return this->errors.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit PluginMeta(const QJsonObject &obj);
|
||||||
|
// This is for tests
|
||||||
|
PluginMeta() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user