websocket_server.cpp
Go to the documentation of this file.
1 /*Wensocket PlotJuggler Plugin license(Faircode, Davide Faconti)
2 
3 Copyright(C) 2018 Philippe Gauthier - ISIR - UPMC
4 Copyright(C) 2020 Davide Faconti
5 Permission is hereby granted to any person obtaining a copy of this software and associated documentation files(the
6 "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
7 merge, publish, distribute, sublicense, and / or sell copies("Use") of the Software, and to permit persons to whom the
8 Software is furnished to do so. The above copyright notice and this permission notice shall be included in all copies or
9 substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11 NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
12 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
13 OR OTHER DEALINGS IN THE SOFTWARE.
14 */
15 #include "websocket_server.h"
16 #include <QTextStream>
17 #include <QFile>
18 #include <QMessageBox>
19 #include <QDebug>
20 #include <QSettings>
21 #include <QDialog>
22 #include <mutex>
23 #include <QWebSocket>
24 #include <QIntValidator>
25 #include <QMessageBox>
26 #include <chrono>
27 
28 #include "ui_websocket_server.h"
29 
30 class WebsocketDialog: public QDialog
31 {
32 public:
34  QDialog(nullptr),
35  ui(new Ui::WebSocketDialog)
36  {
37  ui->setupUi(this);
38  ui->lineEditPort->setValidator( new QIntValidator() );
39  setWindowTitle("WebSocket Server");
40 
41  connect( ui->buttonBox, &QDialogButtonBox::accepted,
42  this, &QDialog::accept );
43  connect( ui->buttonBox, &QDialogButtonBox::rejected,
44  this, &QDialog::reject );
45  }
47  {
48  while( ui->layoutOptions->count() > 0)
49  {
50  auto item = ui->layoutOptions->takeAt(0);
51  item->widget()->setParent(nullptr);
52  }
53  delete ui;
54  }
55  Ui::WebSocketDialog* ui;
56 };
57 
59  _running(false),
60  _server("plotJuggler", QWebSocketServer::NonSecureMode)
61 {
62  connect(&_server, &QWebSocketServer::newConnection,
64 }
65 
67 {
68  shutdown();
69 }
70 
71 bool WebsocketServer::start(QStringList*)
72 {
73  if (_running)
74  {
75  return _running;
76  }
77 
78  if( !availableParsers() )
79  {
80  QMessageBox::warning(nullptr,tr("Websocket Server"), tr("No available MessageParsers"), QMessageBox::Ok);
81  _running = false;
82  return false;
83  }
84 
85  bool ok = false;
86 
87  WebsocketDialog* dialog = new WebsocketDialog();
88 
89  for( const auto& it: *availableParsers())
90  {
91  dialog->ui->comboBoxProtocol->addItem( it.first );
92 
93  if(auto widget = it.second->optionsWidget() )
94  {
95  widget->setVisible(false);
96  dialog->ui->layoutOptions->addWidget( widget );
97  }
98  }
99 
100  // load previous values
101  QSettings settings;
102  QString protocol = settings.value("WebsocketServer::protocol", "JSON").toString();
103  int port = settings.value("WebsocketServer::port", 9871).toInt();
104 
105  dialog->ui->lineEditPort->setText( QString::number(port) );
106 
107  std::shared_ptr<MessageParserCreator> parser_creator;
108 
109  connect(dialog->ui->comboBoxProtocol, qOverload<const QString &>( &QComboBox::currentIndexChanged), this,
110  [&](QString protocol)
111  {
112  if( parser_creator ){
113  QWidget* prev_widget = parser_creator->optionsWidget();
114  prev_widget->setVisible(false);
115  }
116  parser_creator = availableParsers()->at( protocol );
117 
118  if(auto widget = parser_creator->optionsWidget() ){
119  widget->setVisible(true);
120  }
121  });
122 
123  dialog->ui->comboBoxProtocol->setCurrentText(protocol);
124 
125  int res = dialog->exec();
126  if( res == QDialog::Rejected )
127  {
128  _running = false;
129  return false;
130  }
131 
132  port = dialog->ui->lineEditPort->text().toUShort(&ok);
133  protocol = dialog->ui->comboBoxProtocol->currentText();
134  dialog->deleteLater();
135 
136  _parser = parser_creator->createInstance({}, dataMap());
137 
138  // save back to service
139  settings.setValue("WebsocketServer::protocol", protocol);
140  settings.setValue("WebsocketServer::port", port);
141 
142  if ( _server.listen(QHostAddress::Any, port))
143  {
144  qDebug() << "Websocket listening on port" << port;
145  _running = true;
146  }
147  else
148  {
149  QMessageBox::warning(nullptr,tr("Websocket Server"),
150  tr("Couldn't open websocket on port %1").arg(port),
151  QMessageBox::Ok);
152  _running = false;
153  }
154 
155  return _running;
156 }
157 
159 {
160  if (_running)
161  {
163  _server.close();
164  _running = false;
165  }
166 }
167 
169 {
170  QWebSocket* pSocket = _server.nextPendingConnection();
171  connect(pSocket, &QWebSocket::textMessageReceived, this, &WebsocketServer::processMessage);
173  _clients << pSocket;
174 }
175 
176 void WebsocketServer::processMessage(QString message)
177 {
178  std::lock_guard<std::mutex> lock(mutex());
179 
180  using namespace std::chrono;
181  auto ts = high_resolution_clock::now().time_since_epoch();
182  double timestamp = 1e-6* double( duration_cast<microseconds>(ts).count() );
183 
184  QByteArray bmsg = message.toLocal8Bit();
185  MessageRef msg ( reinterpret_cast<uint8_t*>(bmsg.data()), bmsg.size() );
186 
187  try {
188  _parser->parseMessage(msg, timestamp);
189  } catch (std::exception& err)
190  {
191  QMessageBox::warning(nullptr,
192  tr("Websocket Server"),
193  tr("Problem parsing the message. Websocket Server will be stopped.\n%1").arg(err.what()),
194  QMessageBox::Ok);
195  shutdown();
196  emit closed();
197  return;
198  }
199  emit dataReceived();
200  return;
201 }
202 
204 {
205  QWebSocket* pClient = qobject_cast<QWebSocket*>(sender());
206  if (pClient)
207  {
208  disconnect(pClient, &QWebSocket::textMessageReceived, this, &WebsocketServer::processMessage);
210  _clients.removeAll(pClient);
211  pClient->deleteLater();
212  }
213 }
#define nullptr
Definition: backward.hpp:386
QWebSocketServer _server
PJ::MessageParserPtr _parser
virtual ~WebsocketServer() override
MessageParserFactory * availableParsers()
std::mutex & mutex()
constexpr size_t count()
Definition: core.h:960
QList< QWebSocket * > _clients
PlotDataMapRef & dataMap()
detail::named_arg< Char, T > arg(const Char *name, const T &arg)
Definition: core.h:1656
virtual void shutdown() override
static int disconnected
Definition: paho_c_pub.c:80
Ui::WebSocketDialog * ui
def timestamp()
Definition: mqttsas.py:143
virtual bool start(QStringList *) override
void processMessage(QString message)


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 04:02:48