add an example to embed a server in a Qt GUI app

master
Chunting Gu 5 years ago
parent c3643277b2
commit 233aa5910c

@ -23,6 +23,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${BUILD_DIR}/bin/release)
option(WEBCC_ENABLE_AUTOTEST "Build automation test?" OFF)
option(WEBCC_ENABLE_UNITTEST "Build unit test?" OFF)
option(WEBCC_ENABLE_EXAMPLES "Build examples?" ON)
option(WEBCC_ENABLE_QT_EXAMPLES "Build Qt application examples?" OFF)
set(WEBCC_ENABLE_LOG 1 CACHE STRING "Enable logging? (1:Yes, 0:No)")
set(WEBCC_ENABLE_SSL 0 CACHE STRING "Enable SSL/HTTPS (need OpenSSL)? (1:Yes, 0:No)")

@ -40,10 +40,14 @@ target_link_libraries(form_urlencoded_client ${EXAMPLE_LIBS})
add_executable(form_server form_server.cc)
target_link_libraries(form_server ${EXAMPLE_LIBS})
add_subdirectory(book_server)
add_subdirectory(book_client)
if(WIN32)
add_executable(url_unicode url_unicode.cc encoding.cc encoding.h)
target_link_libraries(url_unicode ${EXAMPLE_LIBS})
endif()
add_subdirectory(book_server)
add_subdirectory(book_client)
if(WEBCC_ENABLE_QT_EXAMPLES)
add_subdirectory(qt_app_server)
endif()

@ -0,0 +1,11 @@
project(qt_app_server)
find_package(Qt5 CONFIG REQUIRED Core Gui Widgets)
set(CMAKE_AUTOMOC ON)
file(GLOB SRCS *.cpp *.h)
add_executable(qt_app_server ${SRCS})
target_link_libraries(qt_app_server Qt5::Core Qt5::Gui Qt5::Widgets ${EXAMPLE_LIBS})

@ -0,0 +1,56 @@
#include <thread>
#include <QApplication>
#include "examples/qt_app_server/main_window.h"
#include "webcc/logger.h"
#include "webcc/response_builder.h"
#include "webcc/server.h"
#include "webcc/view.h"
class ApiView : public webcc::View {
public:
explicit ApiView(Context* context) : context_(context) {
}
webcc::ResponsePtr Handle(webcc::RequestPtr request) override {
if (request->method() == "GET") {
emit context_->SomeApiSignal("A GET request has been handled");
return webcc::ResponseBuilder{}.OK().Body("Hello, World!")();
}
return {};
}
private:
Context* context_;
};
int main(int argc, char** argv) {
QApplication app{ argc, argv };
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
Context context;
// Create a server and bind view.
webcc::Server server{ boost::asio::ip::tcp::v4(), 8000 };
server.Route("/", std::make_shared<ApiView>(&context));
// Run the server in a thread to avoid blocking the GUI.
std::thread server_thread{ [&server]() { server.Run(); } };
// Now show our Qt main window and execute the application loop.
MainWindow main_window{ &context };
main_window.resize(400, 300);
main_window.showNormal();
int code = app.exec();
// Stop the server and wait for it to finish.
server.Stop();
server_thread.join();
return code;
}

@ -0,0 +1,21 @@
#include "examples/qt_app_server/main_window.h"
#include <QDebug>
MainWindow::MainWindow(Context* context, QWidget* parent)
: QMainWindow(parent) {
setWindowTitle("Qt App Server");
#if 1
connect(context, &Context::SomeApiSignal, this, &MainWindow::OnSomeApiSignal);
#else
// NOTE: Seems not necessary to use QueuedConnection (because we are using
// std::thread instead of QThread?).
connect(context, &Context::SomeApiSignal, this, &MainWindow::OnSomeApiSignal,
Qt::QueuedConnection);
#endif
}
void MainWindow::OnSomeApiSignal(const QString& text) {
qDebug() << text;
}

@ -0,0 +1,34 @@
#ifndef MAIN_WINDOW_H_
#define MAIN_WINDOW_H_
#include <QMainWindow>
// Some global QObject with public signals for ApiView to inform the handling
// of client requests.
// "Context" is a bad name, you should change it.
class Context : public QObject {
Q_OBJECT
public:
explicit Context(QObject* parent = nullptr) : QObject(parent) {
}
// Public signals emitted from ApiView:
signals:
void SomeApiSignal(const QString& text);
// Add other signals here...
};
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(Context* context, QWidget* parent = nullptr);
private:
// You should encapsulate the required information as the signal parameters.
// I use QString just for demostrating how to transfer data from ApiView.
void OnSomeApiSignal(const QString& text);
};
#endif // MAIN_WINDOW_H_

@ -118,6 +118,7 @@ bool RequestParser::ParseMultipartContent(const char* data,
}
// Next boundary found.
LOG_INFO("Next boundary found, off=%u", off);
// This part has ended.
if (off >= 2) {
@ -128,7 +129,7 @@ bool RequestParser::ParseMultipartContent(const char* data,
// +2 for including the CRLF after the boundary.
pending_data_.erase(0, off + count + 2);
} else {
LOG_ERRO("Invalid part data.");
LOG_ERRO("Invalid part data. off=%u", off);
return false;
}

Loading…
Cancel
Save