summaryrefslogtreecommitdiffstats
path: root/src/remoteobjects/qremoteobjectnode.h
blob: 13e2540f6a75a23f69dab6d331d125ae7adda020 (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
// Copyright (C) 2017 Ford Motor Company
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#ifndef QREMOTEOBJECTNODE_H
#define QREMOTEOBJECTNODE_H

#include <QtCore/qsharedpointer.h>
#include <QtCore/qmetaobject.h>
#include <QtNetwork/qlocalserver.h>
#include <QtRemoteObjects/qtremoteobjectglobal.h>
#include <QtRemoteObjects/qremoteobjectregistry.h>
#include <QtRemoteObjects/qremoteobjectdynamicreplica.h>

#include <functional>

QT_BEGIN_NAMESPACE

class QRemoteObjectReplica;
class SourceApiMap;
class QAbstractItemModel;
class QAbstractItemModelReplica;
class QItemSelectionModel;
class QRemoteObjectAbstractPersistedStorePrivate;
class QRemoteObjectNodePrivate;
class QRemoteObjectHostBasePrivate;
class QRemoteObjectHostPrivate;
class QRemoteObjectRegistryHostPrivate;

class Q_REMOTEOBJECTS_EXPORT QRemoteObjectAbstractPersistedStore : public QObject
{
    Q_OBJECT

public:
    QRemoteObjectAbstractPersistedStore (QObject *parent = nullptr);
    virtual ~QRemoteObjectAbstractPersistedStore();

    virtual void saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values) = 0;
    virtual QVariantList restoreProperties(const QString &repName, const QByteArray &repSig) = 0;

protected:
    QRemoteObjectAbstractPersistedStore(QRemoteObjectAbstractPersistedStorePrivate &, QObject *parent);
    Q_DECLARE_PRIVATE(QRemoteObjectAbstractPersistedStore)
};

class Q_REMOTEOBJECTS_EXPORT QRemoteObjectNode : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QUrl registryUrl READ registryUrl WRITE setRegistryUrl)
    Q_PROPERTY(QRemoteObjectAbstractPersistedStore* persistedStore READ persistedStore WRITE setPersistedStore)
    Q_PROPERTY(int heartbeatInterval READ heartbeatInterval WRITE setHeartbeatInterval NOTIFY heartbeatIntervalChanged)

public:
    enum ErrorCode{
        NoError,
        RegistryNotAcquired,
        RegistryAlreadyHosted,
        NodeIsNoServer,
        ServerAlreadyCreated,
        UnintendedRegistryHosting,
        OperationNotValidOnClientNode,
        SourceNotRegistered,
        MissingObjectName,
        HostUrlInvalid,
        ProtocolMismatch,
        ListenFailed,
        SocketAccessError
    };
    Q_ENUM(ErrorCode)

    QRemoteObjectNode(QObject *parent = nullptr);
    QRemoteObjectNode(const QUrl &registryAddress, QObject *parent = nullptr);
    ~QRemoteObjectNode() override;

    Q_INVOKABLE bool connectToNode(const QUrl &address);
    void addClientSideConnection(QIODevice *ioDevice);
    virtual void setName(const QString &name);
    template < class ObjectType >
    ObjectType *acquire(const QString &name = QString())
    {
        return new ObjectType(this, name);
    }

    template<typename T>
    QStringList instances() const
    {
        const QMetaObject *mobj = &T::staticMetaObject;
        const int index = mobj->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
        if (index == -1)
            return QStringList();

        const QString typeName = QString::fromLatin1(mobj->classInfo(index).value());
        return instances(typeName);
    }
    QStringList instances(QStringView typeName) const;

    QRemoteObjectDynamicReplica *acquireDynamic(const QString &name);
    QAbstractItemModelReplica *acquireModel(const QString &name, QtRemoteObjects::InitialAction action = QtRemoteObjects::FetchRootSize, const QList<int> &rolesHint = {});
    QUrl registryUrl() const;
    virtual bool setRegistryUrl(const QUrl &registryAddress);
    bool waitForRegistry(int timeout = 30000);
    const QRemoteObjectRegistry *registry() const;

    QRemoteObjectAbstractPersistedStore *persistedStore() const;
    void setPersistedStore(QRemoteObjectAbstractPersistedStore *persistedStore);

    ErrorCode lastError() const;

    int heartbeatInterval() const;
    void setHeartbeatInterval(int interval);

    typedef std::function<void (QUrl)> RemoteObjectSchemaHandler;
    void registerExternalSchema(const QString &schema, RemoteObjectSchemaHandler handler);

