Test a local connection with Qt - c++

Is there a way to check if a cable is not unplugged by using Qt ?
I know the Ip adress that I want to contact, at first I was thinking of doing a ping request on this Ip Adress, but it seems to be too much complicated for this simple task.
So I'm thinking that maybe, there is a simple function able to do this in QNetwork library.
I search on the Internet but all the solutions are not testing one particular IP.
Thanks for your help.

Is there a way to check if a cable is not unplugged by using Qt ?
You can achieve this for specified interface using QNetworkSession:
QNetworkConfigurationManager nwManager (this);
for (;;QThread::sleep (1) ) {
bool isConfigurationFound {false};
for (auto & configuration : nwManager.allConfigurations (/*QNetworkConfiguration::Active*/) ) {
// Name depends on the environment: "Wired connection 1", "McDonaldsFreeWiFi", "Home", "eth0", "eth1", etc...
if (isConfigurationFound = (configuration.name () == "eth0") ) {
QNetworkSession session (configuration, this);
session.open ();
session.waitForOpened (/*timeout*/);
qDebug () << "Session info:";
qDebug () << "- usage: " << (session.isOpen () ? "Opened" : "Closed");
qDebug () << "- state: " << (session.state () == QNetworkSession::Connected ? "Connected" : "Not connected");
break;
}
}
qDebug () << (isConfigurationFound ? "" : "Configuration not found.");
}
If you launch this code with connected cable you get:
"Session info:"
"- usage: Opened;"
"- state: Connected;"
If you unplugged cable you get:
"Session info:"
"- usage: Closed"
"- state: Not connected"
Here is full example (also available at GitLab):
CMakeLists.txt
cmake_minimum_required (VERSION 2.8.8)
project (NaQt)
find_package (Qt5Network)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set (NaQt_SOURCES ${PROJECT_SOURCE_DIR}/main.cpp)
set (NaQt_HEADERS ${PROJECT_SOURCE_DIR}/NetworkAnalyzer.h)
qt5_wrap_cpp (NaQt_HEADERS_MOC ${NaQt_HEADERS})
add_executable (
naqt
${NaQt_SOURCES}
${NaQt_HEADERS_MOC}
)
target_link_libraries (
naqt
Qt5::Core
Qt5::Network
)
main.cpp
#include <QtCore>
#include "NetworkAnalyzer.h"
int main (int argc, char * argv [])
{
QCoreApplication application (argc, argv);
NetworkAnalyzer networkAnalyzer (& application);
return application.exec ();
}
NetworkAnalyzer.h
#ifndef QT_NETWORK_ANALYZER_H
#define QT_NETWORK_ANALYZER_H
#include <QThread>
#include <QNetworkConfigurationManager>
#include <QNetworkSession>
#include <QDebug>
class NetworkAnalyzer : public QObject
{
Q_OBJECT
public:
NetworkAnalyzer (QObject * parent = nullptr)
{
QNetworkConfigurationManager nwManager (this);
for (;;QThread::sleep (1) ) {
bool isConfigurationFound {false};
for (auto & configuration : nwManager.allConfigurations (/*QNetworkConfiguration::Active*/) ) {
// Name depends on the environment: "Wired connection 1", "McDonaldsFreeWiFi", "Home", "eth0", "eth1", etc...
if (isConfigurationFound = (configuration.name () == "eth0") ) {
QNetworkSession session (configuration, this);
session.open ();
session.waitForOpened (/*timeout*/);
qDebug () << "Session info:";
qDebug () << "- usage: " << (session.isOpen () ? "Opened" : "Closed");
qDebug () << "- state: " << (session.state () == QNetworkSession::Connected ? "Connected" : "Not connected");
break;
}
}
qDebug () << (isConfigurationFound ? "" : "Configuration not found.");
}
}
};
#endif//QT_NETWORK_ANALYZER_H

Try opening a socket to the specified IP address on a predefined port :
QTcpSocket tester;
tester.connectToHost(address, port);
if(tester.waitForConnected(3000)) {
//Remote host is online
} else {
//Remote host is offline
}

