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


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:12:53