Q_SIGNALS:
    void remoteObjectAdded(const QRemoteObjectSourceLocation &);
    void remoteObjectRemoved(const QRemoteObjectSourceLocation &);

    void error(QRemoteObjectNode::ErrorCode errorCode);
    void heartbeatIntervalChanged(int heartbeatInterval);

protected:
    QRemoteObjectNode(QRemoteObjectNodePrivate &, QObject *parent);

    void timerEvent(QTimerEvent*) override;

private:
    void initializeReplica(QRemoteObjectReplica *instance, const QString &name = QString());
    void persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props);
    QVariantList retrieveProperties(const QString &repName, const QByteArray &repSig);

    Q_DECLARE_PRIVATE(QRemoteObjectNode)
    friend class QRemoteObjectReplica;
    friend class QConnectedReplicaImplementation;
};

class Q_REMOTEOBJECTS_EXPORT QRemoteObjectHostBase : public QRemoteObjectNode
{
    Q_OBJECT
public:
    enum AllowedSchemas { BuiltInSchemasOnly, AllowExternalRegistration };
    Q_ENUM(AllowedSchemas)
    ~QRemoteObjectHostBase() override;
    void setName(const QString &name) override;

    template <template <typename> class ApiDefinition, typename ObjectType>
    bool enableRemoting(ObjectType *object)
    {
        ApiDefinition<ObjectType> *api = new ApiDefinition<ObjectType>(object);
        return enableRemoting(object, api);
    }
    Q_INVOKABLE bool enableRemoting(QObject *object, const QString &name = QString());
    bool enableRemoting(QAbstractItemModel *model, const QString &name, const QList<int> roles, QItemSelectionModel *selectionModel = nullptr);
    Q_INVOKABLE bool disableRemoting(QObject *remoteObject);
    void addHostSideConnection(QIODevice *ioDevice);

    typedef std::function<bool(QStringView, QStringView)> RemoteObjectNameFilter;
    bool proxy(const QUrl &registryUrl, const QUrl &hostUrl={},
               RemoteObjectNameFilter filter=[](QStringView, QStringView) {return true; });
    // TODO: Currently the reverse aspect requires the registry, so this is supported only for
    // QRemoteObjectRegistryHost for now. Consider enabling it also for QRemoteObjectHost.
    bool reverseProxy(RemoteObjectNameFilter filter=[](QStringView, QStringView) {return true; });

protected:
    virtual QUrl hostUrl() const;
    virtual bool setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas=BuiltInSchemasOnly);
    QRemoteObjectHostBase(QRemoteObjectHostBasePrivate &, QObject *);

private:
    bool enableRemoting(QObject *object, const SourceApiMap *, QObject *adapter = nullptr);
    Q_DECLARE_PRIVATE(QRemoteObjectHostBase)
};

class Q_REMOTEOBJECTS_EXPORT QRemoteObjectHost : public QRemoteObjectHostBase
{
    Q_OBJECT
    Q_PROPERTY(QUrl hostUrl READ hostUrl WRITE setHostUrl NOTIFY hostUrlChanged)

public:
    QRemoteObjectHost(QObject *parent = nullptr);
    QRemoteObjectHost(const QUrl &address, const QUrl &registryAddress = QUrl(),
                      AllowedSchemas allowedSchemas=BuiltInSchemasOnly, QObject *parent = nullptr);
    QRemoteObjectHost(const QUrl &address, QObject *parent);
    ~QRemoteObjectHost() override;
    QUrl hostUrl() const override;
    bool setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas=BuiltInSchemasOnly) override;
    static void setLocalServerOptions(QLocalServer::SocketOptions options);

Q_SIGNALS:
    void hostUrlChanged();

protected:
    QRemoteObjectHost(QRemoteObjectHostPrivate &, QObject *);

private:
    Q_DECLARE_PRIVATE(QRemoteObjectHost)
};

class Q_REMOTEOBJECTS_EXPORT QRemoteObjectRegistryHost : public QRemoteObjectHostBase
{
    Q_OBJECT
public:
    QRemoteObjectRegistryHost(const QUrl &registryAddress = QUrl(), QObject *parent = nullptr);
    ~QRemoteObjectRegistryHost() override;
    bool setRegistryUrl(const QUrl &registryUrl) override;

protected:
    QRemoteObjectRegistryHost(QRemoteObjectRegistryHostPrivate &, QObject *);

private:
    Q_DECLARE_PRIVATE(QRemoteObjectRegistryHost)
};

QT_END_NAMESPACE

#endif