MythTV master
mythhttpmetaservice.cpp
Go to the documentation of this file.
1// C++
2#include <algorithm>
3
4// Qt
5#include <QChar> // Fix Qt6 GCC SFINAE warning
6#include <QMetaClassInfo>
7
8// MythTV
9#include "mythlogging.h"
11#include "http/mythhttptypes.h"
12
20MythHTTPMetaService::MythHTTPMetaService(const QString& Name, const QMetaObject& Meta,
22 const QString& MethodsToHide)
23 : m_meta(Meta),
24 m_name(Name)
25{
26 // Register any types
27 if (RegisterCallback != nullptr)
28 std::invoke(RegisterCallback);
29
30 // Static list of signals and slots to avoid
31 static QString s_defaultHide = { "destroyed,deleteLater,objectNameChanged,RegisterCustomTypes" };
32
33 // Retrieve version
34 auto index = Meta.indexOfClassInfo("Version");
35 if (index > -1)
36 m_version = Meta.classInfo(index).value();
37 else
38 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral("Service '%1' is missing version information").arg(Name));
39
40 // Build complete list of meta objects for class hierarchy
41 QList<const QMetaObject*> metas;
42 metas.append(&Meta);
43 const QMetaObject* super = Meta.superClass();
44 while (super)
45 {
46 metas.append(super);
47 super = super->superClass();
48 }
49
50 QString hide = s_defaultHide + MethodsToHide;
51
52 // Pull out public signals and slots, ignoring 'MethodsToHide'
53 for (const auto * meta : metas)
54 {
55 for (int i = 0; i < meta->methodCount(); ++i)
56 {
57 QMetaMethod method = meta->method(i);
58
59 // We want only public methods
60 if (QMetaMethod::Public != method.access())
61 continue;
62
63 // Filtered unwanted
64 QString name(method.methodSignature());
65 name = name.section('(', 0, 0);
66 if (hide.contains(name))
67 continue;
68
69 auto RemoveExisting = [](HTTPMethods& Methods, const HTTPMethodPtr& Method, const QString& Search)
70 {
71 for (const auto & [_name, _method] : Methods)
72 {
73 if ((_name == Search) && (_method->m_method.methodSignature() == Method->m_method.methodSignature()) &&
74 (_method->m_method.returnType() == Method->m_method.returnType()))
75 {
76 Methods.erase(_name);
77 break;
78 }
79 }
80 };
81
82 // Signals
83 if (QMetaMethod::Signal == method.methodType())
84 {
85 auto newmethod = MythHTTPMetaMethod::Create(i, method, HTTPUnknown, {}, false);
86 if (newmethod)
87 {
88 RemoveExisting(m_signals, newmethod, name);
89 m_signals.emplace(name, newmethod);
90 }
91 }
92 // Slots
93 else if (QMetaMethod::Slot == method.methodType())
94 {
95 QString returnname;
96 int types = ParseRequestTypes(Meta, name, returnname);
97 if (types != HTTPUnknown)
98 {
99 auto newmethod = MythHTTPMetaMethod::Create(i, method, types, returnname);
100 if (newmethod)
101 {
102 newmethod->m_protected = isProtected(Meta, name);
103 RemoveExisting(m_slots, newmethod, name);
104 m_slots.emplace(name, newmethod);
105 }
106 }
107 }
108 }
109 }
110
111 int constpropertyindex = -1;
112 for (const auto * meta : metas)
113 {
114 for (int i = meta->propertyOffset(); i < meta->propertyCount(); ++i)
115 {
116 QMetaProperty property = meta->property(i);
117 QString propertyname(property.name());
118
119 if (propertyname != QString("objectName") && property.isReadable() &&
120 ((property.hasNotifySignal() && property.notifySignalIndex() > -1) || property.isConstant()))
121 {
122 // constant properties are given a signal index < 0
123 if (property.notifySignalIndex() > -1)
124 m_properties.emplace(property.notifySignalIndex(), property.propertyIndex());
125 else
126 m_properties.emplace(constpropertyindex--, property.propertyIndex());
127 }
128 }
129 }
130 LOG(VB_GENERAL, LOG_INFO, QString("Service '%1' introspection complete").arg(Name));
131}
132
133int MythHTTPMetaService::ParseRequestTypes(const QMetaObject& Meta, const QString& Method, QString& ReturnName)
134{
135 int custom = HTTPUnknown;
136 int index = Meta.indexOfClassInfo(Method.toLatin1().constData());
137 if (index > -1)
138 {
139 QStringList infos = QString(Meta.classInfo(index).value()).split(';', Qt::SkipEmptyParts);
140 for (const QString &info : std::as_const(infos))
141 {
142 if (info.startsWith(QStringLiteral("methods=")))
143 custom |= MythHTTP::RequestsFromString(info.mid(8));
144 if (info.startsWith(QStringLiteral("name=")))
145 ReturnName = info.mid(5).trimmed();
146 }
147 }
148
149 // determine allowed request types
150 int allowed = HTTPOptions;
151 if (custom != HTTPUnknown)
152 {
153 allowed |= custom;
154 }
155 else if (Method.startsWith(QStringLiteral("Get"), Qt::CaseInsensitive))
156 {
157 allowed |= HTTPGet | HTTPHead | HTTPPost;
158 }
159 else if (Method.startsWith(QStringLiteral("Set"), Qt::CaseInsensitive))
160 {
161 // Put or Post?
162 allowed |= HTTPPost;
163 }
164 else
165 {
166 LOG(VB_GENERAL, LOG_ERR, QString("Failed to get request types for method '%1'- ignoring").arg(Method));
167 return HTTPUnknown;
168 }
169 return allowed;
170}
171
172bool MythHTTPMetaService::isProtected(const QMetaObject& Meta, const QString& Method)
173{
174 int index = Meta.indexOfClassInfo(Method.toLatin1().constData());
175 if (index > -1)
176 {
177 QStringList infos = QString(Meta.classInfo(index).value()).split(';', Qt::SkipEmptyParts);
178 auto isAuth = [](const QString& info)
179 { return info.startsWith(QStringLiteral("AuthRequired=")); };
180 return std::ranges::any_of(std::as_const(infos), isAuth);
181 }
182 return false;
183}
#define RegisterCallback(a, b, c)
static HTTPMethodPtr Create(int Index, QMetaMethod &Method, int RequestTypes, const QString &ReturnName={}, bool Slot=true)
MythHTTPMetaService(const QString &Name, const QMetaObject &Meta, const HTTPRegisterTypes &RegisterCallback=nullptr, const QString &MethodsToHide={})
static int ParseRequestTypes(const QMetaObject &Meta, const QString &Method, QString &ReturnName)
HTTPProperties m_properties
static bool isProtected(const QMetaObject &Meta, const QString &Method)
static int RequestsFromString(const QString &Requests)
static const struct wl_interface * types[]
std::map< QString, HTTPMethodPtr > HTTPMethods
std::shared_ptr< MythHTTPMetaMethod > HTTPMethodPtr
@ HTTPGet
Definition: mythhttptypes.h:94
@ HTTPUnknown
Definition: mythhttptypes.h:92
@ HTTPHead
Definition: mythhttptypes.h:93
@ HTTPPost
Definition: mythhttptypes.h:95
@ HTTPOptions
Definition: mythhttptypes.h:98
std::function< void()> HTTPRegisterTypes
Definition: mythhttptypes.h:50
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
dictionary info
Definition: azlyrics.py:7