Use QT's QNetworkAccessManager class which provides networkAccessibleChanged Signal
and connect a slot to it
connect(&networkAccessManager, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(onNetworkAccessibilityChanged(QNetworkAccessManager::NetworkAccessibility)));
it emits signal telling when the ethernet cable is unplugged

Related

QDbus: connection to org.freedesktop.DBus.ObjectManager.InterfacesAdded fails but lastError() indicates no error

Here's a repo containing three code samples. There's a dbus signal emitter written in python and a subscriber also written in python. There's also a second subscriber written in C++ using Qt6 that doesn't work.
Provider's code:
#!/usr/bin/env python3
# SPDX-License-Identifier: WTFPL
import pydbus
import pydbus_manager
from gi.repository import GLib
from functools import partial
class Provider:
"""
<node>
<interface name='org.foobar.Provider1'>
<property name='FooBar' type='s' access='read'/>
</interface>
</node>
"""
#property
def FooBar(self):
return "foobar foobar"
def add_interface(manager):
print("Adding object")
manager.register_object("/org/foobar/Provider1/FooBar", Provider(), None);
return GLib.SOURCE_REMOVE
if __name__ == "__main__":
loop = GLib.MainLoop()
bus = pydbus.SessionBus()
manager = pydbus_manager.Manager(bus, "org.foobar.Provider1")
print("Registered the object manager")
GLib.timeout_add_seconds(5, partial(add_interface, manager))
print("Scheduled an interface event in 5 seconds")
loop.run()
Receiver's code:
#!/usr/bin/env python3
# SPDX-License-Identifier: WTFPL
import pydbus
from gi.repository import GLib
def on_interfaces_added(*args):
print("InterfacesAdded: args: {}".format(args))
if __name__ == "__main__":
loop = GLib.MainLoop()
bus = pydbus.SessionBus()
intf = bus.get("org.foobar.Provider1", "/org/foobar/Provider1")
intf.InterfacesAdded.connect(on_interfaces_added)
print("Connected to InterfacesAdded signal")
loop.run()
You can install the dependencies using the requirements.txt file in the repo.
The provider exposes a DBus object implementing the ObjectManager interface. It's visible using the qdbus tool as:
$ qdbus --session org.foobar.Provider1 /org/foobar/Provider1
signal void org.freedesktop.DBus.Properties.PropertiesChanged(QString interface_name, QVariantMap changed_properties, QStringList invalidated_properties)
method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface_name, QString property_name)
method QVariantMap org.freedesktop.DBus.Properties.GetAll(QString interface_name)
method void org.freedesktop.DBus.Properties.Set(QString interface_name, QString property_name, QDBusVariant value)
method QString org.freedesktop.DBus.Introspectable.Introspect()
method QString org.freedesktop.DBus.Peer.GetMachineId()
method void org.freedesktop.DBus.Peer.Ping()
signal void org.freedesktop.DBus.ObjectManager.InterfacesAdded(QDBusObjectPath object_path, {D-Bus type "a{sa{sv}}"} interfaces_and_properties)
signal void org.freedesktop.DBus.ObjectManager.InterfacesRemoved(QDBusObjectPath object_path, QStringList interfaces)
method {D-Bus type "a{oa{sa{sv}}}"} org.freedesktop.DBus.ObjectManager.GetManagedObjects()
If you run provider.py and then within 5 seconds receiver.py, you'll see that it correctly connects to and then receives the InterfacesAdded signal:
$ ./python-receiver/receiver.py
Connected to InterfacesAdded signal
InterfacesAdded: args: ('/org/foobar/Provider1/FooBar', {'org.freedesktop.DBus.Properties': {}, 'org.freedesktop.DBus.Introspectable': {}, 'org.freedesktop.DBus.Peer': {}, 'org.foobar.Provider1': {'FooBar': 'foobar foobar'}})
Same with gdbus monitor:
$ gdbus monitor --session --dest org.foobar.Provider1 --object-path /org/foobar/Provider1
Monitoring signals on object /org/foobar/Provider1 owned by org.foobar.Provider1
The name org.foobar.Provider1 is owned by :1.557
/org/foobar/Provider1: org.freedesktop.DBus.ObjectManager.InterfacesAdded (objectpath '/org/foobar/Provider1/FooBar', {'org.freedesktop.DBus.Properties': #a{sv} {}, 'org.freedesktop.DBus.Introspectable': {}, 'org.freedesktop.DBus.Peer': {}, 'org.foobar.Provider1': {'FooBar': <'foobar foobar'>}})
Now the C++ code looks like this:
main.cpp:
// SPDX-License-Identifier: WTFPL
#include <QtGlobal>
#include <QDebug>
#include <QtWidgets/QApplication>
#include <QtDBus/QDBusInterface>
#include "receiver.hpp"
Receiver::Receiver(QObject *parent) : QObject(parent) { }
Receiver::~Receiver() { }
void Receiver::InterfacesAdded(QDBusObjectPath object_path,
QMap<QString, QVariantMap> interfaces_and_properties)
{
qInfo() << "InterfacesAdded: " << object_path.path() << " " << interfaces_and_properties;
}
int main(int argc, char **argv)
{
QApplication app(argc, argv);
auto bus = QDBusConnection::sessionBus();
Receiver receiver;
qInfo() << "Before connection";
qInfo() << "Is connected " << bus.isConnected();
qInfo() << "Trying to connect";
auto ret = bus.connect(
"org.foobar.Provider1",
"/org/foobar/Provider1",
"org.freedesktop.DBus.ObjectManager",
"InterfacesAdded",
&receiver,
SLOT(InterfacesAdded(QDBusObjectPath, QMap<QString, QVariantMap>))
);
qInfo() << "connect() result: " << ret;
if (!ret)
qInfo() << "lastError: " << bus.lastError();
return app.exec();
}
receiver.hpp:
/* SPDX-License-Identifier: WTFPL */
#include <QObject>
#include <QtDBus/QDBusObjectPath>
#include <QMap>
#include <QVariant>
#include <QString>
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver(QObject *parent = nullptr);
virtual ~Receiver();
private slots:
void InterfacesAdded(QDBusObjectPath object_path,
QMap<QString, QVariantMap> interfaces_and_properties);
};
This code can be built from the repo linked above by running qmake6 and then make.
This code doesn't work: bus.connect() returns false but bus.lastError() indicates QDBusError::NoError and bus.lastError().isValid() returns false. This information is conflicting and unclear as to what goes wrong. When I run the program with QDBUS_DEBUG=1, I see a bunch of DBus traffic but nothing that would hint at any specific problem.
What am I doing wrong?

Qt SLOT not triggered by the SIGNAL emitted from std::async in QTest environment

I was investigating the topic of async programming with Qt and I reached the conclusion that it is safe to emit signals from whatever kind of threads (although QT docs only mention QThread), as more or less described here. Now I faced the problem testing my application. To simplify as much as possible: I have the async operation, which might notify MainWindow by emitting the SIGNAL. It works fine in the production, but it doesn't work in unit-test environment with QTest. Complete example (project structure flat, no subdirs):
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(QtFailure)
enable_testing()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
if(CMAKE_VERSION VERSION_LESS "3.7.0")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()
find_package(Qt5 COMPONENTS Core Widgets Test REQUIRED)
add_library(QtFailure source.cpp header.hpp)
target_include_directories(QtFailure PUBLIC .)
target_link_libraries(QtFailure
pthread
Qt5::Core
Qt5::Widgets
)
add_executable(main main.cpp)
target_link_libraries(main QtFailure)
add_executable(QtFailureTest test.cpp)
target_link_libraries(QtFailureTest
QtFailure
Qt5::Test
)
header.hpp
#pragma once
#include <QMainWindow>
#include <QWidget>
#include <future>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
~MainWindow();
void start();
int counter_value();
signals:
void sendSignal();
private slots:
bool triggerSlot();
private:
bool stop_;
std::future<void> async_oper_;
};
source.cpp
#include "header.hpp"
#include <QMainWindow>
#include <QWidget>
#include <QObject>
#include <QDebug>
#include <future>
#include <chrono>
#include <thread>
static int counter = 0;
MainWindow::MainWindow(QWidget* parent):
QMainWindow(parent),
stop_(false),
async_oper_()
{
QObject::connect(this, SIGNAL(sendSignal()), this, SLOT(triggerSlot()));
}
MainWindow::~MainWindow()
{
stop_ = true;
}
int MainWindow::counter_value()
{
return counter;
}
void MainWindow::start()
{
if (async_oper_.valid()) return;
emit sendSignal(); // this one works
async_oper_ = std::async(std::launch::async, [this]()
{
while (!stop_)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
emit sendSignal(); // this one doesn't work in tests
}
});
}
bool MainWindow::triggerSlot()
{
qDebug() << "triggerSlot: " << counter;
counter++;
}
test.cpp
#include "header.hpp"
#include <QSignalSpy>
#include <QDebug>
#include <QtTest/QtTest>
#include <memory>
#include <chrono>
#include <thread>
class MyFixture: public QObject
{
Q_OBJECT
private:
std::unique_ptr<MainWindow> sut_;
private slots:
void init()
{
qDebug("MyFixture init");
sut_.reset(new MainWindow);
}
void cleanup()
{
qDebug("MyFixture cleanup");
sut_.reset();
}
void example_test()
{
QSignalSpy spy(sut_.get(), SIGNAL(sendSignal()));
sut_->start();
std::this_thread::sleep_for(std::chrono::seconds(1));
qDebug() << "num signals: " << spy.count();
qDebug() << "counter value: " << sut_->counter_value();
}
};
QTEST_MAIN(MyFixture)
#include "test.moc"
main.cpp
#include <QApplication>
#include "header.hpp"
int main(int argc, char** argv)
{
QApplication a(argc, argv);
MainWindow w;
w.start();
w.show();
return a.exec();
}
The output from my test is
PASS : MyFixture::initTestCase()
QDEBUG : MyFixture::example_test() MyFixture init
QDEBUG : MyFixture::example_test() triggerSlot: 0
QDEBUG : MyFixture::example_test() num signals: 10
QDEBUG : MyFixture::example_test() counter value: 1
QDEBUG : MyFixture::example_test() MyFixture cleanup
PASS : MyFixture::example_test()
PASS : MyFixture::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 1003ms
which means that the slot was triggered only once, by the signal emitted from the main thread.
The output from main is:
...
triggerSlot: 25
triggerSlot: 26
triggerSlot: 27
etc ...
which is the expected behavior. Why is there a difference between QTest environment and normal QApplication in main? What should I do to correct tests behavior?
I must use standard C++ threads, because my GUI is just a facade to real non-Qt related system, which has different kinds of async opers, callbacks etc.
Sorry for the amount of code, but with QT I cannot really squeeze it in a few lines.
=== EDIT ===
Specifying Qt::DirectConnection connection attribute will "fix" the issue in the QTest environment. But this is something I cannot do in most cases, because GUI actions must take place in the main thread (e.g. scync oper emits signal to trigger QPixmap refresh);
The signal emit code is correct. Queued Signal-Slot connection requires event loop to be running in the receiver thread for signal delivery:
Events to that object are dispatched by that (receiver) thread's event loop.
Event loop of the receiver thread aren't working because you block it in the line
// just suspends current thread without running any event loop
std::this_thread::sleep_for(std::chrono::seconds(1));
That is, event loop of the receiver thread are blocking throughout the whole example_test() method body. There is no one line which runs an event loop within itself. That is not Qt Test or QTEST_MAIN() issue.
Here is how you can fix that:
void example_test()
{
QSignalSpy spy(sut_.get(), SIGNAL(sendSignal()));
sut_->start();
QElapsedTimer timer;
timer.start();
while(timer.elapsed() < 1000)
{
spy.wait(10); // event loop runs here
}
qDebug() << "num signals: " << spy.count();
qDebug() << "counter value: " << sut_->counter_value();
}
QSignalSpy::wait():
Starts an event loop that runs until the given signal is received.
Optionally the event loop can return earlier on a timeout (in
milliseconds).
Returns true if the signal was emitted at least once in timeout milliseconds, otherwise returns false.

