Remoto - VFS: VFS_websocket_client.cpp Source File
Remoto - VFS
VFS_websocket_client.cpp
Go to the documentation of this file.
1 
2 #include "VFS_websocket_client.h"
3 #include "VFS_websocket_server.h"
4 
5 #include "VFS.h"
6 
7 #include <QTimerEvent>
8 
24 : VFS_node()
25 , _socket(socket)
26 , _server(server)
27 , _authenticated(false)
28 , _authorized(false)
29 , _pingID(-1)
30 , _isClient(false)
31 , _connectID(-1)
32 , _interval(3000)
33 {
34  init();
35 }
36 
42 VFS_websocket_client::VFS_websocket_client(QString wsurl, quint16 interval)
43 : VFS_node()
44 , _socket(0)
45 , _server(0)
46 , _authenticated(false)
47 , _authorized(false)
48 , _pingID(-1)
49 , _isClient(true)
50 , _connectID(-1)
51 , _wsurl(wsurl)
52 , _interval(interval)
53 {
54  _socket = new QWebSocket();
55  _socket->setParent(this);
56 
57  init();
58 
59  VFS::LOG( QString("%1 attempting connection to %2...").arg(className()).arg(_wsurl) );
60  _socket->open(_wsurl);
61 }
62 
68 {
69  _address = _socket->peerAddress();
70  //_hwaddress =
71  //_port = _socket->peerPort();
72 
73  if (_isClient)
74  {
75  //this is for auto-reconnect
76  connect( _socket, SIGNAL( connected() ),
77  this, SLOT( socket_connected() ) );
78 
79  connect( _socket, SIGNAL( textMessageReceived(QString) ),
80  this, SLOT( socket_receive_text(QString) ) );
81 
82  connect( _socket, SIGNAL( binaryMessageReceived(QByteArray) ),
83  this, SLOT( socket_receive_binary(QByteArray) ) );
84  }
85  else
86  {
87  if (!_socket->isValid())
88  printf("WARNING! socket is invalid?\n");
89  }
90 
91  connect( _socket, SIGNAL( disconnected() ),
92  this, SLOT( socket_disconnected() ) );
93 
94  connect( _socket, SIGNAL( textMessageReceived(QString) ),
95  SIGNAL( readyTextMessage(QString)) );
96 
97  connect( _socket, SIGNAL( binaryMessageReceived(QByteArray) ),
98  SIGNAL( readyBinaryMessage(QByteArray)) );
99 
100  connect( _socket, SIGNAL( error(QAbstractSocket::SocketError) ),
101  this, SIGNAL( error(QAbstractSocket::SocketError) ) );
102 
103  connect(this,SIGNAL(mounted()),this,SLOT(startPing()));
104  connect(this,SIGNAL(unmounted(VFS_node*)),this,SLOT(close()));
105 }
106 
114 {
115  //QMutexLocker l(&_lock);
116 
117  close();
118 
119  if (_socket)
120  _socket->deleteLater();
121  //delete _socket;
122 }
123 
138 {
139  QHostAddress a = _socket->peerAddress();
140  QString name = _server->uniqueChildName(a.toString());
141  _server->append(name,this,false); //disregard container-ness of the _server, and just add clients. This is useful for presenting menus.
142 }
143 
152 {
153  if (_pingID != -1)
154  killTimer(_pingID);
155 
156  _pingID = startTimer(1000*20); //every 20 seconds... just in case we're behind a proxy of some kind
157 }
158 
166 {
167  //QMutexLocker l(&_lock);
168 
169  int id = e->timerId();
170 
171  if (id == _pingID)
172  {
173  if (_socket->isValid())
174  _socket->ping(); //keep the connection open
175  }
176 
177  if (id == _connectID)
178  {
179  if (_isClient)
180  { VFS::LOG( QString("%1 attempting connection to %2...").arg(className()).arg(_wsurl) );
181  _socket->open(_wsurl); //attempt a connection
182  }
183  }
184 }
185 
191 {
192  VFS::LOG( QString("%1 connected to %2").arg(className()).arg(_wsurl), 2 );
193 
194  startPing();
195  _address = _socket->peerAddress();
196 
197  //printf("CONNECTED! KILL TIMER!\n");
198  if (_connectID != -1)
199  { killTimer(_connectID);
200  _connectID = -1;
201  }
202 
203  emit connected();
204 }
205 
211 {
212  emit disconnected();
213 
214  //printf("DISCONNECTED! START TIMER!\n");
215  if (_isClient && _connectID == -1)
216  { VFS::WARN( QString("Socket disconnected... will attempt to reconnect."), 8, className() );
217  _connectID = startTimer(_interval);
218  }
219 }
220 
227 {
228  return _connectID != -1;
229 }
230 
237 {
238  return _socket->isValid();
239 }
240 
247 {
248  receive( message.toUtf8() );
249 }
250 
257 {
258  receive( message );
259 }
260 
266 {
267  if (_socket && _socket->isValid())
268  _socket->close();
269 }
270 
279 {
280  VFS::ERROR( QString("Cannot write to '%1:%2' node. Create a subclass?" ).arg(className()).arg(r->_path) );
281 }
282 
291 {
292  VFS::ERROR( QString("Cannot submit to '%1:%2' node. Create a subclass?" ).arg(className()).arg(r->_path) );
293 }
294 
304 {
305  qint64 w = _socket->sendTextMessage(data);
306 
307  if (false) //FIXME: websockets often misreport bytes written... a documented bug in Qt5.6-5.7
308  if (w!=data.length())
309  { VFS::ERROR( QString("Could not write all data to websocket! (%1/%2)").arg(w).arg(data.length()) );
310  //printf("Tried to write %lld bytes, but only %d made it.\n",w,data.length());
311  printf("%s",qUtf8Printable(data));
312  return false;
313  }
314  return true;
315 }
316 
326 {
327  qint64 w = _socket->sendBinaryMessage(data);
328 
329  if (w!=data.length())
330  { VFS::ERROR( QString("Could not write all binary data to websocket! (%1/%2)").arg(w).arg(data.length()) );
331  return false;
332  }
333  return true;
334 }
335 
342 {
343  return false;
344 }
345 
351 QJsonDocument VFS_websocket_client::receive(QByteArray message)
352 {
353  QJsonParseError e;
354  QJsonDocument d = QJsonDocument::fromJson(message, &e);
355  if (e.error != QJsonParseError::NoError)
356  {
357  VFS::ERROR( QString("Unparseable command received from %1: %2\n%3").arg(_address.toString()).arg(e.errorString()).arg(QString(message)), 0 );
358  close();
359  return QJsonDocument();
360  }
361 
362  return d;
363 }
VFS_node is the base class from which all other VFS_node classes derive.
Definition: VFS_node.h:143
virtual VFS_node * append(QString name, VFS_node *node, bool containerCheck=true, QString user="server")
Append a VFS_node as a child of this node.
Definition: VFS_node.cpp:1566
QString uniqueChildName(QString name)
Generate a unique child name.
Definition: VFS_node.cpp:2054
void mounted()
Emitted when a node is mount()ed.
void unmounted(VFS_node *self)
Emitted when a node is unmount()ed.
QString className()
Return the class name of a node.
Definition: VFS_node.cpp:2039
The base class for all requests between nodes.
Definition: VFS_node.h:54
QString _path
the target path remnant... the remaining path element once the request has found its target
Definition: VFS_node.h:95
virtual bool isConnecting()
If the client will attempt to reconnect, return true.
bool _isClient
A client connection may not be created by a listening server, thus the second constructor.
virtual void submit(VFS_request *r)
Submit to the socket.
int _pingID
Connections can become stale; This is the ID of the ping timer.
VFS_websocket_client(QWebSocket *socket, VFS_websocket_server *server)
QString _wsurl
For client connections, the WebSocket address to connect to.
QHostAddress _address
The network address of the connected client.
quint16 _interval
The reconnect interval if disconnected.
virtual void authorized()
Notify the node that it has received authorization from some auth method.
void connected()
Connection has been made.
virtual void write(VFS_request *r)
Write to the socket.
virtual void socket_receive_text(QString message)
The socket has received a message in text mode.
void readyTextMessage(QString message)
A text message has been received.
virtual void socket_connected()
Slot called when the client is connected.
int _connectID
For client connections, the reconnect timerID.
virtual void socket_disconnected()
Slot called when the client is disconnected.
virtual ~VFS_websocket_client()
VFS_websocket_client destructor -.
VFS_websocket_server * _server
owning server
virtual void timerEvent(QTimerEvent *event)
Send the ping command.
void readyBinaryMessage(QByteArray message)
A binary message has been received.
virtual void init()
Initialize needed signal/slot connections.
virtual void close()
Close the socket if it is connected.
virtual bool isConnected()
If the client will attempt to reconnect, return true.
virtual bool writeBinary(QByteArray data)
Write binary data over the websocket.
void error(QAbstractSocket::SocketError)
There has been a socket error.
virtual void startPing()
Start the ping timer.
QWebSocket * _socket
client socket
void disconnected()
Connection has been lost.
virtual bool writeText(QString data)
Write text data over the websocket.
virtual void socket_receive_binary(QByteArray message)
VFS_websocket_client::socket_receive_binary.
virtual QJsonDocument receive(QByteArray message)
VFS_websocket_VFSclient::receive.
virtual bool isContainer()
A VFS_websocket_client cannot contain children.
A VFS_websocket server will listen for incoming websocket connections, optionally using ssl.
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
Definition: VFS.cpp:209
static void ERROR(QString message, int level=0, QString user="server")
Send a message to the VFS::_errors VFS_stream.
Definition: VFS.cpp:307
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
Definition: VFS.cpp:258
message(m)
Change the message of an existing arrowMessage.