added suport for embedding resources and added serving /favicon.ico
Dieser Commit ist enthalten in:
Ursprung
8c2d89cdc6
Commit
de65905387
@ -203,6 +203,21 @@ if(DEFINED ENV{VCPKG_ROOT})
|
||||
include($ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
|
||||
endif()
|
||||
|
||||
### RESOURCES ###
|
||||
|
||||
include(cmake/add-resource.cmake)
|
||||
|
||||
add_resource(resource-shared
|
||||
BASE_DIR ../
|
||||
FILES
|
||||
shared/gfx/appicon.ico
|
||||
)
|
||||
|
||||
add_dependencies(traintastic-server resource-shared)
|
||||
if(BUILD_TESTING)
|
||||
add_dependencies(traintastic-server-test resource-shared)
|
||||
endif()
|
||||
|
||||
### OPTIONS ###
|
||||
|
||||
if(NO_LOCALHOST_ONLY_SETTING)
|
||||
|
||||
40
server/cmake/add-resource.cmake
Normale Datei
40
server/cmake/add-resource.cmake
Normale Datei
@ -0,0 +1,40 @@
|
||||
#
|
||||
# This file is part of the traintastic source code.
|
||||
# See <https://github.com/traintastic/traintastic>.
|
||||
#
|
||||
# Copyright (C) 2024 Reinder Feenstra
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
function(add_resource TARGET_NAME)
|
||||
cmake_parse_arguments(PARSE_ARG "" "BASE_DIR" "FILES" ${ARGN})
|
||||
if(PARSE_ARG_BASE_DIR)
|
||||
set(PARSE_ARG_BASE_DIR "${CMAKE_SOURCE_DIR}/${PARSE_ARG_BASE_DIR}")
|
||||
else()
|
||||
set(PARSE_ARG_BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif()
|
||||
foreach(INPUT_FILE ${PARSE_ARG_FILES})
|
||||
set(OUTPUT_FILE ${CMAKE_BINARY_DIR}/resource/${INPUT_FILE}.hpp)
|
||||
add_custom_command(
|
||||
OUTPUT ${OUTPUT_FILE}
|
||||
COMMAND Python3::Interpreter ${CMAKE_SOURCE_DIR}/cmake/generateresourceheader.py ${PARSE_ARG_BASE_DIR} ${INPUT_FILE} ${OUTPUT_FILE}
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/cmake/generateresourceheader.py ${PARSE_ARG_BASE_DIR}/${INPUT_FILE}
|
||||
COMMENT "Generating resource header resource/${INPUT_FILE}.hpp"
|
||||
)
|
||||
list(APPEND OUTPUT_HEADERS ${OUTPUT_FILE})
|
||||
endforeach()
|
||||
add_custom_target(${TARGET_NAME} ALL DEPENDS ${OUTPUT_HEADERS})
|
||||
endfunction()
|
||||
84
server/cmake/generateresourceheader.py
Normale Datei
84
server/cmake/generateresourceheader.py
Normale Datei
@ -0,0 +1,84 @@
|
||||
#
|
||||
# This file is part of the traintastic source code.
|
||||
# See <https://github.com/traintastic/traintastic>.
|
||||
#
|
||||
# Copyright (C) 2024 Reinder Feenstra
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print(f"Usage: {sys.argv[0]} <input dir> <input file> <output header>")
|
||||
sys.exit(1)
|
||||
|
||||
input_file = os.path.join(sys.argv[1], sys.argv[2])
|
||||
input_file_ext = os.path.splitext(input_file)[1]
|
||||
|
||||
namespaces = ['Resource'] + os.path.dirname(sys.argv[2]).replace('../', '').split('/')
|
||||
variable = re.sub(r'[\.]+','_', os.path.basename(sys.argv[2]).lower())
|
||||
guard = '_'.join(namespaces).upper() + '_' + re.sub(r'[\.]+','_', os.path.basename(sys.argv[3]).upper())
|
||||
|
||||
is_binary = input_file_ext not in ['html', 'css', 'js']
|
||||
|
||||
with open(input_file, 'rb') as f:
|
||||
contents = f.read()
|
||||
|
||||
if is_binary:
|
||||
size = len(contents)
|
||||
contents = ', '.join(['std::byte{' + str(by) + '}' for by in contents])
|
||||
|
||||
contents = '\n '.join(textwrap.wrap(contents, width=120))
|
||||
|
||||
with open(sys.argv[3], 'w') as f:
|
||||
f.write(f'''// Auto-generated, do not edit, it will be overwritten
|
||||
|
||||
#ifndef {guard}
|
||||
#define {guard}
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace {'::'.join(namespaces)}
|
||||
{{
|
||||
|
||||
constexpr std::array<std::byte, {size}> {variable}{{{{
|
||||
{contents}
|
||||
}}}};
|
||||
|
||||
}}
|
||||
#endif
|
||||
''')
|
||||
|
||||
else: # text
|
||||
with open(sys.argv[3], 'w') as f:
|
||||
f.write(f'''// Auto-generated, do not edit, it will be overwritten
|
||||
|
||||
#ifndef {guard}
|
||||
#define {guard}
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace {'::'.join(namespaces)}
|
||||
{{
|
||||
|
||||
constexpr std::string_view {variable} = R"({contents})";
|
||||
|
||||
}}
|
||||
#endif
|
||||
''')
|
||||
@ -21,6 +21,8 @@
|
||||
*/
|
||||
|
||||
#include "server.hpp"
|
||||
#include <boost/beast/http/buffer_body.hpp>
|
||||
#include <tcb/span.hpp>
|
||||
#include <traintastic/network/message.hpp>
|
||||
#include <version.hpp>
|
||||
#include "connection.hpp"
|
||||
@ -29,6 +31,7 @@
|
||||
#include "../log/log.hpp"
|
||||
#include "../log/logmessageexception.hpp"
|
||||
#include "../utils/setthreadname.hpp"
|
||||
#include <resource/shared/gfx/appicon.ico.hpp>
|
||||
|
||||
#define IS_SERVER_THREAD (std::this_thread::get_id() == m_thread.get_id())
|
||||
|
||||
@ -40,7 +43,8 @@ namespace
|
||||
|
||||
static constexpr std::string_view serverHeader{"Traintastic-server/" TRAINTASTIC_VERSION_FULL};
|
||||
static constexpr std::string_view contentTypeTextPlain{"text/plain"};
|
||||
static constexpr std::string_view contentTypeTextHtml{"text/Html"};
|
||||
static constexpr std::string_view contentTypeTextHtml{"text/html"};
|
||||
static constexpr std::string_view contentTypeImageXIcon{"image/x-icon"};
|
||||
|
||||
http::message_generator notFound(const http::request<http::string_body>& request)
|
||||
{
|
||||
@ -70,6 +74,30 @@ http::message_generator methodNotAllowed(const http::request<http::string_body>&
|
||||
return response;
|
||||
}
|
||||
|
||||
http::message_generator binary(const http::request<http::string_body>& request, std::string_view contentType, tcb::span<const std::byte> body)
|
||||
{
|
||||
if(request.method() != http::verb::get && request.method() != http::verb::head)
|
||||
{
|
||||
return methodNotAllowed(request, {http::verb::get, http::verb::head});
|
||||
}
|
||||
http::response<http::buffer_body> response{http::status::ok, request.version()};
|
||||
response.set(http::field::server, serverHeader);
|
||||
response.set(http::field::content_type, contentType);
|
||||
response.keep_alive(request.keep_alive());
|
||||
if(request.method() == http::verb::head)
|
||||
{
|
||||
response.content_length(body.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
response.body().data = const_cast<std::byte*>(body.data());
|
||||
response.body().size = body.size();
|
||||
}
|
||||
response.body().more = false;
|
||||
response.prepare_payload();
|
||||
return response;
|
||||
}
|
||||
|
||||
http::message_generator text(const http::request<http::string_body>& request, std::string_view contentType, std::string_view body)
|
||||
{
|
||||
if(request.method() != http::verb::get && request.method() != http::verb::head)
|
||||
@ -288,10 +316,11 @@ void Server::doAccept()
|
||||
|
||||
http::message_generator Server::handleHTTPRequest(http::request<http::string_body>&& request)
|
||||
{
|
||||
if(request.target() == "/")
|
||||
const auto target = request.target();
|
||||
if(target == "/")
|
||||
{
|
||||
return textHtml(request,
|
||||
"<!doctype html>"
|
||||
"<!DOCTYPE html>"
|
||||
"<html>"
|
||||
"<head>"
|
||||
"<meta charset=\"utf-8\">"
|
||||
@ -299,11 +328,15 @@ http::message_generator Server::handleHTTPRequest(http::request<http::string_bod
|
||||
"<title>Traintastic v" TRAINTASTIC_VERSION_FULL "</title>"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<h1>Traintastic v" TRAINTASTIC_VERSION_FULL "</h1>"
|
||||
"<h1>Traintastic <small>v" TRAINTASTIC_VERSION_FULL "</small></h1>"
|
||||
"</body>"
|
||||
"</html>");
|
||||
}
|
||||
if(request.target() == "/version")
|
||||
if(target == "/favicon.ico")
|
||||
{
|
||||
return binary(request, contentTypeImageXIcon, Resource::shared::gfx::appicon_ico);
|
||||
}
|
||||
if(target == "/version")
|
||||
{
|
||||
return textPlain(request, TRAINTASTIC_VERSION_FULL);
|
||||
}
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren