1 /*
2  * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12  * for more details.
13  */
14 
15 #pragma once
16 
17 #include <QWebSocket>
18 #include <QTimer>
19 
20 #include "capabilities.h"
21 
22 namespace OCC {
23 
24 class Account;
25 class AbstractCredentials;
26 
27 class OWNCLOUDSYNC_EXPORT PushNotifications : public QObject
28 {
29     Q_OBJECT
30 
31 public:
32     explicit PushNotifications(Account *account, QObject *parent = nullptr);
33 
34     ~PushNotifications() override;
35 
36     /**
37      * Setup push notifications
38      *
39      * This method needs to be called before push notifications can be used.
40      */
41     void setup();
42 
43     /**
44      * Set the interval for reconnection attempts
45      *
46      * @param interval Interval in milliseconds.
47      */
48     void setReconnectTimerInterval(uint32_t interval);
49 
50     /**
51      * Indicates if push notifications ready to use
52      *
53      * Ready to use means connected and authenticated.
54      */
55     bool isReady() const;
56 
57     /**
58      * Set the interval in which the websocket will ping the server if it is still alive.
59      *
60      * If the websocket does not respond in timeoutInterval, the connection will be terminated.
61      *
62      * @param interval Interval in milliseconds.
63      */
64     void setPingInterval(int interval);
65 
66 signals:
67     /**
68      * Will be emitted after a successful connection and authentication
69      */
70     void ready();
71 
72     /**
73      * Will be emitted if files on the server changed
74      */
75     void filesChanged(Account *account);
76 
77     /**
78      * Will be emitted if activities have been changed on the server
79      */
80     void activitiesChanged(Account *account);
81 
82     /**
83      * Will be emitted if notifications have been changed on the server
84      */
85     void notificationsChanged(Account *account);
86 
87     /**
88      * Will be emitted if push notifications are unable to authenticate
89      *
90      * It's save to call #PushNotifications::setup() after this signal has been emitted.
91      */
92     void authenticationFailed();
93 
94     /**
95      * Will be emitted if push notifications are unable to connect or the connection timed out
96      *
97      * It's save to call #PushNotifications::setup() after this signal has been emitted.
98      */
99     void connectionLost();
100 
101 private slots:
102     void onWebSocketConnected();
103     void onWebSocketDisconnected();
104     void onWebSocketTextMessageReceived(const QString &message);
105     void onWebSocketError(QAbstractSocket::SocketError error);
106     void onWebSocketSslErrors(const QList<QSslError> &errors);
107     void onWebSocketPongReceived(quint64 elapsedTime, const QByteArray &payload);
108     void onPingTimedOut();
109 
110 private:
111     void openWebSocket();
112     void reconnectToWebSocket();
113     void closeWebSocket();
114     void authenticateOnWebSocket();
115     bool tryReconnectToWebSocket();
116     void initReconnectTimer();
117     void pingWebSocketServer();
118     void startPingTimer();
119     void startPingTimedOutTimer();
120 
121     void handleAuthenticated();
122     void handleNotifyFile();
123     void handleInvalidCredentials();
124     void handleNotifyNotification();
125     void handleNotifyActivity();
126 
127     void emitFilesChanged();
128     void emitNotificationsChanged();
129     void emitActivitiesChanged();
130 
131     Account *_account = nullptr;
132     QWebSocket *_webSocket;
133     uint8_t _failedAuthenticationAttemptsCount = 0;
134     QTimer *_reconnectTimer = nullptr;
135     uint32_t _reconnectTimerInterval = 20 * 1000;
136     bool _isReady = false;
137 
138     QTimer _pingTimer;
139     QTimer _pingTimedOutTimer;
140     bool _pongReceivedFromWebSocketServer = false;
141 };
142 }
143