diff --git a/vacancy_server/CMakeLists.txt b/vacancy_server/CMakeLists.txt new file mode 100644 index 0000000..27a2c70 --- /dev/null +++ b/vacancy_server/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.9) +project(vacancy-server) + +set(CMAKE_CXX_STANDARD 11) + +set(TBB_DIR lib/tbb) +include(cmake/TBBGet.cmake) +tbb_get(TBB_ROOT tbb_root CONFIG_DIR TBB_DIR) +find_package(TBB) + +MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar) + IF(MSVC) + GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE) + SET(PrecompiledBinary "${CMAKE_CURRENT_BINARY_DIR}/${PrecompiledBasename}.pch") + SET(Sources ${${SourcesVar}}) + + SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource} + PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" + OBJECT_OUTPUTS "${PrecompiledBinary}") + SET_SOURCE_FILES_PROPERTIES(${Sources} + PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" + OBJECT_DEPENDS "${PrecompiledBinary}") + # Add precompiled header to SourcesVar + LIST(APPEND ${SourcesVar} ${PrecompiledSource}) + ENDIF(MSVC) +ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER) + +ADD_MSVC_PRECOMPILED_HEADER(${PROJECT_NAME} "pch.h" "src/pch.cpp") + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}\ + -pthread\ + -Werror\ + -Wall\ + -Wextra\ + -Winit-self\ + -Wold-style-cast\ + -Woverloaded-virtual\ + -Winit-self\ + -pedantic-errors\ + -Wuninitialized\ + -Wuseless-cast\ + -Woverloaded-virtual\ + -Wnon-virtual-dtor\ + -Wconversion\ + -Wtrigraphs\ + -Wlogical-op\ + -Wfloat-equal\ + -Wstrict-overflow=4\ + -fsanitize=leak\ + -fsanitize=undefined\ + -fomit-frame-pointer\ +") + +add_executable( + ${PROJECT_NAME} + src/main.cpp + + src/server.cpp + src/vacancy.cpp + src/speciality.cpp + + src/network/socket_exception.cpp + src/network/server_socket.cpp + src/network/client_socket.cpp + + src/util/user_view.cpp +) + +target_link_libraries(${PROJECT_NAME} ${TBB_IMPORTED_TARGETS}) + +target_include_directories( + ${PROJECT_NAME} + PRIVATE ${PROJECT_SOURCE_DIR}/lib + PUBLIC ${PROJECT_SOURCE_DIR}/include + +) \ No newline at end of file diff --git a/vacancy_server/Readme.md b/vacancy_server/Readme.md new file mode 100644 index 0000000..e86025a --- /dev/null +++ b/vacancy_server/Readme.md @@ -0,0 +1,99 @@ +# Протокол для обмена сообщениями в системе "Vacancy service" + +## Общие замечания + +Все запросы и ответы передаются в формате _json_. Общий вид всех сообщений: +- 4 байта -- размер сообщения (без учёта этих 4-х байт). `uint_32` в формате _little endian_. +- Строка -- тело сообщения в формате _json_ + +В случае, если во время обработки запроса происходит ошибка (`success != 0`), сервер отвечает стандартным ответом с ошибкой. + +## Описание запросов и ответов + +### Добавление специальности + +#### Запрос + +- `uint32_t requestType = 1` +- `string speciality` -- название специализации + +#### Ответ + +- `int success = 0` + +--- + +### Добавление вакансии + +#### Запрос + +- `uint32_t requestType = 2` +- `VacancyInfo vacancy` + +Где `VacancyInfo`: +- `int32_t specialityId` +- `string company` +- `string position` (должность) +- `int32_t minAge` +- `int32_t maxAge` +- `int32_t salary` + +#### Ответ + +- `int success = 0` +- `uint32_t id` (id новой вакансии) + +--- + +### Удаление вакансии + +#### Запрос + +- `uint32_t requestType = 3` +- `uint32_t id` + +#### Ответ + +- `int success = 0` + +--- + +### Список специальностей + +#### Запрос + +- `uint32_t requestType = 4` + +#### Ответ + +- `int success = 0` +- `[SpecialityInfo] specialities` + +Где `SpecialityInfo`: +- `uint32_t id` +- `string speciality` + +--- + +### Список вакансий + +#### Запрос + +В данном запросе все занчения по-умолчанию (кроме поля `requestType`) означают, что пользователь не ввёл данные для этого поля + +- `uint32_t requestType = 5` +- `int32_t specialityId = -1` +- `int32_t age = -1` +- `int32_t salary = -1` + +#### Ответ + +- `int success = 0` +- `[VacancyInfo] vacancies` + +--- + +### Ответ с ошибкой + +- `int success != 0` +- `string cause` diff --git a/vacancy_server/cmake/TBBGet.cmake b/vacancy_server/cmake/TBBGet.cmake new file mode 100644 index 0000000..84fffac --- /dev/null +++ b/vacancy_server/cmake/TBBGet.cmake @@ -0,0 +1,298 @@ +# Copyright (c) 2017-2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# + +include(CMakeParseArguments) + +# Save the location of Intel TBB CMake modules here, as it will not be possible to do inside functions, +# see for details: https://cmake.org/cmake/help/latest/variable/CMAKE_CURRENT_LIST_DIR.html +set(_tbb_cmake_module_path .) + +## +# Downloads file. +# +# Parameters: +# URL - URL to download data from; +# SAVE_AS - filename there to save downloaded data; +# INFO - text description of content to be downloaded; +# will be printed as message in format is "Downloading : ; +# FORCE - option to delete local file from SAVE_AS if it exists; +# +function(_tbb_download_file) + set(options FORCE) + set(oneValueArgs URL RELEASE SAVE_AS INFO) + cmake_parse_arguments(tbb_df "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (tbb_df_FORCE AND EXISTS "${tbb_df_SAVE_AS}") + file(REMOVE ${tbb_df_SAVE_AS}) + endif() + + if (NOT EXISTS "${tbb_df_SAVE_AS}") + set(_show_progress) + if (TBB_DOWNLOADING_PROGRESS) + set(_show_progress SHOW_PROGRESS) + endif() + + message(STATUS "Downloading ${tbb_df_INFO}: ${tbb_df_URL}") + file(DOWNLOAD ${tbb_df_URL} ${tbb_df_SAVE_AS} ${_show_progress} STATUS download_status) + + list(GET download_status 0 download_status_num) + if (NOT download_status_num EQUAL 0) + message(STATUS "Unsuccessful downloading: ${download_status}") + file(REMOVE ${tbb_df_SAVE_AS}) + return() + endif() + else() + message(STATUS "Needed file was found locally ${tbb_df_SAVE_AS}. Remove it if you still want to download a new one") + endif() +endfunction() + +## +# Checks if specified Intel TBB release is available on GitHub. +# +# tbb_check_git_release( ) +# Parameters: +# - release to be checked; +# - store result (TRUE/FALSE). +# +function(_tbb_check_git_release_tag _tbb_release_tag _tbb_release_tag_avail) + if (_tbb_release_tag STREQUAL LATEST) + set(${_tbb_release_tag_avail} TRUE PARENT_SCOPE) + return() + endif() + + set(tbb_releases_file "${CMAKE_CURRENT_BINARY_DIR}/tbb_releases.json") + + _tbb_download_file(URL "${tbb_github_api}/releases" + SAVE_AS ${tbb_releases_file} + INFO "information from GitHub about Intel TBB releases" + FORCE) + + if (NOT EXISTS "${tbb_releases_file}") + set(${_tbb_release_tag_avail} FALSE PARENT_SCOPE) + return() + endif() + + file(READ ${tbb_releases_file} tbb_releases) + + string(REPLACE "\"" "" tbb_releases ${tbb_releases}) + string(REGEX MATCHALL "tag_name: *([A-Za-z0-9_\\.]+)" tbb_releases ${tbb_releases}) + + set(_release_available FALSE) + foreach(tbb_rel ${tbb_releases}) + string(REGEX REPLACE "tag_name: *" "" tbb_rel_cut ${tbb_rel}) + list(REMOVE_ITEM tbb_releases ${tbb_rel}) + list(APPEND tbb_releases ${tbb_rel_cut}) + if (_tbb_release_tag STREQUAL tbb_rel_cut) + set(_release_available TRUE) + break() + endif() + endforeach() + + if (NOT _release_available) + string(REPLACE ";" ", " tbb_releases_str "${tbb_releases}") + message(STATUS "Requested release tag ${_tbb_release_tag} is not available. Available Intel TBB release tags: ${tbb_releases_str}") + endif() + + set(${_tbb_release_tag_avail} ${_release_available} PARENT_SCOPE) +endfunction() + +## +# Compares two Intel TBB releases and provides result +# TRUE if the first release is less than the second, FALSE otherwise. +# +# tbb_is_release_less( ) +# +function(_tbb_is_release_less rel1 rel2 result) + # Convert release to numeric representation to compare it using "if" with VERSION_LESS. + string(REGEX REPLACE "[A-Za-z]" "" rel1 "${rel1}") + string(REPLACE "_" "." rel1 "${rel1}") + string(REGEX REPLACE "[A-Za-z]" "" rel2 "${rel2}") + string(REPLACE "_" "." rel2 "${rel2}") + + if (${rel1} VERSION_LESS ${rel2}) + set(${result} TRUE PARENT_SCOPE) + return() + endif() + + set(${result} FALSE PARENT_SCOPE) +endfunction() + +## +# Finds exact URL to download Intel TBB basing on provided parameters. +# +# Usage: +# _tbb_get_url(URL RELEASE_TAG OS [SOURCE_CODE]) +# +function(_tbb_get_url) + set(oneValueArgs URL RELEASE_TAG OS) + set(options SOURCE_CODE) + cmake_parse_arguments(tbb_get_url "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set(tbb_github_api "https://api.github.com/repos/01org/tbb") + + _tbb_check_git_release_tag(${tbb_get_url_RELEASE_TAG} tbb_release_available) + if (NOT tbb_release_available) + set(${tbb_download_FULL_PATH} ${tbb_download_FULL_PATH}-NOTFOUND PARENT_SCOPE) + return() + endif() + + if (tbb_get_url_RELEASE_TAG STREQUAL LATEST) + set(tbb_rel_info_api_url "${tbb_github_api}/releases/latest") + else() + set(tbb_rel_info_api_url "${tbb_github_api}/releases/tags/${tbb_get_url_RELEASE_TAG}") + endif() + + set(tbb_release_info_file "${CMAKE_CURRENT_BINARY_DIR}/tbb_${tbb_get_url_RELEASE_TAG}_info.json") + + _tbb_download_file(URL ${tbb_rel_info_api_url} + SAVE_AS ${tbb_release_info_file} + INFO "information from GitHub about packages for Intel TBB ${tbb_get_url_RELEASE_TAG}" + FORCE) + + if (NOT EXISTS "${tbb_release_info_file}") + set(${tbb_get_url_URL} ${tbb_get_url_URL}-NOTFOUND PARENT_SCOPE) + return() + endif() + + file(STRINGS ${tbb_release_info_file} tbb_release_info) + + if (tbb_get_url_SOURCE_CODE) + # Find name of the latest release to get link to source archive. + if (tbb_get_url_RELEASE_TAG STREQUAL LATEST) + string(REPLACE "\"" "" tbb_release_info ${tbb_release_info}) + string(REGEX REPLACE ".*tag_name: *([A-Za-z0-9_\\.]+).*" "\\1" tbb_get_url_RELEASE_TAG "${tbb_release_info}") + endif() + + set(${tbb_get_url_URL} "https://github.com/01org/tbb/archive/${tbb_get_url_RELEASE_TAG}.tar.gz" PARENT_SCOPE) + else() + if (tbb_get_url_OS MATCHES "Linux") + set(tbb_lib_archive_suffix lin.tgz) + elseif (tbb_get_url_OS MATCHES "Windows") + set(tbb_lib_archive_suffix win.zip) + elseif (tbb_get_url_OS MATCHES "Darwin") + set(tbb_lib_archive_suffix mac.tgz) + + # Since 2017_U4 release archive for Apple has suffix "mac.tgz" instead of "osx.tgz". + if (NOT tbb_get_url_RELEASE_TAG STREQUAL "LATEST") + _tbb_is_release_less(${tbb_get_url_RELEASE_TAG} 2017_U4 release_less) + if (release_less) + set(tbb_lib_archive_suffix osx.tgz) + endif() + endif() + elseif (tbb_get_url_OS MATCHES "Android") + set(tbb_lib_archive_suffix and.tgz) + else() + message(STATUS "Currently prebuilt Intel TBB is not available for your OS (${tbb_get_url_OS})") + set(${tbb_get_url_URL} ${tbb_get_url_URL}-NOTFOUND PARENT_SCOPE) + return() + endif() + + string(REGEX REPLACE ".*(https.*oss_${tbb_lib_archive_suffix}).*" "\\1" tbb_bin_url "${tbb_release_info}") + + set(${tbb_get_url_URL} ${tbb_bin_url} PARENT_SCOPE) + endif() +endfunction() + +function(tbb_get) + set(oneValueArgs RELEASE_TAG SYSTEM_NAME SAVE_TO TBB_ROOT CONFIG_DIR) + set(options SOURCE_CODE) + cmake_parse_arguments(tbb_get "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set(tbb_os ${CMAKE_SYSTEM_NAME}) + if (tbb_get_SYSTEM_NAME) + set(tbb_os ${tbb_get_SYSTEM_NAME}) + endif() + + set(tbb_release_tag LATEST) + if (tbb_get_RELEASE_TAG) + set(tbb_release_tag ${tbb_get_RELEASE_TAG}) + endif() + + set(tbb_save_to ${CMAKE_CURRENT_BINARY_DIR}/tbb_downloaded) + if (tbb_get_SAVE_TO) + set(tbb_save_to ${tbb_get_SAVE_TO}) + endif() + + if (tbb_get_SOURCE_CODE) + _tbb_get_url(URL tbb_url RELEASE_TAG ${tbb_release_tag} OS ${tbb_os} SOURCE_CODE) + else() + _tbb_get_url(URL tbb_url RELEASE_TAG ${tbb_release_tag} OS ${tbb_os}) + endif() + + if (NOT tbb_url) + message(STATUS "URL to download Intel TBB has not been found") + set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) + return() + endif() + + get_filename_component(filename ${tbb_url} NAME) + set(local_file "${CMAKE_CURRENT_BINARY_DIR}/${filename}") + + _tbb_download_file(URL ${tbb_url} + SAVE_AS ${local_file} + INFO "Intel TBB library") + + if (NOT EXISTS "${local_file}") + set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) + return() + endif() + + get_filename_component(subdir_name ${filename} NAME_WE) + file(MAKE_DIRECTORY ${tbb_save_to}/${subdir_name}) + if (NOT EXISTS "${tbb_save_to}/${subdir_name}") + message(STATUS "${tbb_save_to}/${subdir_name} can not be created") + set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) + return() + endif() + + message(STATUS "Unpacking ${local_file} to ${tbb_save_to}/${subdir_name}") + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${local_file} + WORKING_DIRECTORY ${tbb_save_to}/${subdir_name} + RESULT_VARIABLE unpacking_result) + + if (NOT unpacking_result EQUAL 0) + message(STATUS "Unsuccessful unpacking: ${unpacking_result}") + set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) + return() + endif() + + file(GLOB_RECURSE tbb_h ${tbb_save_to}/${subdir_name}/*/include/tbb/tbb.h) + list(GET tbb_h 0 tbb_h) + + if (NOT EXISTS "${tbb_h}") + message(STATUS "tbb/tbb.h has not been found in the downloaded package") + set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) + return() + endif() + + get_filename_component(tbb_root "${tbb_h}" PATH) + get_filename_component(tbb_root "${tbb_root}" PATH) + get_filename_component(tbb_root "${tbb_root}" PATH) + + if (NOT tbb_get_SOURCE_CODE) + set(tbb_config_dir ${tbb_root}/cmake) + + if (NOT EXISTS "${tbb_config_dir}") + tbb_make_config(TBB_ROOT ${tbb_root} CONFIG_DIR tbb_config_dir) + endif() + + set(${tbb_get_CONFIG_DIR} ${tbb_config_dir} PARENT_SCOPE) + endif() + + set(${tbb_get_TBB_ROOT} ${tbb_root} PARENT_SCOPE) +endfunction() diff --git a/vacancy_server/include/network/client_socket.h b/vacancy_server/include/network/client_socket.h new file mode 100644 index 0000000..7f99749 --- /dev/null +++ b/vacancy_server/include/network/client_socket.h @@ -0,0 +1,38 @@ +#pragma once + +#include "pch.h" +#include "socket_exception.h" + +namespace network { + + class ClientSocket { + public: + explicit ClientSocket(int descriptor = -1); + + ~ClientSocket(); + + bool is_alive(); + + void close(); + + void send_message(const std::string &message); + + std::string receive_message(); + + private: + int descriptor_; + bool is_alive_; + + void write_to_socket(const void *buffer, uint32_t size); + + void read_to_buffer(uint8_t *buffer, size_t size); + + uint32_t read_message_size(); + + std::shared_ptr encode_number(uint32_t number); + + uint32_t parse_uint32(const uint8_t *buffer); + }; + + +} // namespace network \ No newline at end of file diff --git a/vacancy_server/include/network/server_socket.h b/vacancy_server/include/network/server_socket.h new file mode 100644 index 0000000..bca9697 --- /dev/null +++ b/vacancy_server/include/network/server_socket.h @@ -0,0 +1,31 @@ +#pragma once + +#include "pch.h" +#include "client_socket.h" +#include "socket_exception.h" + +namespace network { + + class ServerSocket { + + public: + + explicit ServerSocket(uint16_t port); + + ~ServerSocket(); + + void open_connection(); + + std::shared_ptr accept(); + + void close_connection(); + + private: + int descriptor_; + const uint16_t port_; + struct sockaddr_in address_; + std::set sockets_; + + }; + +} // namespace network \ No newline at end of file diff --git a/vacancy_server/include/network/socket_exception.h b/vacancy_server/include/network/socket_exception.h new file mode 100644 index 0000000..c3aa6d0 --- /dev/null +++ b/vacancy_server/include/network/socket_exception.h @@ -0,0 +1,16 @@ +#pragma once + +#include "pch.h" + +namespace network { + + struct socket_exception : std::exception { + explicit socket_exception(std::string msg = ""); + + const char *what() const noexcept override; + + private: + std::string msg_; + }; + +} // namespace network \ No newline at end of file diff --git a/vacancy_server/include/pch.h b/vacancy_server/include/pch.h new file mode 100644 index 0000000..5049b75 --- /dev/null +++ b/vacancy_server/include/pch.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define INT_SIZE 4 +#define POWER_OF_TWO 8 +//#define UCHAR_MAX 0xffu + +#define INVALID_SOCKET -1 + +#define JSON_NAME(name, body) const char * const name = #body; + +JSON_NAME(REQUEST_TYPE, requestType) +JSON_NAME(SPECIALITY, speciality) +JSON_NAME(SPECIALITY_ID, specialityId) +JSON_NAME(SUCCESS, success) +JSON_NAME(ID, id) +JSON_NAME(VACANCY, vacancy) +JSON_NAME(SPECIALITIES, specialities) +JSON_NAME(COMPANY, company) +JSON_NAME(POSITION, position) +JSON_NAME(MIN_AGE, minAge) +JSON_NAME(MAX_AGE, maxAge) +JSON_NAME(SALARY, salary) +JSON_NAME(AGE, age) +JSON_NAME(VACANCIES, vacancies) +JSON_NAME(CAUSE, cause) \ No newline at end of file diff --git a/vacancy_server/include/server.h b/vacancy_server/include/server.h new file mode 100644 index 0000000..df7fe5d --- /dev/null +++ b/vacancy_server/include/server.h @@ -0,0 +1,80 @@ +#pragma once + +#include "pch.h" +#include "speciality.h" +#include "vacancy.h" +#include "util/user_view.h" +#include "network/server_socket.h" + +namespace vacancy_service { + + enum RequestStatus { + OK = 0, + ERROR = 1 + }; + + struct Statistics { + + Statistics(); + + std::atomic_uint32_t vacancy_count; + std::atomic_uint32_t speciality_count; + std::atomic_uint32_t client_count; + tbb::concurrent_unordered_map specialities; + tbb::concurrent_unordered_map vacancies; + }; + + class Server { + public: + + static const uint16_t DEFAULT_PORT = 1111; + + explicit Server(uint16_t port); + + void run(); + + void shut_down(); + + private: + uint16_t port_; + std::shared_ptr statistics_; + network::ServerSocket socket_; + bool is_alive_; + + void open_connection(); + + enum RequestType { + ADD_SPECIALITY = 1, + ADD_VACANCY = 2, + REMOVE_VACANCY = 3, + GET_SPECIALITIES = 4, + GET_VACANCIES = 5 + }; + + class ClientHandler { + public: + ClientHandler(const std::shared_ptr &socket, + std::shared_ptr &statistics); + + void operator()(); + + private: + std::shared_ptr socket_; + std::shared_ptr statistics_; + + nlohmann::json process_add_speciality_request(const nlohmann::json &request); + + nlohmann::json process_add_vacancy_request(const nlohmann::json &request); + + nlohmann::json process_remove_vacancy_request(const nlohmann::json &request); + + nlohmann::json process_get_specialities_request(const nlohmann::json &); + + nlohmann::json process_find_vacancies_request(const nlohmann::json &request); + + void process_request(const std::string &request); + }; + + }; + +} // namespace server \ No newline at end of file diff --git a/vacancy_server/include/speciality.h b/vacancy_server/include/speciality.h new file mode 100644 index 0000000..6a2d67c --- /dev/null +++ b/vacancy_server/include/speciality.h @@ -0,0 +1,20 @@ +#pragma once + +#include "pch.h" + +namespace vacancy_service { + + struct SpecialityInfo { + SpecialityInfo() = default; + + SpecialityInfo(int32_t id, const std::string &speciality); + + int32_t id; + std::string speciality; + }; + + void to_json(nlohmann::json &j, const SpecialityInfo &info); + + void from_json(const nlohmann::json &j, SpecialityInfo &info); + +} // namespace vacancy_service \ No newline at end of file diff --git a/vacancy_server/include/util/user_view.h b/vacancy_server/include/util/user_view.h new file mode 100644 index 0000000..8e9f87f --- /dev/null +++ b/vacancy_server/include/util/user_view.h @@ -0,0 +1,13 @@ +#pragma once + +#include "pch.h" + +namespace util { + + struct UserView { + static std::string get_user_input(const std::string &str = ""); + + static void println(const std::string &str = ""); + }; + +} // namespace util \ No newline at end of file diff --git a/vacancy_server/include/vacancy.h b/vacancy_server/include/vacancy.h new file mode 100644 index 0000000..a587ec0 --- /dev/null +++ b/vacancy_server/include/vacancy.h @@ -0,0 +1,36 @@ +#pragma once + +#include "pch.h" + +namespace vacancy_service { + + struct VacancyInfo { + VacancyInfo() = default; + + VacancyInfo(const VacancyInfo &) = default; + + VacancyInfo(VacancyInfo &&) = default; + + VacancyInfo &operator=(const VacancyInfo &) = default; + + VacancyInfo &operator=(VacancyInfo &&) = default; + + VacancyInfo(int32_t speciality_id, const std::string &company, const std::string &position, + int32_t min_age, int32_t max_age, int32_t salary); + + bool is_suitable(int32_t speciality, int32_t age, int32_t salary) const; + + int32_t speciality_id; + std::string company; + std::string position; + int32_t min_age; + int32_t max_age; + int32_t salary; + bool available = true; + }; + + void to_json(nlohmann::json &j, const VacancyInfo &info); + + void from_json(const nlohmann::json &j, VacancyInfo &info); + +} // namespace vacancy_service \ No newline at end of file diff --git a/vacancy_server/lib/json.hpp b/vacancy_server/lib/json.hpp new file mode 100644 index 0000000..c9af0be --- /dev/null +++ b/vacancy_server/lib/json.hpp @@ -0,0 +1,20406 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.5.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 5 +#define NLOHMANN_JSON_VERSION_PATCH 0 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} // namespace nlohmann + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} +} + +// #include + +// #include + + +#include + +// #include + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template