QT 5.4 QPrinterInfo::printerName returns blanks

I am trying to instantiate a printer without using QPrintDialog as our GUI is QML where QPrintDialog does not exist (we are creating a printer selection dialog in QML). I am calling two invokable C++ functions 1) one function retrieves a list of valid printers and passes that back to QML, and 2) second function instantiate a printer name that was selected by the user in QML and then prints to a painter. I am using Ubuntu Linux (32) with Qt5.4.0. One interesting issue I uncovered is that when I use QPrinterInfo::availablePrinterNames() a valid list of printer names is found. When I get a list of QPrinterInfo object via using static function QPrinterInfo::availablePrinters(), then traverse the list and display the names in printerName, an empty string is returned. The documentation says that this should be a unique ID for the printer, not an empty string?????
Here's is a extract which demonstrates the issue:
#include <QCoreApplication>
#include <QString>
#include <QStringList>
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPrintDialog>
#include <QtPrintSupport/QPrinterInfo>
#include <QDebug>
#include <QList>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Printer names via availablePrinterNames method";
QStringList name_list = QPrinterInfo::availablePrinterNames();
foreach ( QString name, name_list)
qDebug() << name;
qDebug() << "\nPrinter names via availablePrinters method";
QList<QPrinterInfo> info_list = QPrinterInfo::availablePrinters();
foreach ( QPrinterInfo info, info_list )
qDebug() << info.printerName();
return a.exec();
}
I have not tried this with earlier versions of QT or the Windows version. Does anyone have any hints?
Thanks
In short: The reason for the issue is that CUPS supports driverless printers (info), and Qt does not.
Qt uses CUPS API to return the list of printers in system (availablePrinterNames) without checking, but when it constructs QPrinterInfo, it checks if the printer has a PPD driver. If not, the printer is considered invalid, and Qt returns empty name for it.
Please try this, it worked for me. First you should add windowsprintersupport.dll to your project.
int count = 0;
QList<QPrinterInfo> info_list = QPrinterInfo::availablePrinters();
foreach ( QPrinterInfo info, info_list )
{
count++;
qDebug()<< "Printer_"<< count<< ": " << info.printerName() << "State: " << info.state();
if(info.printerName() == "YOUR_PRINTER_NAME")
{
if (info.state() == 0)
qDebug()<< "Printer Idle";
else if (info.state() == 1)
qDebug()<< "Printer Active";
else if (info.state() == 2)
qDebug()<< "Printer Aborted";
else if (info.state() == 3)
qDebug()<< "Printer Error";
else
qDebug()<< "Printer Undefined Error";
}
}

