summaryrefslogtreecommitdiffstats
path: root/src/helper/remoteobjects/qifremoteobjectsconfig.cpp
blob: af477a3675a1b114a846c701b4cd7a60ab6a5519 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "qifremoteobjectsconfig.h"

#include <QtIfRemoteObjectsHelper/qifremoteobjectshelper.h>

using namespace Qt::StringLiterals;

QT_BEGIN_NAMESPACE

#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0)
#  define Q_STATIC_LOGGING_CATEGORY(cat, rule, init) Q_LOGGING_CATEGORY(cat, rule, init)
#endif

Q_STATIC_LOGGING_CATEGORY(qLcQtIfRoConfig, "qt.if.remoteobjects.config",
                          QtInfoMsg)

/*!
    \class QIfRemoteObjectsConfig
    \inmodule QtIfRemoteObjectsHelper
    \brief The QIfRemoteObjectsConfig helps to maintain config options for remote object based
    servers.

    The QIfRemoteObjectsConfig class can used to retrieve a correctly configured QRemoteObjectHost
    for the provided interface.

    In the simplest form it can be used like this in your main.cpp:
    \code
    #include <QCoreApplication>

    #include "myapi.h"
    #include "core.h"

    #include <QIfRemoteObjectsConfig>

    using namespace Qt::StringLiterals;

    int main(int argc, char *argv[])
    {
        QCoreApplication app(argc, argv);

        QIfRemoteObjectsConfig config;

        MyApi service;
        config.enableRemoting(u"Example.If.RemoteModule"_s, "MyApi"_s, &service);

        return app.exec();
    }
    \endcode

    This will make the service accessible using the default url build from the module parameter.
    In this case: \e local://RemoteModule

    \section1 Manage Remoting URLs

    Usually multiple interfaces are defined within a module and by using the default urls those
    services are always served by a single module URL using a local socket.

    To change the URL of all services a default server can be set using the \l setDefaultServerUrl()
    function.

    For more flexibility, a config file can be provided using the \l parseConfigFile function. This
    allows to set the used URL on interface or module level. Defining module URLs allows the same
    config file to be reused by multiple servers where each server hosts all interfaces of a single
    module.

    \section1 Legacy Config support

    Until 6.7 the autogenerated code of a QtRemoteObject based server used a file called
    "server.conf" in the current directory to read the URLs used for remoting a service.

    Reading this config file can be enabled by using the \l parseLegacyConfigFile() function.

    See also the \l{config_server_qtro_useGeneratedMain}{useGeneratedMain QFace Annotation} to let
    \l ifcodegen generate a main.cpp with fully setup QIfRemoteObjectsConfig.
*/


/*!
    Sets the \a defaultServerUrl, which will be used for all services which don't have a server set
    either for the interface or the module inside a config file.
*/
void QIfRemoteObjectsConfig::setDefaultServerUrl(const QUrl &defaultServerUrl)
{
    m_defaultServer = defaultServerUrl;
}

/*!
    Parses the config file at \a confFilePath and uses the stored module and interface specific
    urls when requested by \l host().

    \sa host()
*/
void QIfRemoteObjectsConfig::parseConfigFile(const QString &confFilePath)
{
    m_settings.reset(new QSettings(confFilePath, QSettings::IniFormat));
}

/*!
    Parses the legacy \e "server.conf" file in the current directory or at the location set
    by the \e SERVER_CONF_PATH environment variable.
*/
void QIfRemoteObjectsConfig::parseLegacyConfigFile()
{
    QString configPath(u"./server.conf"_s);
    if (qEnvironmentVariableIsSet("SERVER_CONF_PATH")) {
        qCDebug(qLcQtIfRoConfig) << "Environment variable SERVER_CONF_PATH defined." << configPath;
        configPath = QString::fromLocal8Bit(qgetenv("SERVER_CONF_PATH"));
    }
    qCDebug(qLcQtIfRoConfig) << "Parsing local server.conf file:" << QDir::current().absoluteFilePath(configPath);
    m_settings.reset(new QSettings(configPath, QSettings::IniFormat));
}

/*!
    Enables logging of all errors reported by the created QRemoteObjectHost instances on stderr.

    Setting \a enabled to \c false disables the logging.

    \sa reportErrorsOnStdErr
*/
void QIfRemoteObjectsConfig::setReportErrorsOnStdErr(bool enabled)
{
    m_reportErrorsOnStdErr = enabled;
}