QtSoap Network transport error (99): Error creating SSL context () Linux Mint

I have a problem with connection to a web service with ssl protocol. I was trying to connect with specyfied WebService using open libraries QtSoap. Since now I have been searching any solution of error which I have mentioned in the topic, but not found any for linux-mint system. Only one I have seen, which people confirmed were for Windows here 1 and here 2. I have certificate for this webService which contains a key.
My pice of code:
#include "qtsoap.h"
...
int main(int argc, char **argv)
{
...
QtSoapMessage message;
QSsl::SslProtocol protocol = QSsl::SslV2;
message.addHeaderItem(new QtSoapSimpleType(QtSoapQName("tagName"),"tagValue"));
...
message.setMethod("method", "WSAddress");
message.addMethodArgument("attr", "", value);
...
QtSoapHttpTransport http;
http.setHost("ipaddress", true, port);
http.setAction("http://tempuri.org/IDataService/DARTGetReservationData");
http.submitRequest(message, "path", protocol, "certificatePath");
}
I have made some changes in a library if You have already noticed in submitRequest, adding specyfied SslProtocol and certificatePath. Here is a sorce:
void QtSoapHttpTransport::submitRequest(QNetworkRequest &networkReq, QtSoapMessage &request, const QString &path, QSsl::SslProtocol ssl, QString certificatePath)
{
networkReq.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("text/xml;charset=utf-8"));
networkReq.setRawHeader("SOAPAction", soapAction.toLatin1());
url.setPath(path);
networkReq.setUrl(url);
QSslConfiguration sslConf = networkReq.sslConfiguration();
soapResponse.clear();
if(certificatePath != NULL)
{
QFile sslCertificateFile(certificatePath);
if (sslCertificateFile.open(QIODevice::ReadOnly))
{
QSslCertificate certif(&sslCertificateFile);
if (certif.isNull())
{
qDebug() << "Failed to load certificate";
}
sslConf.setLocalCertificate(certif);
sslConf.setPrivateKey(certif.publicKey());
qDebug() << "certif version=" << certif.version() << ", serial=" << certif.serialNumber()
<< ", issuer=" << certif.issuerInfo(QSslCertificate::Organization)
<< " and subject=" << certif.subjectInfo(QSslCertificate::CommonName);
QSslKey key(certif.publicKey());
qDebug() << "key isNull ? " << key.isNull();
sslConf.setPrivateKey(key);
sslCertificateFile.close();
}
else
qDebug() << "Cannot open certificate";
}
if(ssl != NULL)
sslConf.setProtocol(ssl);
networkReq.setSslConfiguration(sslConf);
networkRep = networkMgr.post(networkReq, request.toXmlString().toUtf8().constData());
}
One more thing related to this modified libraries. I added some headers to:
#include <QSslCertificate>
#include <QSsl>
#include <QSslConfiguration>
#include <QSslKey>
#include <QFile>
I guess that there is missing something in my *.pro file, but I do not know what it could be. So I added it below
QT += core network xml
QT -= gui
TARGET = SSLConnectionTest
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
qtsoap.cpp
HEADERS += \
qtsoap.h
Another thing that could be wrong is there is missing some other libraries which I don't know. I hope someone have found solution of this problem?
Sorry for my poor english.

Can multiple WT applications run on same port?

Update 1: I have recently found out that WT communicates using TCP (HTTP), if that helps anyone.
The title says it all, is it possible to run 2 different WT applications or projects on the same port? I know WT has come control over how the application is hosted with its start up parameters as follows. I am using Visual Studio 2010 and the parameters below are entered in the debugging->command arguments box as follows:
--http-address=0.0.0.0 --http-port=8080 --deploy-path=/hello --docroot=.
The above parameters will require that the user opens a web page at
http://127.0.0.1:8080/hello
So I though, hey what if I host another project with the below parameters
--http-address=0.0.0.0 --http-port=8080 --deploy-path=/world --docroot=.
so then I would need to connect to
http://127.0.0.1:8080/world
The above actually does not work, it only hosts the first application that connects, and the second will not connect until the first shuts down. So this brings me here. Are there any other ways to run multiple WT applications on the same port?
Thank you in advance for any help!
Yes, you can achieve that but you will need to create your own WRun and use addEntryPoint. This is actually mentioned in the tutorial and goes as follows:
Inside WRun()
WRun() is actually a convenience function which creates and configures a WServer instance. If you want more control, for example if you have multiple “entry points”, or want to control the server starting and stopping, you can use the WServer API directly instead.
Here you have an example, both applications are the Hello World application, but notice that they have different titles and different messages on the buttons and when you press them. You can find another implementation of WRun on src/http/Serve.C and src/Wt/WServer.
two_helloworlds.cc
#include <Wt/WApplication>
#include <Wt/WBreak>
#include <Wt/WContainerWidget>
#include <Wt/WLineEdit>
#include <Wt/WPushButton>
#include <Wt/WText>
#include <Wt/WException>
#include <Wt/WLogger>
#include <Wt/WServer>
class HelloApplication : public Wt::WApplication
{
public:
HelloApplication(const Wt::WEnvironment& env, const std::string& title);
private:
Wt::WLineEdit *nameEdit_;
Wt::WText *greeting_;
void greet();
};
HelloApplication::HelloApplication(const Wt::WEnvironment& env, const std::string& title)
: Wt::WApplication(env)
{
setTitle(title);
root()->addWidget(new Wt::WText("Your name, please ? "));
nameEdit_ = new Wt::WLineEdit(root());
Wt::WPushButton *button = new Wt::WPushButton("Greet me.", root());
root()->addWidget(new Wt::WBreak());
greeting_ = new Wt::WText(root());
button->clicked().connect(this, &HelloApplication::greet);
}
void HelloApplication::greet()
{ greeting_->setText("Hello there, " + nameEdit_->text());
}
class GoodbyeApplication : public Wt::WApplication{
public:
GoodbyeApplication(const Wt::WEnvironment& env, const std::string& title);
private: Wt::WLineEdit *nameEdit_;
Wt::WText *greeting_;
void greet();
};
GoodbyeApplication::GoodbyeApplication(const Wt::WEnvironment& env, const std::string& title)
: Wt::WApplication(env)
{
setTitle(title);
root()->addWidget(new Wt::WText("Your name, please ? "));
nameEdit_ = new Wt::WLineEdit(root());
Wt::WPushButton *button = new Wt::WPushButton("Say goodbye.", root());
root()->addWidget(new Wt::WBreak());
greeting_ = new Wt::WText(root());
button->clicked().connect(this, &GoodbyeApplication::greet);
}
void GoodbyeApplication::greet()
{
greeting_->setText("Goodbye, " + nameEdit_->text());
}
Wt::WApplication *createApplication(const Wt::WEnvironment& env)
{
return new HelloApplication(env, "First app");
}
Wt::WApplication *createSecondApplication(const Wt::WEnvironment& env)
{
return new GoodbyeApplication(env, "Second app");
}
int YourWRun(int argc, char *argv[], Wt::ApplicationCreator createApplication, Wt::ApplicationCreator createSecondApplication)
{
try {
// use argv[0] as the application name to match a suitable entry
// in the Wt configuration file, and use the default configuration
// file (which defaults to /etc/wt/wt_config.xml unless the environment
// variable WT_CONFIG_XML is set)
Wt::WServer server(argv[0],"");
// WTHTTP_CONFIGURATION is e.g. "/etc/wt/wthttpd"
server.setServerConfiguration(argc, argv, WTHTTP_CONFIGURATION);
// add a single entry point, at the default location (as determined
// by the server configuration's deploy-path)
server.addEntryPoint(Wt::Application, createApplication);
server.addEntryPoint(Wt::Application, createSecondApplication,"/second");
if (server.start()) {
int sig = Wt::WServer::waitForShutdown(argv[0]);
std::cerr << "Shutdown (signal = " << sig << ")" << std::endl;
server.stop();
/*
if (sig == SIGHUP)
WServer::restart(argc, argv, environ);
*/
}
} catch (Wt::WServer::Exception& e) {
std::cerr << e.what() << "\n";
return 1;
} catch (std::exception& e) {
std::cerr << "exception: " << e.what() << "\n";
return 1;
}
}
int main(int argc, char **argv)
{
return YourWRun(argc, argv, &createApplication, &createSecondApplication);
}
Compile it with
g++ -g -o two_helloworlds two_helloworlds.cc -I/usr/local/include -L/usr/local/lib -lwthttp -lwt -lboost_random -lboost_regex -lboost_signals -lboost_system -lboost_thread -lboost_filesystem -lboost_program_options -lboost_date_time
and execute with
./two_helloworlds --docroot . --http-address 0.0.0.0 --http-port 8080
on localhost:8080 you will access one of the applications and on localhost:8080/second you will access the other.