/*!
    Returns \c true, if error logging to stderr for the created QRemoteObjectHost instances is
    enabled. Defaults to \c true.
*/
bool QIfRemoteObjectsConfig::reportErrorsOnStdErr() const
{
    return m_reportErrorsOnStdErr;
}

/*!
    Returns a QRemoteObjectHost with a preconfigured url.

    The url is specific to the provided \a module and \a interface arguments and can be modified
    using the \l setDefaultServerUrl() function or by using one of the config files.

    If multiple values are configured the urls are resolved in the following order:
    \list numbered
        \li interface
        \li module
        \li legacy \e Registry key
        \li defaultServer
        \li \a fallbackUrl argument
    \endlist

    If none of these settings have been configured, or invalid urls were passed, a default url is
    built using the \a module argument.

    \sa host
*/
QRemoteObjectHost *QIfRemoteObjectsConfig::host(const QString &module, const QString &interface, const QUrl &fallbackUrl)
{
    QUrl url;
    if (m_settings) {
        m_settings->beginGroup(module + u"/" + interface);
        url = m_settings->value(u"connectionUrl").toUrl();
        m_settings->endGroup();
        if (url.isValid())
            return host(url);

        m_settings->beginGroup(module);
        url = m_settings->value(u"connectionUrl").toUrl();
        m_settings->endGroup();
        if (url.isValid())
            return host(url);

        // Debug registry is deprecated please use the serverUrl instead.
        if (m_settings->contains(u"Registry")) {
            qCInfo(qLcQtIfRoConfig) << "Using the 'Registry' key is deprecated and will be removed"
                                       "in future Qt versions.";
            qCInfo(qLcQtIfRoConfig) << "Please use the 'connectionUrl' key instead."
                                       "This can be set per module or per interface in the conf file.";
            url = m_settings->value(u"Registry").toUrl();
        }
        if (url.isValid())
            return host(url);

    }

    // No settings for the interface/module were provided
    // Use the defaultServer if that is set
    if (m_defaultServer.isValid())
        return host(m_defaultServer);

    // If valid use fallback URL
    if (fallbackUrl.isValid())
        return host(fallbackUrl);

    // Create default url (using localsockets) for the module
    return host(QUrl(QIfRemoteObjectsHelper::buildDefaultUrl(module.split(u'.').last().toLower())));
}

/*!
    Returns a QRemoteObjectHost with a preconfigured \a url.

    \sa host
*/
QRemoteObjectHost *QIfRemoteObjectsConfig::host(const QUrl &url)
{
    if (m_hostHash.contains(url))
        return m_hostHash.value(url);

    auto host = new QRemoteObjectHost(url);
    m_hostHash.insert(url, host);
    qCDebug(qLcQtIfRoConfig) << "Listening on" << url;
    host->connect(host, &QRemoteObjectNode::error, host, [this](QRemoteObjectNode::ErrorCode code) {
        // No logging category on purpose, this is not related to the config class
        if (m_reportErrorsOnStdErr)
            qWarning() << "QRemoteObjects Error: " << code;
    });
    return host;
}

/*!
    Enables remoting of the passed \a object using a QRemoteObjectHost instance
    with a preconfigured url.

    Returns \c true if remoting is successfully enabled for the passed \a object.

    See host() for more information on how \a module, \a interface and \a fallbackUrl influence
    the effective url.

    \sa enableRemoting
*/
bool QIfRemoteObjectsConfig::enableRemoting(const QString &module, const QString &interface, const QUrl &fallbackUrl, QObject *object)
{
    return host(module, interface, fallbackUrl)->enableRemoting(object, module + u"."_s + interface);
}

/*!
    Enables remoting of the passed \a object using a QRemoteObjectHost instance
    with a preconfigured url.

    Returns \c true if remoting is successfully enabled for the passed \a object.

    See host() for more information on how \a module and \a interface influence the effective url.

    \sa enableRemoting
*/
bool QIfRemoteObjectsConfig::enableRemoting(const QString &module, const QString &interface, QObject *object)
{
    return enableRemoting(module, interface, QString(), object);
}

QT_END_NAMESPACE

#include "moc_qifremoteobjectsconfig.cpp"