mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralfms.git
synced 2026-01-27 02:23:02 +00:00
Reword with microservice arch.
This commit is contained in:
@@ -5,6 +5,13 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
if(UNIX AND APPLE)
|
||||
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)
|
||||
set(MYSQL_ROOT_DIR /usr/local/opt/mysql-client)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(PostgreSQL_TYPE_INCLUDE_DIR /usr/include/postgresql)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)
|
||||
endif()
|
||||
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build)
|
||||
@@ -19,7 +26,6 @@ else()
|
||||
endif()
|
||||
|
||||
set(BUILD_SHARED_LIBS 1)
|
||||
|
||||
add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}" -DAWS_CUSTOM_MEMORY_MANAGEMENT)
|
||||
|
||||
set(Boost_USE_STATIC_LIBS OFF)
|
||||
@@ -29,29 +35,36 @@ set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
find_package(Boost REQUIRED system)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(AWSSDK REQUIRED COMPONENTS s3)
|
||||
find_package(CppKafka REQUIRED)
|
||||
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
||||
|
||||
include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka)
|
||||
if(SMALL_BUILD)
|
||||
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
||||
else()
|
||||
find_package(CppKafka REQUIRED)
|
||||
find_package(PostgreSQL REQUIRED)
|
||||
find_package(MySQL REQUIRED)
|
||||
find_package(ODBC REQUIRED)
|
||||
find_package(Poco REQUIRED COMPONENTS JSON Crypto JWT Net Util NetSSL Data DataSQLite DataPostgreSQL DataMySQL DataODBC)
|
||||
endif()
|
||||
|
||||
include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include)
|
||||
|
||||
add_executable( ucentralfms
|
||||
build
|
||||
src/Daemon.cpp src/Daemon.h src/RESTAPI_objects.h src/RESTAPI_objects.cpp
|
||||
src/StorageService.cpp src/StorageService.h src/storage_tables.cpp
|
||||
src/storage_sqlite.cpp src/SubSystemServer.cpp src/SubSystemServer.h
|
||||
src/Daemon.cpp src/Daemon.h
|
||||
src/StorageService.cpp src/StorageService.h
|
||||
src/storage_tables.cpp src/storage_sqlite.cpp
|
||||
src/SubSystemServer.cpp src/SubSystemServer.h
|
||||
src/RESTAPI_handler.cpp src/RESTAPI_handler.h
|
||||
src/Utils.cpp src/Utils.h src/storage_callbacks.cpp src/storage_firmwares.cpp
|
||||
src/storage_latestfirmware.cpp src/RESTAPI_server.cpp src/RESTAPI_server.h
|
||||
src/storage_firmwares.cpp
|
||||
src/storage_mysql.cpp src/storage_pgql.cpp src/storage_odbc.cpp
|
||||
src/Utils.cpp src/Utils.h
|
||||
src/RESTAPI_server.cpp src/RESTAPI_server.h
|
||||
src/RESTAPI_firmwaresHandler.cpp src/RESTAPI_firmwaresHandler.h
|
||||
src/RESTAPI_callbacksHandler.cpp src/RESTAPI_callbacksHandler.h
|
||||
src/RESTAPI_callbackHandler.cpp src/RESTAPI_callbackHandler.h
|
||||
src/RESTAPI_firmwareHandler.cpp src/RESTAPI_firmwareHandler.h
|
||||
src/RESTAPI_latestFirmwareListHandler.cpp src/RESTAPI_latestFirmwareListHandler.h
|
||||
src/RESTAPI_GWobjects.cpp src/RESTAPI_GWobjects.h
|
||||
src/ALBHealthCheckServer.h
|
||||
src/RESTAPI_callbackChannel.cpp src/RESTAPI_callbackChannel.h
|
||||
src/NotificationMgr.cpp src/NotificationMgr.h
|
||||
src/s3bucketreader.cpp src/s3bucketreader.h
|
||||
src/RESTAPI_newFirmwareAvailable.cpp src/RESTAPI_newFirmwareAvailable.h
|
||||
src/ManifestCreator.cpp src/ManifestCreator.h
|
||||
src/KafkaManager.cpp src/KafkaManager.h
|
||||
src/MicroService.h src/MicroService.cpp
|
||||
@@ -61,8 +74,13 @@ add_executable( ucentralfms
|
||||
src/OpenAPIRequest.h src/OpenAPIRequest.cpp
|
||||
src/RESTAPI_InternalServer.cpp src/RESTAPI_InternalServer.h
|
||||
src/RESTAPI_utils.cpp src/RESTAPI_utils.h
|
||||
)
|
||||
src/RESTAPI_FMSObjects.cpp src/RESTAPI_FMSObjects.h
|
||||
src/storage_firmwares.h src/storage_history.cpp
|
||||
src/storage_history.h src/storage_deviceTypes.cpp src/storage_deviceTypes.h)
|
||||
|
||||
target_link_libraries(ucentralfms PUBLIC
|
||||
${Poco_LIBRARIES} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${AWSSDK_LINK_LIBRARIES} CppKafka::cppkafka )
|
||||
${Poco_LIBRARIES} ${MySQL_LIBRARIES}
|
||||
${ODBC_LIBRARIES} ${Boost_LIBRARIES}
|
||||
${ZLIB_LIBRARIES} ${AWSSDK_LINK_LIBRARIES}
|
||||
CppKafka::cppkafka )
|
||||
|
||||
|
||||
57
cmake/CppKafkaConfig.cmake
Normal file
57
cmake/CppKafkaConfig.cmake
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
|
||||
####### Any changes to this file will be overwritten by the next CMake run ####
|
||||
####### The input file was config.cmake.in ########
|
||||
|
||||
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
|
||||
|
||||
macro(set_and_check _var _file)
|
||||
set(${_var} "${_file}")
|
||||
if(NOT EXISTS "${_file}")
|
||||
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(check_required_components _NAME)
|
||||
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||
if(NOT ${_NAME}_${comp}_FOUND)
|
||||
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
####################################################################################
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
# Add FindRdKafka.cmake
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
set(RDKAFKA_MIN_VERSION_HEX "0x00090400")
|
||||
|
||||
# Find boost optional
|
||||
find_dependency(Boost REQUIRED)
|
||||
|
||||
# Try to find the RdKafka configuration file if present.
|
||||
# This will search default system locations as well as RdKafka_ROOT and RdKafka_DIR paths if specified.
|
||||
find_package(RdKafka QUIET CONFIG)
|
||||
set(RDKAFKA_TARGET_IMPORTS ${RdKafka_FOUND})
|
||||
if (NOT RdKafka_FOUND)
|
||||
find_dependency(RdKafka REQUIRED MODULE)
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CppKafkaTargets.cmake")
|
||||
|
||||
# Export 'CppKafka_ROOT'
|
||||
set_and_check(CppKafka_ROOT "${PACKAGE_PREFIX_DIR}")
|
||||
|
||||
# Export 'CppKafka_INSTALL_INCLUDE_DIR'
|
||||
set_and_check(CppKafka_INSTALL_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")
|
||||
|
||||
# Export 'CppKafka_INSTALL_LIB_DIR'
|
||||
set_and_check(CppKafka_INSTALL_LIB_DIR "${PACKAGE_PREFIX_DIR}/lib")
|
||||
|
||||
# Validate installed components
|
||||
check_required_components("CppKafka")
|
||||
133
cmake/FindMySQL.cmake
Normal file
133
cmake/FindMySQL.cmake
Normal file
@@ -0,0 +1,133 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#.rst:
|
||||
# FindMySQL
|
||||
# -------
|
||||
#
|
||||
# Find MySQL Runtime
|
||||
#
|
||||
# This will define the following variables::
|
||||
#
|
||||
# MYSQL_FOUND - True if the system has the libraries
|
||||
# MYSQL_INCLUDE_DIRS - where to find the headers
|
||||
# MYSQL_LIBRARIES - where to find the libraries
|
||||
# MYSQL_DEFINITIONS - compile definitons
|
||||
#
|
||||
# Hints:
|
||||
# Set ``MYSQL_ROOT_DIR`` to the root directory of an installation.
|
||||
#
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(PC_MYSQL QUIET mysqlclient)
|
||||
pkg_check_modules(PC_MARIADB QUIET mariadb)
|
||||
|
||||
SET(BINDIR32_ENV_NAME "ProgramFiles(x86)")
|
||||
SET(BINDIR32 $ENV{${BINDIR32_ENV_NAME}})
|
||||
|
||||
find_path(MYSQL_INCLUDE_DIR mysql/mysql.h
|
||||
HINTS
|
||||
${MYSQL_ROOT_DIR}/include
|
||||
${MYSQL_ROOT_INCLUDE_DIRS}
|
||||
PATHS
|
||||
${PC_MYSQL_INCLUDE_DIRS}
|
||||
${PC_MARIADB_INCLUDE_DIRS}
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/mysql/mysql/include
|
||||
/usr/local/mysql/include
|
||||
$ENV{MYSQL_INCLUDE_DIR}
|
||||
$ENV{MYSQL_DIR}/include
|
||||
$ENV{ProgramFiles}/MySQL/*/include
|
||||
${BINDIR32}/MySQL/*/include
|
||||
$ENV{SystemDrive}/MySQL/*/include
|
||||
$ENV{MARIADB_INCLUDE_DIR}
|
||||
$ENV{MARIADB_DIR}/include
|
||||
${MARIADB_INCLUDE_DIR}
|
||||
${MARIADB_DIR}/include
|
||||
PATH_SUFFIXES
|
||||
mysql
|
||||
mariadb
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
set(libsuffixDist debug)
|
||||
set(libsuffixBuild Debug)
|
||||
else (CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
set(libsuffixDist opt)
|
||||
set(libsuffixBuild Release)
|
||||
set(WIN_MYSQL_DEFINITONS " -DDBUG_OFF")
|
||||
endif (CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
|
||||
find_library(MYSQL_LIBRARY NAMES mysqlclient
|
||||
HINTS
|
||||
${MYSQL_ROOT_DIR}/lib
|
||||
${MYSQL_ROOT_LIBRARY_DIRS}
|
||||
PATHS
|
||||
${PC_MYSQL_LIBRARY_DIRS}
|
||||
${PC_MARIADB_LIBRARY_DIRS}
|
||||
$ENV{MYSQL_DIR}/lib
|
||||
$ENV{MYSQL_DIR}/libmysql
|
||||
$ENV{MYSQL_DIR}/client
|
||||
$ENV{ProgramFiles}/MySQL/*/lib
|
||||
${BINDIR32}/MySQL/*/lib
|
||||
$ENV{SystemDrive}/MySQL/*/lib
|
||||
PATH_SUFFIXES
|
||||
vs12
|
||||
vs11
|
||||
vs10
|
||||
${libsuffixDist}
|
||||
${libsuffixBuild}
|
||||
)
|
||||
else()
|
||||
find_library(MYSQL_LIBRARY NAMES mysqlclient mysqlclient_r mariadbclient
|
||||
HINTS
|
||||
${MYSQL_ROOT_DIR}/lib
|
||||
${MYSQL_ROOT_LIBRARY_DIRS}
|
||||
PATHS
|
||||
${PC_MYSQL_LIBRARY_DIRS}
|
||||
${PC_MARIADB_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/usr/local/mysql/lib
|
||||
/opt/mysql/mysql/lib
|
||||
$ENV{MYSQL_DIR}/libmysql_r/.libs
|
||||
$ENV{MYSQL_DIR}/lib
|
||||
${MYSQL_DIR}/lib
|
||||
PATH_SUFFIXES
|
||||
mysql
|
||||
mariadb
|
||||
)
|
||||
endif()
|
||||
|
||||
set(MYSQL_VERSION ${PC_MYSQL_VERSION})
|
||||
|
||||
find_package_handle_standard_args(MySQL
|
||||
FOUND_VAR MYSQL_FOUND
|
||||
REQUIRED_VARS
|
||||
MYSQL_INCLUDE_DIR
|
||||
MYSQL_LIBRARY
|
||||
VERSION_VAR MYSQL_VERSION
|
||||
)
|
||||
|
||||
if(MYSQL_FOUND)
|
||||
set(MYSQL_LIBRARIES ${MYSQL_LIBRARY})
|
||||
set(MYSQL_INCLUDE_DIRS ${MYSQL_INCLUDE_DIR})
|
||||
set(MYSQL_DEFINITIONS "${PC_MYSQL_CFLAGS_OTHER}${WIN_MYSQL_DEFINITONS}")
|
||||
endif()
|
||||
|
||||
if(MYSQL_FOUND AND NOT TARGET MySQL::client)
|
||||
add_library(MySQL::client UNKNOWN IMPORTED)
|
||||
set_target_properties(MySQL::client PROPERTIES
|
||||
IMPORTED_LOCATION "${MYSQL_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_MYSQL_CFLAGS_OTHER}${WIN_MYSQL_DEFINITONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${MYSQL_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
MYSQL_LIBRARY
|
||||
MYSQL_INCLUDE_DIR
|
||||
)
|
||||
212
cmake/FindPostgreSQL.cmake
Normal file
212
cmake/FindPostgreSQL.cmake
Normal file
@@ -0,0 +1,212 @@
|
||||
# TODO(Bjoe) This is taken from cmake 3.10. For poco we need some changes here. Maybe we create an issue on cmake project
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#.rst:
|
||||
# FindPostgreSQL
|
||||
# --------------
|
||||
#
|
||||
# Find the PostgreSQL installation.
|
||||
#
|
||||
# This module defines
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# PostgreSQL_LIBRARIES - the PostgreSQL libraries needed for linking
|
||||
# PostgreSQL_INCLUDE_DIRS - the directories of the PostgreSQL headers
|
||||
# PostgreSQL_LIBRARY_DIRS - the link directories for PostgreSQL libraries
|
||||
# PostgreSQL_VERSION - the version of PostgreSQL found (since CMake 2.8.8)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# History:
|
||||
# This module is derived from the module originally found in the VTK source tree.
|
||||
#
|
||||
# ----------------------------------------------------------------------------
|
||||
# Note:
|
||||
# PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the
|
||||
# version mumber of the implementation of PostgreSQL.
|
||||
# In Windows the default installation of PostgreSQL uses that as part of the path.
|
||||
# E.g C:\Program Files\PostgreSQL\8.4.
|
||||
# Currently, the following version numbers are known to this module:
|
||||
# "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0"
|
||||
#
|
||||
# To use this variable just do something like this:
|
||||
# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4")
|
||||
# before calling find_package(PostgreSQL) in your CMakeLists.txt file.
|
||||
# This will mean that the versions you set here will be found first in the order
|
||||
# specified before the default ones are searched.
|
||||
#
|
||||
# ----------------------------------------------------------------------------
|
||||
# You may need to manually set:
|
||||
# PostgreSQL_ROOT_DIR - that points to the root of where you have installed PostgreSQL
|
||||
# PostgreSQL_INCLUDE_DIR - the path to where the PostgreSQL include files are.
|
||||
# PostgreSQL_LIBRARY_DIR - The path to where the PostgreSQL library files are.
|
||||
# If FindPostgreSQL.cmake cannot find the include files or the library files.
|
||||
#
|
||||
# ----------------------------------------------------------------------------
|
||||
# The following variables are set if PostgreSQL is found:
|
||||
# PostgreSQL_FOUND - Set to true when PostgreSQL is found.
|
||||
# PostgreSQL_INCLUDE_DIRS - Include directories for PostgreSQL
|
||||
# PostgreSQL_LIBRARY_DIRS - Link directories for PostgreSQL libraries
|
||||
# PostgreSQL_LIBRARIES - The PostgreSQL libraries.
|
||||
#
|
||||
# ----------------------------------------------------------------------------
|
||||
# If you have installed PostgreSQL in a non-standard location.
|
||||
# (Please note that in the following comments, it is assumed that <Your Path>
|
||||
# points to the root directory of the include directory of PostgreSQL.)
|
||||
# Then you have three options.
|
||||
# 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to <Your Path>/include and
|
||||
# PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is
|
||||
# 2) Use CMAKE_INCLUDE_PATH to set a path to <Your Path>/PostgreSQL<-version>. This will allow find_path()
|
||||
# to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file
|
||||
# set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "<Your Path>/include")
|
||||
# 3) Set an environment variable called ${PostgreSQL_ROOT} / ${PostgreSQL_ROOT_DIR} that points to the root of where you have
|
||||
# installed PostgreSQL, e.g. <Your Path>.
|
||||
#
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include")
|
||||
set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}")
|
||||
set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.")
|
||||
set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}")
|
||||
set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4")
|
||||
|
||||
|
||||
set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS}
|
||||
"10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
|
||||
|
||||
# Define additional search paths for root directories.
|
||||
set(PostgreSQL_ROOT_DIRECTORIES
|
||||
ENV PostgreSQL_ROOT
|
||||
${PostgreSQL_ROOT}
|
||||
${PostgreSQL_ROOT_DIR}
|
||||
)
|
||||
foreach(suffix ${PostgreSQL_KNOWN_VERSIONS})
|
||||
if(WIN32)
|
||||
list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES
|
||||
"PostgreSQL/${suffix}/lib")
|
||||
list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
|
||||
"PostgreSQL/${suffix}/include")
|
||||
list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES
|
||||
"PostgreSQL/${suffix}/include/server")
|
||||
endif()
|
||||
if(UNIX)
|
||||
list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES
|
||||
"pgsql-${suffix}/lib")
|
||||
list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
|
||||
"pgsql-${suffix}/include")
|
||||
list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES
|
||||
"postgresql/${suffix}/server"
|
||||
"pgsql-${suffix}/include/server")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(UNIX)
|
||||
list(APPEND PostgreSQL_ROOT_DIRECTORIES
|
||||
"/usr")
|
||||
list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
|
||||
"include/postgresql")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Look for an installation.
|
||||
#
|
||||
find_path(PostgreSQL_INCLUDE_DIR
|
||||
NAMES libpq-fe.h
|
||||
HINTS
|
||||
${PostgreSQL_ROOT_INCLUDE_DIRS}
|
||||
PATHS
|
||||
# Look in other places.
|
||||
${PostgreSQL_ROOT_DIRECTORIES}
|
||||
PATH_SUFFIXES
|
||||
pgsql
|
||||
postgresql
|
||||
include
|
||||
${PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES}
|
||||
# Help the user find it if we cannot.
|
||||
DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
|
||||
)
|
||||
|
||||
# TODO(Bjoe) It is not needed to build an PostgreSQL client. Maybe create an issue on cmake project
|
||||
# find_path(PostgreSQL_TYPE_INCLUDE_DIR
|
||||
# NAMES catalog/pg_type.h
|
||||
# PATHS
|
||||
# # Look in other places.
|
||||
# ${PostgreSQL_ROOT_DIRECTORIES}
|
||||
# PATH_SUFFIXES
|
||||
# postgresql
|
||||
# pgsql/server
|
||||
# postgresql/server
|
||||
# include/server
|
||||
# ${PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES}
|
||||
# # Help the user find it if we cannot.
|
||||
# DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
|
||||
# )
|
||||
|
||||
# The PostgreSQL library.
|
||||
set(PostgreSQL_LIBRARY_TO_FIND pq)
|
||||
# Setting some more prefixes for the library
|
||||
set(PostgreSQL_LIB_PREFIX "")
|
||||
if(WIN32)
|
||||
set(PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib")
|
||||
set(PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND})
|
||||
endif()
|
||||
|
||||
find_library(PostgreSQL_LIBRARY
|
||||
NAMES ${PostgreSQL_LIBRARY_TO_FIND}
|
||||
HINTS
|
||||
${PostgreSQL_ROOT_LIBRARY_DIRS}
|
||||
PATHS
|
||||
${PostgreSQL_ROOT_DIRECTORIES}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
${PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES}
|
||||
# Help the user find it if we cannot.
|
||||
DOC "The ${PostgreSQL_LIBRARY_DIR_MESSAGE}"
|
||||
)
|
||||
get_filename_component(PostgreSQL_LIBRARY_DIR ${PostgreSQL_LIBRARY} PATH)
|
||||
|
||||
if(PostgreSQL_INCLUDE_DIR)
|
||||
# Some platforms include multiple pg_config.hs for multi-lib configurations
|
||||
# This is a temporary workaround. A better solution would be to compile
|
||||
# a dummy c file and extract the value of the symbol.
|
||||
file(GLOB _PG_CONFIG_HEADERS "${PostgreSQL_INCLUDE_DIR}/pg_config*.h")
|
||||
foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS})
|
||||
if(EXISTS "${_PG_CONFIG_HEADER}")
|
||||
file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str
|
||||
REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"")
|
||||
if(pgsql_version_str)
|
||||
string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*"
|
||||
"\\1" PostgreSQL_VERSION "${pgsql_version_str}")
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
unset(pgsql_version_str)
|
||||
endif()
|
||||
|
||||
# Did we find anything?
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
PostgreSQL
|
||||
REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR #PostgreSQL_TYPE_INCLUDE_DIR
|
||||
VERSION_VAR PostgreSQL_VERSION
|
||||
)
|
||||
set(PostgreSQL_FOUND ${POSTGRESQL_FOUND})
|
||||
|
||||
# Now try to get the include and library path.
|
||||
if(PostgreSQL_FOUND)
|
||||
set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR} ) #${PostgreSQL_TYPE_INCLUDE_DIR} )
|
||||
set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR} )
|
||||
set(PostgreSQL_LIBRARIES ${PostgreSQL_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(PostgreSQL_FOUND AND NOT TARGET PostgreSQL::PostgreSQL)
|
||||
add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED)
|
||||
set_target_properties(PostgreSQL::PostgreSQL PROPERTIES
|
||||
IMPORTED_LOCATION "${PostgreSQL_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_LIBRARY ) #PostgreSQL_TYPE_INCLUDE_DIR
|
||||
73
cmake/FindRdKafka.cmake
Normal file
73
cmake/FindRdKafka.cmake
Normal file
@@ -0,0 +1,73 @@
|
||||
# This find module helps find the RdKafka module. It exports the following variables:
|
||||
# - RdKafka_INCLUDE_DIR : The directory where rdkafka.h is located.
|
||||
# - RdKafka_LIBNAME : The name of the library, i.e. librdkafka.a, librdkafka.so, etc.
|
||||
# - RdKafka_LIBRARY_PATH : The full library path i.e. <path_to_binaries>/${RdKafka_LIBNAME}
|
||||
# - RdKafka::rdkafka : Imported library containing all above properties set.
|
||||
|
||||
if (CPPKAFKA_RDKAFKA_STATIC_LIB)
|
||||
set(RDKAFKA_PREFIX ${CMAKE_STATIC_LIBRARY_PREFIX})
|
||||
set(RDKAFKA_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set(RDKAFKA_LIBRARY_TYPE STATIC)
|
||||
else()
|
||||
set(RDKAFKA_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX})
|
||||
set(RDKAFKA_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
set(RDKAFKA_LIBRARY_TYPE SHARED)
|
||||
endif()
|
||||
|
||||
set(RdKafka_LIBNAME ${RDKAFKA_PREFIX}rdkafka${RDKAFKA_SUFFIX})
|
||||
|
||||
find_path(RdKafka_INCLUDE_DIR
|
||||
NAMES librdkafka/rdkafka.h
|
||||
HINTS ${RdKafka_ROOT}/include
|
||||
)
|
||||
|
||||
find_library(RdKafka_LIBRARY_PATH
|
||||
NAMES ${RdKafka_LIBNAME} rdkafka
|
||||
HINTS ${RdKafka_ROOT}/lib ${RdKafka_ROOT}/lib64
|
||||
)
|
||||
|
||||
# Check lib paths
|
||||
if (CPPKAFKA_CMAKE_VERBOSE)
|
||||
get_property(FIND_LIBRARY_32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS)
|
||||
get_property(FIND_LIBRARY_64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
|
||||
message(STATUS "RDKAFKA search 32-bit library paths: ${FIND_LIBRARY_32}")
|
||||
message(STATUS "RDKAFKA search 64-bit library paths: ${FIND_LIBRARY_64}")
|
||||
message(STATUS "RdKafka_ROOT = ${RdKafka_ROOT}")
|
||||
message(STATUS "RdKafka_INCLUDE_DIR = ${RdKafka_INCLUDE_DIR}")
|
||||
message(STATUS "RdKafka_LIBNAME = ${RdKafka_LIBNAME}")
|
||||
message(STATUS "RdKafka_LIBRARY_PATH = ${RdKafka_LIBRARY_PATH}")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(RdKafka DEFAULT_MSG
|
||||
RdKafka_LIBNAME
|
||||
RdKafka_LIBRARY_PATH
|
||||
RdKafka_INCLUDE_DIR
|
||||
)
|
||||
|
||||
set(CONTENTS "#include <librdkafka/rdkafka.h>\n #if RD_KAFKA_VERSION >= ${RDKAFKA_MIN_VERSION_HEX}\n int main() { }\n #endif")
|
||||
set(FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/rdkafka_version_test.cpp)
|
||||
file(WRITE ${FILE_NAME} ${CONTENTS})
|
||||
|
||||
try_compile(RdKafka_FOUND ${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES ${FILE_NAME}
|
||||
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${RdKafka_INCLUDE_DIR}")
|
||||
|
||||
if (RdKafka_FOUND)
|
||||
add_library(RdKafka::rdkafka ${RDKAFKA_LIBRARY_TYPE} IMPORTED GLOBAL)
|
||||
set(RDKAFKA_DEPENDENCIES pthread)
|
||||
# set(RDKAFKA_DEPENDENCIES pthread rt crypto dl z)
|
||||
set_target_properties(RdKafka::rdkafka PROPERTIES
|
||||
IMPORTED_NAME RdKafka
|
||||
IMPORTED_LOCATION "${RdKafka_LIBRARY_PATH}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${RdKafka_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${RDKAFKA_DEPENDENCIES}")
|
||||
message(STATUS "Found valid rdkafka version")
|
||||
mark_as_advanced(
|
||||
RDKAFKA_LIBRARY
|
||||
RdKafka_INCLUDE_DIR
|
||||
RdKafka_LIBRARY_PATH
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "Failed to find valid rdkafka version")
|
||||
endif()
|
||||
@@ -2,7 +2,7 @@ openapi: 3.0.1
|
||||
info:
|
||||
title: uCentral Firmware Service API
|
||||
description: A process to manage new uCentral firmware distribution.
|
||||
version: 0.0.2
|
||||
version: 0.1.0
|
||||
license:
|
||||
name: BSD3
|
||||
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
@@ -11,7 +11,7 @@ info:
|
||||
url: https://www.ucentral.info/support
|
||||
|
||||
servers:
|
||||
- url: 'https://localhost:15055/api/v1'
|
||||
- url: 'https://localhost:16003/api/v1'
|
||||
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
@@ -74,8 +74,8 @@ components:
|
||||
description: Definition of a firmware release
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
deviceType:
|
||||
type: string
|
||||
description:
|
||||
@@ -110,7 +110,9 @@ components:
|
||||
latest:
|
||||
type: boolean
|
||||
notes:
|
||||
type: string
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/NoteInfo'
|
||||
created:
|
||||
type: integer
|
||||
format: int64
|
||||
@@ -127,8 +129,8 @@ components:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
deviceType:
|
||||
type: string
|
||||
manufacturer:
|
||||
@@ -138,7 +140,9 @@ components:
|
||||
policy:
|
||||
type: string
|
||||
notes:
|
||||
type: string
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/NoteInfo'
|
||||
lastUpdate:
|
||||
type: integer
|
||||
format: int64
|
||||
@@ -154,44 +158,12 @@ components:
|
||||
items:
|
||||
$ref: '#/components/schemas/DeviceType'
|
||||
|
||||
DeviceEntry:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
campaignId:
|
||||
type: integer
|
||||
format: int64
|
||||
serialNumber:
|
||||
type: string
|
||||
commandUUID:
|
||||
type: string
|
||||
format: uuid
|
||||
runAt:
|
||||
type: integer
|
||||
format: int64
|
||||
submitted:
|
||||
type: integer
|
||||
format: int64
|
||||
completed:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
DeviceEntryList:
|
||||
type: object
|
||||
properties:
|
||||
deviceEntries:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/DeviceEntry'
|
||||
|
||||
RevisionHistoryEntry:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
serialNumber:
|
||||
type: string
|
||||
revisionId:
|
||||
@@ -207,78 +179,11 @@ components:
|
||||
RevisionHistoryEntryList:
|
||||
type: object
|
||||
properties:
|
||||
entries:
|
||||
history:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RevisionHistoryEntry'
|
||||
|
||||
Campaign:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
started:
|
||||
type: integer
|
||||
format: int64
|
||||
canceled:
|
||||
type: integer
|
||||
format: int64
|
||||
startDate:
|
||||
type: integer
|
||||
format: int64
|
||||
schedule:
|
||||
type: string
|
||||
completed:
|
||||
type: integer
|
||||
format: int64
|
||||
deviceCount:
|
||||
type: integer
|
||||
completedDevices:
|
||||
type: integer
|
||||
submittedDevices:
|
||||
type: integer
|
||||
notes:
|
||||
type: string
|
||||
lastUpdate:
|
||||
type: integer
|
||||
format: int64
|
||||
created:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
CampaignList:
|
||||
type: object
|
||||
properties:
|
||||
campaigns:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Campaign'
|
||||
|
||||
GenericErrorResponse:
|
||||
description: Typical error response
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
GenericGoodAnswer:
|
||||
description: used for all succesful responses.
|
||||
properties:
|
||||
Operation:
|
||||
type: string
|
||||
Details:
|
||||
type: string
|
||||
Code:
|
||||
type: integer
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## These are endpoints that all services in the uCentral stack must provide
|
||||
@@ -335,11 +240,23 @@ components:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/StringList'
|
||||
- $ref: '#/components/schemas/TagValuePairList'
|
||||
#########################################################################################
|
||||
##
|
||||
## End of uCentral system wide values
|
||||
##
|
||||
#########################################################################################
|
||||
|
||||
NoteInfo:
|
||||
type: object
|
||||
properties:
|
||||
created:
|
||||
type: integer
|
||||
format: int64
|
||||
createdBy:
|
||||
type: string
|
||||
note:
|
||||
type: string
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## End of uCentral system wide values
|
||||
##
|
||||
#########################################################################################
|
||||
|
||||
paths:
|
||||
/firmwares:
|
||||
@@ -374,6 +291,11 @@ paths:
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
name: deviceType
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: List firmwares
|
||||
@@ -397,8 +319,8 @@ paths:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
@@ -421,8 +343,8 @@ paths:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -451,8 +373,8 @@ paths:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
requestBody:
|
||||
description: Firmware details
|
||||
@@ -482,8 +404,8 @@ paths:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
@@ -491,7 +413,7 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericGoodAnswer'
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
@@ -545,8 +467,8 @@ paths:
|
||||
description: ID of deviceType to retrieve
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
@@ -570,8 +492,8 @@ paths:
|
||||
description: ID of deviceType to retrieve
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
@@ -591,8 +513,8 @@ paths:
|
||||
description: ID of deviceType to modify
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
requestBody:
|
||||
description: Modifications for the DeviceType
|
||||
@@ -655,265 +577,6 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/campaigns:
|
||||
get:
|
||||
tags:
|
||||
- Campaign
|
||||
summary: List all cmapaigns
|
||||
operationId: getCampaigns
|
||||
parameters:
|
||||
- in: query
|
||||
description: Pagination start (starts at 1. If not specified, 1 is assumed)
|
||||
name: offset
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
- in: query
|
||||
description: Maximum number of entries to return (if absent, no limit is assumed)
|
||||
name: limit
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
- in: query
|
||||
description: Maximum number of entries to return (if absent, no limit is assumed)
|
||||
name: startDate
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
- in: query
|
||||
description: Maximum number of entries to return (if absent, no limit is assumed)
|
||||
name: endDate
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
- in: query
|
||||
description: Filter the results
|
||||
name: filter
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
|
||||
responses:
|
||||
200:
|
||||
description: List of campaigns.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CampaignList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/campaign/{id}:
|
||||
get:
|
||||
tags:
|
||||
- Campaign
|
||||
summary: Get a single campaign definition
|
||||
operationId: getCampaign
|
||||
parameters:
|
||||
- in: path
|
||||
description: ID of the campaign
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/Campaign'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- Campaign
|
||||
summary: Delete a single campaign definition
|
||||
operationId: deleteCampaign
|
||||
parameters:
|
||||
- in: path
|
||||
description: ID of the campaign
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
post:
|
||||
tags:
|
||||
- Campaign
|
||||
summary: Create a single campaign definition
|
||||
operationId: createCampaign
|
||||
parameters:
|
||||
- in: path
|
||||
description: ID of the campaign
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
requestBody:
|
||||
description: Canpaign creation details
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Campaign'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/Campaign'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- Campaign
|
||||
summary: Create a single campaign definition
|
||||
operationId: updateCampaign
|
||||
parameters:
|
||||
- in: path
|
||||
description: ID of the campaign
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
requestBody:
|
||||
description: Canpaign modification details
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Campaign'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/Campaign'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/campaign/{id}/entries:
|
||||
get:
|
||||
tags:
|
||||
- Campaign
|
||||
summary: List all campaign entries
|
||||
operationId: getCampaignEntries
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
- in: query
|
||||
description: Pagination start (starts at 1. If not specified, 1 is assumed)
|
||||
name: offset
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
- in: query
|
||||
description: Maximum number of entries to return (if absent, no limit is assumed)
|
||||
name: limit
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
- in: query
|
||||
description: Maximum number of entries to return (if absent, no limit is assumed)
|
||||
name: startDate
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
- in: query
|
||||
description: Maximum number of entries to return (if absent, no limit is assumed)
|
||||
name: endDate
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
- in: query
|
||||
description: Filter the results
|
||||
name: filter
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/DeviceEntryList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/campaign/{id}/entry/{serialNumber}:
|
||||
post:
|
||||
tags:
|
||||
- Campaign
|
||||
operationId: createSingleEntry
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DeviceEntryList'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/DeviceEntryList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- Campaign
|
||||
operationId: deleteSingleEntry
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## These are endpoints that all services in the uCentral stack must provide
|
||||
@@ -944,51 +607,3 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/callbackChannel:
|
||||
post:
|
||||
tags:
|
||||
- Callback
|
||||
summary: Generic callback hook
|
||||
operationId: postCallback
|
||||
parameters:
|
||||
- in: query
|
||||
name: subscribe
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
name: uri
|
||||
schema:
|
||||
type: string
|
||||
format: uri
|
||||
- in: query
|
||||
name: key
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: topics
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: topic
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
description: A generic JSONDocument, may be empty too {}
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AnyPayload'
|
||||
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "StorageService.h"
|
||||
#include "RESTAPI_server.h"
|
||||
#include "RESTAPI_InternalServer.h"
|
||||
#include "NotificationMgr.h"
|
||||
#include "ManifestCreator.h"
|
||||
#include "ALBHealthCheckServer.h"
|
||||
#include "KafkaManager.h"
|
||||
@@ -37,7 +36,6 @@ namespace uCentral {
|
||||
Types::SubSystemVec{Storage(),
|
||||
RESTAPI_server(),
|
||||
RESTAPI_InternalServer(),
|
||||
NotificationMgr(),
|
||||
ManifestCreator()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-10.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Stringifier.h"
|
||||
|
||||
#include <aws/core/Aws.h>
|
||||
#include <aws/s3/S3Client.h>
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
#include <aws/s3/model/CreateBucketRequest.h>
|
||||
#include <aws/s3/model/PutObjectRequest.h>
|
||||
#include <aws/s3/model/Owner.h>
|
||||
#include <aws/s3/model/AccessControlPolicy.h>
|
||||
#include <aws/s3/model/PutBucketAclRequest.h>
|
||||
#include <aws/s3/model/GetBucketAclRequest.h>
|
||||
|
||||
#include "FWManager.h"
|
||||
#include "Daemon.h"
|
||||
#include "NotificationMgr.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTAPI_objects.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace uCentral::FWManager {
|
||||
Service *Service::instance_ = nullptr;
|
||||
|
||||
int Start() {
|
||||
return Service::instance()->Start();
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
Service::instance()->Stop();
|
||||
}
|
||||
|
||||
bool AddJob(const std::string &UUID, const uCentral::Auth::APIKeyEntry & Entry) {
|
||||
return Service::instance()->AddJob(UUID, Entry);
|
||||
}
|
||||
|
||||
Service::Service() noexcept:
|
||||
uSubSystemServer("FirmwareMgr", "FWR-MGR", "firmwaremgr")
|
||||
{
|
||||
}
|
||||
|
||||
int Service::Start() {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
S3BucketName_ = uCentral::ServiceConfig::GetString("s3.bucketname");
|
||||
S3Region_ = uCentral::ServiceConfig::GetString("s3.region");
|
||||
S3Secret_ = uCentral::ServiceConfig::GetString("s3.secret");
|
||||
S3Key_ = uCentral::ServiceConfig::GetString("s3.key");
|
||||
S3Retry_ = uCentral::ServiceConfig::GetInt("s3.retry",60);
|
||||
AwsConfig_ = Aws::MakeUnique<Aws::Client::ClientConfiguration>("fws");
|
||||
if(!S3Region_.empty())
|
||||
AwsConfig_->region = S3Region_;
|
||||
AwsCreds_ = Aws::MakeUnique<Aws::Auth::AWSCredentials>("fws");
|
||||
AwsCreds_->SetAWSAccessKeyId(S3Key_.c_str());
|
||||
AwsCreds_->SetAWSSecretKey(S3Secret_.c_str());
|
||||
S3Client_ = Aws::MakeUnique<Aws::S3::S3Client>("fws",*AwsCreds_,*AwsConfig_);
|
||||
Logger_.information("Starting ");
|
||||
Worker_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Service::Stop() {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
Logger_.information("Stopping ");
|
||||
Running_ = false;
|
||||
Worker_.join();
|
||||
|
||||
/*delete S3Client_;
|
||||
delete AwsCreds_;
|
||||
delete AwsConfig_;*/
|
||||
}
|
||||
|
||||
void Service::run() {
|
||||
|
||||
Running_ = true;
|
||||
|
||||
// const std::string & Path = uCentral::uFileUploader::Path();
|
||||
std::string Path;
|
||||
|
||||
auto Uploads=0;
|
||||
|
||||
while(Running_) {
|
||||
bool RemoveJob = false;
|
||||
|
||||
if(Jobs_.empty()) {
|
||||
if (Uploads!=0) {
|
||||
uCentral::NotificationMgr::Update();
|
||||
Uploads = 0;
|
||||
}
|
||||
Poco::Thread::sleep(10000);
|
||||
} else {
|
||||
JobId JobEntry;
|
||||
{
|
||||
SubMutexGuard G(Mutex_);
|
||||
JobEntry = Jobs_.front();
|
||||
}
|
||||
|
||||
try {
|
||||
Poco::File JSONFileName(Path + "/" + JobEntry.UUID + "/latest-upgrade.json");
|
||||
|
||||
if (JSONFileName.exists() && JSONFileName.isFile()) {
|
||||
std::ifstream in(JSONFileName.path(),std::ios_base::in);
|
||||
|
||||
Poco::JSON::Parser parser;
|
||||
Poco::JSON::Object::Ptr Obj = parser.parse(in).extract<Poco::JSON::Object::Ptr>();
|
||||
Poco::DynamicStruct ds = *Obj;
|
||||
in.close();
|
||||
|
||||
if( ds.contains("image") && ds.contains("compatible")
|
||||
&& ds.contains("revision") && ds.contains("timestamp")) {
|
||||
|
||||
// let's see if the image file exists
|
||||
std::string ImageName{ds["image"].toString()};
|
||||
Poco::File ImageFileName(Path + "/" + JobEntry.UUID + "/" + ImageName);
|
||||
if(ImageFileName.exists() && ImageFileName.isFile()) {
|
||||
Poco::File JSONRealFileName{ ImageFileName.path() + ".json"};
|
||||
std::string JSONObjectName{ImageName+".json"};
|
||||
JSONFileName.copyTo(JSONRealFileName.path());
|
||||
Logger_.information(Poco::format("JOB(%s): Processing...",JobEntry.UUID));
|
||||
if(SendToS3(JSONObjectName, JSONRealFileName.path(),
|
||||
ImageName, ImageFileName.path())) {
|
||||
RemoveJob = true;
|
||||
// create the new firmware entry
|
||||
uCentral::Objects::Firmware F;
|
||||
|
||||
F.UUID = uCentral::instance()->CreateUUID();
|
||||
F.Owner = JobEntry.Entry.Owner;
|
||||
F.FirmwareDate = ds["timestamp"];
|
||||
F.Size = ImageFileName.getSize();
|
||||
F.DownloadCount = 0;
|
||||
F.Uploaded = time(nullptr);
|
||||
F.Compatible = ds["compatible"].toString();
|
||||
F.FirmwareVersion = ds["revision"].toString();
|
||||
F.FirmwareFileName = ds["image"].toString();
|
||||
F.Uploader = JobEntry.Entry.Description;
|
||||
F.S3URI = "https://s3-" + S3Region_ + ".amazonaws.com/" + S3BucketName_ + "/" + ImageName;
|
||||
F.Latest = 1;
|
||||
|
||||
if(uCentral::Storage::AddFirmware(F)) {
|
||||
Logger_.information(
|
||||
Poco::format("JOB(%s): Added to firmware DB.", JobEntry.UUID));
|
||||
RemoveJob = true;
|
||||
Uploads++;
|
||||
} else {
|
||||
Logger_.error(Poco::format("JOB(%s): Could not add the DB entry.",JobEntry.UUID));
|
||||
}
|
||||
} else {
|
||||
RemoveJob = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
RemoveJob = true;
|
||||
Logger_.information(Poco::format("JOB(%s): Missing image file %s",JobEntry.UUID,ImageFileName.path()));
|
||||
}
|
||||
|
||||
} else {
|
||||
Logger_.information(Poco::format("JOB(%s): missing some JSON field(s).",JobEntry.UUID));
|
||||
RemoveJob = true;
|
||||
}
|
||||
} else {
|
||||
Logger_.information(Poco::format("JOB(%s): No JSON document.",JobEntry.UUID));
|
||||
RemoveJob = true;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
RemoveJob = true;
|
||||
}
|
||||
|
||||
if(RemoveJob) {
|
||||
SubMutexGuard G(Mutex_);
|
||||
Jobs_.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Service::SendObjectToS3(const std::string &ObjectName, const std::string & ObjectFileName) {
|
||||
try {
|
||||
|
||||
Aws::S3::Model::PutObjectRequest Request;
|
||||
Request.SetBucket(S3BucketName_.c_str());
|
||||
Request.SetKey(ObjectName.c_str());
|
||||
Request.SetACL(Aws::S3::Model::ObjectCannedACL::public_read);
|
||||
|
||||
std::cout << "Attempting to add " << ObjectName << " to the bucket " << S3BucketName_ << " in region "
|
||||
<< S3Region_ << std::endl;
|
||||
|
||||
std::shared_ptr<Aws::IOStream> Body =
|
||||
Aws::MakeShared<Aws::FStream>(ObjectFileName.c_str(), ObjectFileName.c_str(),
|
||||
std::ios_base::in | std::ios_base::binary);
|
||||
Request.SetBody(Body);
|
||||
Aws::S3::Model::PutObjectOutcome outcome = S3Client_->PutObject(Request);
|
||||
|
||||
if (outcome.IsSuccess()) {
|
||||
Logger_.information(Poco::format("S3-UPLOADER: uploaded %s", ObjectName));
|
||||
return true;
|
||||
} else {
|
||||
Logger_.error(Poco::format("S3-UPLOADER: could not upload %s. Exception: %s. Message: %s", ObjectName,
|
||||
outcome.GetError().GetExceptionName(), outcome.GetError().GetMessage()));
|
||||
return false;
|
||||
}
|
||||
} catch (...) {
|
||||
Logger_.error("Exception while uploading to S3.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Service::SendToS3(const std::string & JSONObjectName , const std::string & JSONDocFileName,
|
||||
const std::string & ImageObjectName, const std::string & ImageFileName) {
|
||||
try {
|
||||
|
||||
if( SendObjectToS3(JSONObjectName,JSONDocFileName) &&
|
||||
SendObjectToS3(ImageObjectName,ImageFileName) ) {
|
||||
std::cout << "All objects sent..." << std::endl;
|
||||
return true;
|
||||
}
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch(...) {
|
||||
Logger_.error(Poco::format("S3 Exception while sending %s",JSONDocFileName));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Service::AddJob(const std::string &UUID, const uCentral::Auth::APIKeyEntry & Entry) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
JobId NewJob{ .UUID = UUID,
|
||||
.Entry = Entry};
|
||||
|
||||
Jobs_.push(NewJob);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -1,69 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-10.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_UFWMANAGER_H
|
||||
#define UCENTRALFWS_UFWMANAGER_H
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "SubSystemServer.h"
|
||||
#include <aws/core/Aws.h>
|
||||
#include <aws/s3/S3Client.h>
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
#include "AuthService.h"
|
||||
|
||||
namespace uCentral::FWManager {
|
||||
|
||||
int Start();
|
||||
void Stop();
|
||||
bool AddJob(const std::string &UUID, const uCentral::Auth::APIKeyEntry & Entry);
|
||||
|
||||
struct JobId {
|
||||
std::string UUID;
|
||||
uCentral::Auth::APIKeyEntry Entry;
|
||||
};
|
||||
|
||||
class Service : public uSubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
|
||||
Service() noexcept;
|
||||
|
||||
friend int Start();
|
||||
friend void Stop();
|
||||
|
||||
static Service *instance() {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ = new Service;
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
friend bool AddJob(const std::string &UUID, const uCentral::Auth::APIKeyEntry & Entry);
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
static Service *instance_;
|
||||
std::queue<JobId> Jobs_;
|
||||
Poco::Thread Worker_;
|
||||
std::atomic_bool Running_=false;
|
||||
std::string S3BucketName_;
|
||||
std::string S3Region_;
|
||||
std::string S3Key_;
|
||||
std::string S3Secret_;
|
||||
uint64_t S3Retry_;
|
||||
Aws::UniquePtr<Aws::Client::ClientConfiguration> AwsConfig_;
|
||||
Aws::UniquePtr<Aws::Auth::AWSCredentials> AwsCreds_;
|
||||
Aws::UniquePtr<Aws::S3::S3Client> S3Client_;
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
bool AddJob(const std::string &UUID, const uCentral::Auth::APIKeyEntry & Entry);
|
||||
|
||||
bool SendToS3(const std::string & JSONObjectName , const std::string & JSONDocFileName,
|
||||
const std::string & ImageObjectName, const std::string & ImageFileName);
|
||||
bool SendObjectToS3(const std::string &ObjectName, const std::string & ObjectFileName);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif //UCENTRALFWS_UFWMANAGER_H
|
||||
@@ -106,12 +106,10 @@ namespace uCentral {
|
||||
|
||||
cppkafka::Consumer Consumer(Config);
|
||||
Consumer.set_assignment_callback([this](const cppkafka::TopicPartitionList& partitions) {
|
||||
std::cout << "Partition assigned: " << partitions.front().get_partition() << std::endl;
|
||||
Logger_.information(Poco::format("Got assigned: %Lu...",(uint64_t )partitions.front().get_partition()));
|
||||
Logger_.information(Poco::format("Partition assigned: %Lu...",(uint64_t )partitions.front().get_partition()));
|
||||
});
|
||||
Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) {
|
||||
std::cout << "Partition revocation: " << partitions.front().get_partition() << std::endl;
|
||||
Logger_.information(Poco::format("Got revoked: %Lu...",(uint64_t )partitions.front().get_partition()));
|
||||
Logger_.information(Poco::format("Partition revocation: %Lu...",(uint64_t )partitions.front().get_partition()));
|
||||
});
|
||||
|
||||
Types::StringVec Topics;
|
||||
|
||||
@@ -194,6 +194,7 @@ namespace uCentral {
|
||||
DebugMode_ = ConfigGetBool("ucentral.system.debug",false);
|
||||
MyPrivateEndPoint_ = ConfigGetString("ucentral.system.uri.private");
|
||||
MyPublicEndPoint_ = ConfigGetString("ucentral.system.uri.public");
|
||||
UIURI_ = ConfigGetString("ucentral.system.uri.ui");
|
||||
MyHash_ = CreateHash(MyPublicEndPoint_);
|
||||
InitializeSubSystemServers();
|
||||
ServerApplication::initialize(self);
|
||||
|
||||
@@ -132,6 +132,8 @@ namespace uCentral {
|
||||
|
||||
void SavePID();
|
||||
inline uint64_t GetPID() { return Poco::Process::id(); };
|
||||
[[nodiscard]] inline const std::string GetPublicAPIEndPoint() const { return MyPublicEndPoint_ + "/api/v1"; };
|
||||
[[nodiscard]] inline const std::string & GetUIURI() const { return UIURI_;};
|
||||
|
||||
private:
|
||||
bool HelpRequested_ = false;
|
||||
@@ -150,6 +152,7 @@ namespace uCentral {
|
||||
std::string MyHash_;
|
||||
std::string MyPrivateEndPoint_;
|
||||
std::string MyPublicEndPoint_;
|
||||
std::string UIURI_;
|
||||
std::string Version_;
|
||||
BusEventManager BusEventManager_;
|
||||
SubMutex InfraMutex_;
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-11.
|
||||
//
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "NotificationMgr.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTAPI_objects.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/Net/HTTPSClientSession.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
#include "Poco/Net/MediaType.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
class NotificationMgr *NotificationMgr::instance_ = nullptr;
|
||||
|
||||
NotificationMgr::NotificationMgr() noexcept:
|
||||
SubSystemServer("NotificationMgr", "NOTIFY-MGR", "nodifymgr") {
|
||||
}
|
||||
|
||||
int NotificationMgr::Start() {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
Logger_.information("Starting ");
|
||||
Worker_.start(*this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NotificationMgr::Stop() {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
Logger_.information("Stopping ");
|
||||
Running_ = false;
|
||||
|
||||
Worker_.wakeUp();
|
||||
Worker_.join();
|
||||
}
|
||||
|
||||
void NotificationMgr::run() {
|
||||
|
||||
Running_ = true;
|
||||
|
||||
while (Running_) {
|
||||
Poco::Thread::trySleep(2000000000);
|
||||
|
||||
if(!Running_)
|
||||
break;
|
||||
if(!Updated_)
|
||||
continue;
|
||||
Updated_ = false;
|
||||
|
||||
if(uCentral::Storage()->FirmwareVersion()!=ManifestVersion_) {
|
||||
Poco::JSON::Object Manifest;
|
||||
|
||||
uCentral::Storage()->BuildFirmwareManifest(Manifest, ManifestVersion_);
|
||||
std::stringstream OS;
|
||||
Poco::JSON::Stringifier stringifier;
|
||||
stringifier.condense(Manifest, OS);
|
||||
CurrentManifest_ = OS.str();
|
||||
}
|
||||
|
||||
// Send it...
|
||||
NotifyCallers();
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationMgr::Update() {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
Updated_ = true;
|
||||
Worker_.wakeUp();
|
||||
}
|
||||
|
||||
void NotificationMgr::NotifyCallers() {
|
||||
|
||||
std::vector<uCentral::Objects::Callback> Callbacks;
|
||||
|
||||
std::ofstream File( "latest_manifest.json" , std::ofstream::out | std::ofstream::trunc);
|
||||
File << CurrentManifest_;
|
||||
File.close();
|
||||
|
||||
// build the list of callbacks or update the existing callers.
|
||||
if(uCentral::Storage()->GetCallbacks(0,200,Callbacks)) {
|
||||
for(const auto & i:Callbacks) {
|
||||
auto Index = EndPoints_.find(i.UUID);
|
||||
if(Index==EndPoints_.end()) {
|
||||
NotifyEndPoint E{
|
||||
.Caller = i,
|
||||
.LasContact = 0,
|
||||
.LastVersion = 0};
|
||||
EndPoints_[i.UUID] = E;
|
||||
} else {
|
||||
Index->second.Caller = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(EndPoints_.empty())
|
||||
return;
|
||||
|
||||
for(auto & host:EndPoints_) {
|
||||
if(host.second.LastVersion!=ManifestVersion_) {
|
||||
if(SendManifest(host.second.Caller)) {
|
||||
host.second.LastVersion = ManifestVersion_;
|
||||
host.second.LasContact = time(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DoRequest(Poco::Net::HTTPSClientSession& Session, Poco::Net::HTTPRequest& Request, Poco::Net::HTTPResponse& Response, const std::string & Doc)
|
||||
{
|
||||
std::stringstream Body(Doc);
|
||||
Request.setContentType("application/json");
|
||||
Request.setContentLength(Doc.length());
|
||||
std::ostream& OS = Session.sendRequest(Request);
|
||||
Poco::StreamCopier::copyStream(Body, OS);
|
||||
Session.receiveResponse(Response);
|
||||
return (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK);
|
||||
}
|
||||
|
||||
bool NotificationMgr::SendManifest(const uCentral::Objects::Callback &Host) {
|
||||
|
||||
Poco::URI Uri(Host.URI);
|
||||
|
||||
Uri.addQueryParameter("topic", "ucentralfws");
|
||||
|
||||
Poco::Net::HTTPSClientSession Session(Uri.getHost(), Uri.getPort());
|
||||
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Uri.getPathAndQuery(),
|
||||
Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
Request.add("X-API-KEY", Host.Token);
|
||||
Poco::Net::HTTPResponse Response;
|
||||
return DoRequest(Session, Request, Response, CurrentManifest_);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-11.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_NOTIFICATIONMGR_H
|
||||
#define UCENTRALFWS_NOTIFICATIONMGR_H
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "SubSystemServer.h"
|
||||
#include "RESTAPI_objects.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
struct NotifyEndPoint {
|
||||
uCentral::Objects::Callback Caller;
|
||||
uint64_t LasContact;
|
||||
uint64_t LastVersion;
|
||||
};
|
||||
|
||||
class NotificationMgr : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
|
||||
NotificationMgr() noexcept;
|
||||
|
||||
static NotificationMgr *instance() {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ = new NotificationMgr;
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
void run() override;
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void Update();
|
||||
|
||||
void NotifyCallers();
|
||||
void SetVersion(const std::string &Manifest);
|
||||
bool SendManifest(const uCentral::Objects::Callback &Host);
|
||||
|
||||
private:
|
||||
static NotificationMgr *instance_;
|
||||
Poco::Thread Worker_;
|
||||
std::atomic_bool Running_ = false;
|
||||
std::atomic_bool Updated_ = false;
|
||||
std::map<std::string,NotifyEndPoint> EndPoints_;
|
||||
|
||||
std::string CurrentManifest_;
|
||||
uint64_t ManifestVersion_=0;
|
||||
};
|
||||
|
||||
inline NotificationMgr * NotificationMgr() { return NotificationMgr::instance(); };
|
||||
} // namespace
|
||||
|
||||
|
||||
#endif //UCENTRALFWS_NOTIFICATIONMGR_H
|
||||
154
src/RESTAPI_FMSObjects.cpp
Normal file
154
src/RESTAPI_FMSObjects.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-12.
|
||||
//
|
||||
|
||||
#include "RESTAPI_FMSObjects.h"
|
||||
#include "RESTAPI_utils.h"
|
||||
|
||||
using uCentral::RESTAPI_utils::field_to_json;
|
||||
using uCentral::RESTAPI_utils::field_from_json;
|
||||
|
||||
namespace uCentral::FMSObjects {
|
||||
|
||||
void Firmware::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "deviceType", deviceType);
|
||||
field_to_json(Obj, "description", description);
|
||||
field_to_json(Obj, "revision", revision);
|
||||
field_to_json(Obj, "uri", uri);
|
||||
field_to_json(Obj, "image", image);
|
||||
field_to_json(Obj, "imageDate", imageDate);
|
||||
field_to_json(Obj, "size", size);
|
||||
field_to_json(Obj, "downloadCount", downloadCount);
|
||||
field_to_json(Obj, "firmwareHash", firmwareHash);
|
||||
field_to_json(Obj, "owner", owner);
|
||||
field_to_json(Obj, "location", location);
|
||||
field_to_json(Obj, "uploader", uploader);
|
||||
field_to_json(Obj, "digest", digest);
|
||||
field_to_json(Obj, "latest", latest);
|
||||
field_to_json(Obj, "notes", notes);
|
||||
field_to_json(Obj, "created", created);
|
||||
};
|
||||
|
||||
bool Firmware::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "id", id);
|
||||
field_from_json(Obj, "deviceType", deviceType);
|
||||
field_from_json(Obj, "description", description);
|
||||
field_from_json(Obj, "revision", revision);
|
||||
field_from_json(Obj, "uri", uri);
|
||||
field_from_json(Obj, "image", image);
|
||||
field_from_json(Obj, "imageDate", imageDate);
|
||||
field_from_json(Obj, "size", size);
|
||||
field_from_json(Obj, "downloadCount", downloadCount);
|
||||
field_from_json(Obj, "firmwareHash", firmwareHash);
|
||||
field_from_json(Obj, "owner", owner);
|
||||
field_from_json(Obj, "location", location);
|
||||
field_from_json(Obj, "uploader", uploader);
|
||||
field_from_json(Obj, "digest", digest);
|
||||
field_from_json(Obj, "latest", latest);
|
||||
field_from_json(Obj, "notes", notes);
|
||||
field_from_json(Obj, "created", created);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FirmwareList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"firmwares",firmwares);
|
||||
}
|
||||
|
||||
bool FirmwareList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "firmwares", firmwares);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceType::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "deviceType", deviceType);
|
||||
field_to_json(Obj, "manufacturer", manufacturer);
|
||||
field_to_json(Obj, "model", model);
|
||||
field_to_json(Obj, "policy", policy);
|
||||
field_to_json(Obj, "notes", notes);
|
||||
field_to_json(Obj, "lastUpdate", lastUpdate);
|
||||
field_to_json(Obj, "created", created);
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "id", id);
|
||||
}
|
||||
|
||||
bool DeviceType::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "id", id);
|
||||
field_from_json(Obj, "deviceType", deviceType);
|
||||
field_from_json(Obj, "manufacturer", manufacturer);
|
||||
field_from_json(Obj, "model", model);
|
||||
field_from_json(Obj, "policy", policy);
|
||||
field_from_json(Obj, "notes", notes);
|
||||
field_from_json(Obj, "lastUpdate", lastUpdate);
|
||||
field_from_json(Obj, "created", created);
|
||||
field_from_json(Obj, "id", id);
|
||||
field_from_json(Obj, "id", id);
|
||||
field_from_json(Obj, "id", id);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceTypeList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"deviceTypes", deviceTypes);
|
||||
}
|
||||
|
||||
bool DeviceTypeList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"deviceTypes", deviceTypes);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RevisionHistoryEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "serialNumber", serialNumber);
|
||||
field_to_json(Obj, "upgraded", upgraded);
|
||||
field_to_json(Obj, "commandUUID", commandUUID);
|
||||
}
|
||||
|
||||
bool RevisionHistoryEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "id", id);
|
||||
field_from_json(Obj, "serialNumber", serialNumber);
|
||||
field_from_json(Obj, "upgraded", upgraded);
|
||||
field_from_json(Obj, "commandUUID", commandUUID);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RevisionHistoryEntryList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"deviceTypes", history);
|
||||
}
|
||||
|
||||
bool RevisionHistoryEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"deviceTypes", history);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
89
src/RESTAPI_FMSObjects.h
Normal file
89
src/RESTAPI_FMSObjects.h
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-12.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
#define UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
|
||||
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace uCentral::FMSObjects {
|
||||
|
||||
struct Firmware {
|
||||
std::string id;
|
||||
std::string deviceType;
|
||||
std::string description;
|
||||
std::string revision;
|
||||
std::string uri;
|
||||
std::string image;
|
||||
uint64_t imageDate;
|
||||
uint64_t size;
|
||||
uint64_t downloadCount;
|
||||
std::string firmwareHash;
|
||||
std::string owner;
|
||||
std::string location;
|
||||
std::string uploader;
|
||||
std::string digest;
|
||||
bool latest;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
uint64_t created;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
typedef std::vector<Firmware> FirmwareVec;
|
||||
|
||||
struct FirmwareList {
|
||||
FirmwareVec firmwares;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceType {
|
||||
std::string id;
|
||||
std::string deviceType;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string policy;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
uint64_t lastUpdate;
|
||||
uint64_t created;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
typedef std::vector<DeviceType> DeviceTypeVec;
|
||||
|
||||
struct DeviceTypeList {
|
||||
DeviceTypeVec deviceTypes;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RevisionHistoryEntry {
|
||||
std::string id;
|
||||
std::string serialNumber;
|
||||
uint64_t upgraded;
|
||||
std::string commandUUID;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
typedef std::vector<RevisionHistoryEntry> RevisionHistoryEntryVec;
|
||||
|
||||
struct RevisionHistoryEntryList {
|
||||
RevisionHistoryEntryVec history;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
207
src/RESTAPI_GWobjects.cpp
Normal file
207
src/RESTAPI_GWobjects.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/JSON/Stringifier.h"
|
||||
|
||||
#include "Daemon.h"
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
#include "DeviceRegistry.h"
|
||||
#endif
|
||||
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
#include "RESTAPI_handler.h"
|
||||
#include "RESTAPI_utils.h"
|
||||
#include "Utils.h"
|
||||
|
||||
using uCentral::RESTAPI_utils::field_to_json;
|
||||
using uCentral::RESTAPI_utils::field_from_json;
|
||||
using uCentral::RESTAPI_utils::EmbedDocument;
|
||||
|
||||
namespace uCentral::GWObjects {
|
||||
|
||||
void Device::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
field_to_json(Obj,"deviceType", uCentral::Daemon::instance()->IdentifyDevice(Compatible));
|
||||
#endif
|
||||
field_to_json(Obj,"macAddress", MACAddress);
|
||||
field_to_json(Obj,"manufacturer", Manufacturer);
|
||||
field_to_json(Obj,"UUID", UUID);
|
||||
EmbedDocument("configuration", Obj, Configuration);
|
||||
field_to_json(Obj,"notes", Notes);
|
||||
field_to_json(Obj,"createdTimestamp", CreationTimestamp);
|
||||
field_to_json(Obj,"lastConfigurationChange", LastConfigurationChange);
|
||||
field_to_json(Obj,"lastConfigurationDownload", LastConfigurationDownload);
|
||||
field_to_json(Obj,"lastFWUpdate", LastFWUpdate);
|
||||
field_to_json(Obj,"owner", Owner);
|
||||
field_to_json(Obj,"location", Location);
|
||||
field_to_json(Obj,"venue", Venue);
|
||||
field_to_json(Obj,"firmware", Firmware);
|
||||
field_to_json(Obj,"compatible", Compatible);
|
||||
field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy);
|
||||
field_to_json(Obj,"devicePassword", DevicePassword);
|
||||
}
|
||||
|
||||
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
|
||||
to_json(Obj);
|
||||
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
ConnectionState ConState;
|
||||
|
||||
if (DeviceRegistry()->GetState(SerialNumber, ConState)) {
|
||||
ConState.to_json(Obj);
|
||||
} else {
|
||||
field_to_json(Obj,"ipAddress", "N/A");
|
||||
field_to_json(Obj,"txBytes", (uint64_t) 0);
|
||||
field_to_json(Obj,"rxBytes", (uint64_t )0);
|
||||
field_to_json(Obj,"messageCount", (uint64_t )0);
|
||||
field_to_json(Obj,"connected", false);
|
||||
field_to_json(Obj,"lastContact", "N/A");
|
||||
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Device::from_json(Poco::JSON::Object::Ptr Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"serialNumber",SerialNumber);
|
||||
field_from_json(Obj,"deviceType",DeviceType);
|
||||
field_from_json(Obj,"macAddress",MACAddress);
|
||||
field_from_json(Obj,"configuration",Configuration);
|
||||
field_from_json(Obj,"notes",Notes);
|
||||
field_from_json(Obj,"manufacturer",Manufacturer);
|
||||
field_from_json(Obj,"owner",Owner);
|
||||
field_from_json(Obj,"location",Location);
|
||||
field_from_json(Obj,"venue",Venue);
|
||||
field_from_json(Obj,"compatible",Compatible);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Device::Print() const {
|
||||
std::cout << "Device: " << SerialNumber << " DeviceType:" << DeviceType << " MACAddress:" << MACAddress << " Manufacturer:"
|
||||
<< Manufacturer << " " << Configuration << std::endl;
|
||||
}
|
||||
|
||||
void Statistics::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("data", Obj, Data);
|
||||
field_to_json(Obj,"UUID", UUID);
|
||||
field_to_json(Obj,"recorded", Recorded);
|
||||
}
|
||||
|
||||
void Capabilities::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("capabilities", Obj, Capabilities);
|
||||
field_to_json(Obj,"firstUpdate", FirstUpdate);
|
||||
field_to_json(Obj,"lastUpdate", LastUpdate);
|
||||
}
|
||||
|
||||
void DeviceLog::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("data", Obj, Data);
|
||||
field_to_json(Obj,"log", Log);
|
||||
field_to_json(Obj,"severity", Severity);
|
||||
field_to_json(Obj,"recorded", Recorded);
|
||||
field_to_json(Obj,"logType", LogType);
|
||||
field_to_json(Obj,"UUID", UUID);
|
||||
}
|
||||
|
||||
void HealthCheck::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("values", Obj, Data);
|
||||
field_to_json(Obj,"UUID", UUID);
|
||||
field_to_json(Obj,"sanity", Sanity);
|
||||
field_to_json(Obj,"recorded", Recorded);
|
||||
}
|
||||
|
||||
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("configuration", Obj, Configuration);
|
||||
field_to_json(Obj,"name", Name);
|
||||
field_to_json(Obj,"modelIds", Models);
|
||||
field_to_json(Obj,"description", Description);
|
||||
field_to_json(Obj,"created", Created);
|
||||
field_to_json(Obj,"lastModified", LastModified);
|
||||
}
|
||||
|
||||
void CommandDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("details", Obj, Details);
|
||||
EmbedDocument("results", Obj, Results);
|
||||
field_to_json(Obj,"UUID", UUID);
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
field_to_json(Obj,"command", Command);
|
||||
field_to_json(Obj,"errorText", ErrorText);
|
||||
field_to_json(Obj,"submittedBy", SubmittedBy);
|
||||
field_to_json(Obj,"status", Status);
|
||||
field_to_json(Obj,"submitted", Submitted);
|
||||
field_to_json(Obj,"executed", Executed);
|
||||
field_to_json(Obj,"completed", Completed);
|
||||
field_to_json(Obj,"when", RunAt);
|
||||
field_to_json(Obj,"errorCode", ErrorCode);
|
||||
field_to_json(Obj,"custom", Custom);
|
||||
field_to_json(Obj,"waitingForFile", WaitingForFile);
|
||||
field_to_json(Obj,"attachFile", AttachDate);
|
||||
}
|
||||
|
||||
bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"name",Name);
|
||||
field_from_json(Obj,"configuration",Configuration);
|
||||
field_from_json(Obj,"modelIds",Models);
|
||||
field_from_json(Obj,"description",Description);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BlackListedDevice::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
field_to_json(Obj,"author", Author);
|
||||
field_to_json(Obj,"reason", Reason);
|
||||
field_to_json(Obj,"created", Created);
|
||||
}
|
||||
|
||||
void ConnectionState::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
field_to_json(Obj,"ipAddress", Address);
|
||||
field_to_json(Obj,"txBytes", TX);
|
||||
field_to_json(Obj,"rxBytes", RX);
|
||||
field_to_json(Obj,"messageCount", MessageCount);
|
||||
field_to_json(Obj,"UUID", UUID);
|
||||
field_to_json(Obj,"connected", Connected);
|
||||
field_to_json(Obj,"firmware", Firmware);
|
||||
field_to_json(Obj,"lastContact", LastContact);
|
||||
switch(VerifiedCertificate) {
|
||||
case NO_CERTIFICATE:
|
||||
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break;
|
||||
case VALID_CERTIFICATE:
|
||||
field_to_json(Obj,"verifiedCertificate", "VALID_CERTIFICATE"); break;
|
||||
case MISMATCH_SERIAL:
|
||||
field_to_json(Obj,"verifiedCertificate", "MISMATCH_SERIAL"); break;
|
||||
case VERIFIED:
|
||||
field_to_json(Obj,"verifiedCertificate", "VERIFIED"); break;
|
||||
default:
|
||||
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break;
|
||||
}
|
||||
}
|
||||
|
||||
void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
field_to_json(Obj,"server", Server);
|
||||
field_to_json(Obj,"port", Port);
|
||||
field_to_json(Obj,"token",Token);
|
||||
field_to_json(Obj,"timeout", TimeOut);
|
||||
field_to_json(Obj,"connectionId",ConnectionId);
|
||||
field_to_json(Obj,"commandUUID",CommandUUID);
|
||||
field_to_json(Obj,"started", Started);
|
||||
field_to_json(Obj,"viewport",ViewPort);
|
||||
field_to_json(Obj,"password",DevicePassword);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
161
src/RESTAPI_GWobjects.h
Normal file
161
src/RESTAPI_GWobjects.h
Normal file
@@ -0,0 +1,161 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRAL_RESTAPI_OBJECTS_H
|
||||
#define UCENTRAL_RESTAPI_OBJECTS_H
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace uCentral::GWObjects {
|
||||
|
||||
enum CertificateValidation {
|
||||
NO_CERTIFICATE,
|
||||
VALID_CERTIFICATE,
|
||||
MISMATCH_SERIAL,
|
||||
VERIFIED
|
||||
};
|
||||
|
||||
struct ConnectionState {
|
||||
uint64_t MessageCount = 0 ;
|
||||
std::string SerialNumber;
|
||||
std::string Address = "N/A";
|
||||
uint64_t UUID = 0 ;
|
||||
uint64_t PendingUUID = 0 ;
|
||||
uint64_t TX = 0, RX = 0;
|
||||
bool Connected = false;
|
||||
uint64_t LastContact=0;
|
||||
std::string Firmware;
|
||||
CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct Device {
|
||||
std::string SerialNumber;
|
||||
std::string DeviceType;
|
||||
std::string MACAddress;
|
||||
std::string Manufacturer;
|
||||
std::string Configuration;
|
||||
SecurityObjects::NoteInfoVec Notes;
|
||||
std::string Owner;
|
||||
std::string Location;
|
||||
std::string Firmware;
|
||||
std::string Compatible;
|
||||
std::string FWUpdatePolicy;
|
||||
uint64_t UUID;
|
||||
uint64_t CreationTimestamp;
|
||||
uint64_t LastConfigurationChange;
|
||||
uint64_t LastConfigurationDownload;
|
||||
uint64_t LastFWUpdate;
|
||||
std::string Venue;
|
||||
std::string DevicePassword;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void to_json_with_status(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(Poco::JSON::Object::Ptr Obj);
|
||||
void Print() const;
|
||||
};
|
||||
|
||||
struct Statistics {
|
||||
uint64_t UUID;
|
||||
std::string Data;
|
||||
uint64_t Recorded;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct HealthCheck {
|
||||
uint64_t UUID;
|
||||
std::string Data;
|
||||
uint64_t Recorded;
|
||||
uint64_t Sanity;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct Capabilities {
|
||||
std::string Capabilities;
|
||||
uint64_t FirstUpdate;
|
||||
uint64_t LastUpdate;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct DeviceLog {
|
||||
enum Level {
|
||||
LOG_EMERG = 0, /* system is unusable */
|
||||
LOG_ALERT = 1, /* action must be taken immediately */
|
||||
LOG_CRIT = 2, /* critical conditions */
|
||||
LOG_ERR = 3, /* error conditions */
|
||||
LOG_WARNING = 4, /* warning conditions */
|
||||
LOG_NOTICE = 5, /* normal but significant condition */
|
||||
LOG_INFO = 6, /* informational */
|
||||
LOG_DEBUG = 7 /* debug-level messages */
|
||||
};
|
||||
std::string Log;
|
||||
std::string Data;
|
||||
uint64_t Severity;
|
||||
uint64_t Recorded;
|
||||
uint64_t LogType;
|
||||
uint64_t UUID;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct DefaultConfiguration {
|
||||
std::string Name;
|
||||
std::string Configuration;
|
||||
std::string Models;
|
||||
std::string Description;
|
||||
uint64_t Created;
|
||||
uint64_t LastModified;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(Poco::JSON::Object::Ptr Obj);
|
||||
};
|
||||
|
||||
struct CommandDetails {
|
||||
std::string UUID;
|
||||
std::string SerialNumber;
|
||||
std::string Command;
|
||||
std::string Status;
|
||||
std::string SubmittedBy;
|
||||
std::string Results;
|
||||
std::string Details;
|
||||
std::string ErrorText;
|
||||
uint64_t Submitted = time(nullptr);
|
||||
uint64_t Executed = 0;
|
||||
uint64_t Completed = 0 ;
|
||||
uint64_t RunAt = 0 ;
|
||||
uint64_t ErrorCode = 0 ;
|
||||
uint64_t Custom = 0 ;
|
||||
uint64_t WaitingForFile = 0 ;
|
||||
uint64_t AttachDate = 0 ;
|
||||
uint64_t AttachSize = 0 ;
|
||||
std::string AttachType;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct BlackListedDevice {
|
||||
std::string SerialNumber;
|
||||
std::string Reason;
|
||||
std::string Author;
|
||||
uint64_t Created;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct RttySessionDetails {
|
||||
std::string SerialNumber;
|
||||
std::string Server;
|
||||
uint64_t Port;
|
||||
std::string Token;
|
||||
uint64_t TimeOut;
|
||||
std::string ConnectionId;
|
||||
uint64_t Started;
|
||||
std::string CommandUUID;
|
||||
uint64_t ViewPort;
|
||||
std::string DevicePassword;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRAL_RESTAPI_OBJECTS_H
|
||||
@@ -6,13 +6,8 @@
|
||||
|
||||
#include "Poco/URI.h"
|
||||
|
||||
#include "RESTAPI_callbackHandler.h"
|
||||
#include "RESTAPI_callbacksHandler.h"
|
||||
#include "RESTAPI_firmwareHandler.h"
|
||||
#include "RESTAPI_firmwaresHandler.h"
|
||||
#include "RESTAPI_latestFirmwareListHandler.h"
|
||||
#include "RESTAPI_callbackChannel.h"
|
||||
#include "RESTAPI_newFirmwareAvailable.h"
|
||||
#include "RESTAPI_system_command.h"
|
||||
|
||||
#include "Utils.h"
|
||||
@@ -69,11 +64,6 @@ namespace uCentral {
|
||||
return RESTAPI_Router<
|
||||
RESTAPI_firmwaresHandler,
|
||||
RESTAPI_firmwareHandler,
|
||||
RESTAPI_callbacksHandler,
|
||||
RESTAPI_callbackHandler,
|
||||
RESTAPI_latestFirmwareListHandler,
|
||||
RESTAPI_callbackChannel,
|
||||
RESTAPI_newFirmwareAvailable,
|
||||
RESTAPI_system_command
|
||||
>(Path, Bindings, Logger_);
|
||||
}
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-11.
|
||||
//
|
||||
|
||||
#include "RESTAPI_callbackChannel.h"
|
||||
#include "StorageService.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_callbackChannel::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
|
||||
ParseParameters(Request);
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
|
||||
DoPost(Request, Response);
|
||||
else
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
void
|
||||
RESTAPI_callbackChannel::DoPost(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
if (!ValidateAPIKey(Request, Response)) {
|
||||
UnAuthorized(Request, Response);
|
||||
return;
|
||||
}
|
||||
|
||||
auto Subscribe = GetParameter("subscribe", "");
|
||||
if (Subscribe == "true") {
|
||||
// subscribing
|
||||
// we must have uri, msgs, id, key
|
||||
auto URI = GetParameter("uri", "");
|
||||
auto Topics = GetParameter("topics", "");
|
||||
auto ID = GetParameter("id", "");
|
||||
auto Key = GetParameter("key", "");
|
||||
|
||||
if (URI.empty() || Topics.empty() || ID.empty() || Key.empty()) {
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
}
|
||||
|
||||
uCentral::Objects::Callback C;
|
||||
|
||||
C.UUID = ID;
|
||||
C.TokenType = "X-API-KEY";
|
||||
C.Token = Key;
|
||||
C.URI = URI;
|
||||
C.Created = time(nullptr);
|
||||
C.Creator = UserInfo_.userinfo.name;
|
||||
C.Topics = Topics;
|
||||
|
||||
if (uCentral::Storage()->AddOrUpdateCallback(C)) {
|
||||
Logger_.information(Poco::format("CALLBACK(%s): Just subscribed.", UserInfo_.userinfo.name));
|
||||
OK(Request, Response);
|
||||
return;
|
||||
} else {
|
||||
Logger_.error(Poco::format("CALLBACK(%s): Could not register.", UserInfo_.userinfo.name));
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
}
|
||||
} else if (Subscribe == "false") {
|
||||
// removing a subscription
|
||||
auto ID = GetParameter("id", "");
|
||||
if (ID.empty()) {
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
}
|
||||
if (uCentral::Storage()->DeleteCallback(ID)) {
|
||||
OK(Request, Response);
|
||||
return;
|
||||
}
|
||||
Logger_.error(Poco::format("CALLBACK(%s): Cannot remove subscription.", UserInfo_.userinfo.name));
|
||||
NotFound(Request, Response);
|
||||
return;
|
||||
} else {
|
||||
// not a subscription message
|
||||
auto Topic = GetParameter("topic", "");
|
||||
if (Topic.empty()) {
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
}
|
||||
Poco::JSON::Parser parser;
|
||||
Poco::JSON::Object::Ptr Obj = parser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
OK(Request, Response);
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-11.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_RESTAPI_CALLBACKCHANNEL_H
|
||||
#define UCENTRALFWS_RESTAPI_CALLBACKCHANNEL_H
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
class RESTAPI_callbackChannel : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_callbackChannel(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/callbackChannel"};}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override;
|
||||
void DoPost(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRALFWS_RESTAPI_CALLBACKCHANNEL_H
|
||||
@@ -1,103 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-09.
|
||||
//
|
||||
|
||||
#include "RESTAPI_callbackHandler.h"
|
||||
#include "StorageService.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_callbackHandler::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
ParseParameters(Request);
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
DoGet(Request, Response);
|
||||
else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
|
||||
DoPost(Request, Response);
|
||||
else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_PUT)
|
||||
DoPut(Request, Response);
|
||||
else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE)
|
||||
DoDelete(Request, Response);
|
||||
else
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
void
|
||||
RESTAPI_callbackHandler::DoPost(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
Poco::JSON::Parser parser;
|
||||
Poco::JSON::Object::Ptr Obj = parser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
uCentral::Objects::Callback C;
|
||||
|
||||
if (C.from_json(Obj)) {
|
||||
C.UUID = Daemon()->CreateUUID();
|
||||
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
void
|
||||
RESTAPI_callbackHandler::DoPut(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
void
|
||||
RESTAPI_callbackHandler::DoGet(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
auto UUID = GetBinding("uuid", "");
|
||||
|
||||
if (!UUID.empty()) {
|
||||
uCentral::Objects::Callback C;
|
||||
if (uCentral::Storage()->GetCallback(UUID, C)) {
|
||||
Poco::JSON::Object Object;
|
||||
|
||||
C.to_json(Object);
|
||||
ReturnObject(Request, Object, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
void
|
||||
RESTAPI_callbackHandler::DoDelete(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
auto UUID = GetBinding("uuid", "");
|
||||
|
||||
if (!UUID.empty()) {
|
||||
if (uCentral::Storage()->DeleteCallback(UUID)) {
|
||||
OK(Request, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-09.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_RESTAPI_CALLBACKHANDLER_H
|
||||
#define UCENTRALFWS_RESTAPI_CALLBACKHANDLER_H
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
class RESTAPI_callbackHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_callbackHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/callback/{uuid}"};}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override;
|
||||
void DoPost(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
void DoGet(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
void DoDelete(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
void DoPut(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRALFWS_RESTAPI_CALLBACKHANDLER_H
|
||||
@@ -1,50 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-09.
|
||||
//
|
||||
|
||||
#include "RESTAPI_callbacksHandler.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_callbacksHandler::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
ParseParameters(Request);
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
DoGet(Request, Response);
|
||||
else
|
||||
BadRequest(Request, Response);
|
||||
|
||||
}
|
||||
|
||||
void RESTAPI_callbacksHandler::DoGet(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
auto Offset = GetParameter("offset", 0);
|
||||
auto Limit = GetParameter("limit", 100);
|
||||
|
||||
std::vector<uCentral::Objects::Callback> List;
|
||||
if (uCentral::Storage()->GetCallbacks(Offset, Limit, List)) {
|
||||
|
||||
Poco::JSON::Array ObjectArray;
|
||||
|
||||
for (const auto &i:List) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
ObjectArray.add(Obj);
|
||||
}
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set("callbacks", ObjectArray);
|
||||
ReturnObject(Request, RetObj, Response);
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-09.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_RESTAPI_CALLBACKSHANDLER_H
|
||||
#define UCENTRALFWS_RESTAPI_CALLBACKSHANDLER_H
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
class RESTAPI_callbacksHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_callbacksHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/callbacks"};}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override;
|
||||
void DoGet(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
};
|
||||
}
|
||||
#endif //UCENTRALFWS_RESTAPI_CALLBACKSHANDLER_H
|
||||
@@ -42,8 +42,8 @@ namespace uCentral {
|
||||
auto UUID = GetBinding("uuid", "");
|
||||
|
||||
if (!UUID.empty()) {
|
||||
uCentral::Objects::Firmware F;
|
||||
if (uCentral::Storage()->GetFirmware(UUID, F)) {
|
||||
FMSObjects::Firmware F;
|
||||
if (Storage()->GetFirmware(UUID, F)) {
|
||||
Poco::JSON::Object Object;
|
||||
F.to_json(Object);
|
||||
ReturnObject(Request, Object, Response);
|
||||
@@ -64,7 +64,7 @@ namespace uCentral {
|
||||
auto UUID = GetBinding("uuid", "");
|
||||
|
||||
if (!UUID.empty()) {
|
||||
if (uCentral::Storage()->DeleteFirmware(UUID)) {
|
||||
if (Storage()->DeleteFirmware(UUID)) {
|
||||
OK(Request, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace uCentral {
|
||||
auto Offset = GetParameter("offset", 0);
|
||||
auto Limit = GetParameter("limit", 100);
|
||||
|
||||
std::vector<uCentral::Objects::Firmware> List;
|
||||
std::vector<FMSObjects::Firmware> List;
|
||||
if (uCentral::Storage()->GetFirmwares(Offset, Limit, List)) {
|
||||
|
||||
Poco::JSON::Array ObjectArray;
|
||||
|
||||
@@ -194,12 +194,13 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
void RESTAPIHandler::UnAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
const std::string & Reason) {
|
||||
PrepareResponse(Request, Response, Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",403);
|
||||
ErrorObject.set("ErrorDetails",Request.getMethod());
|
||||
ErrorObject.set("ErrorDescription","You do not have access to this resource.");
|
||||
ErrorObject.set("ErrorDescription",Reason.empty() ? "No access allowed." : Reason) ;
|
||||
std::ostream &Answer = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
@@ -244,7 +245,37 @@ namespace uCentral {
|
||||
Response.sendFile(File.path(),"application/octet-stream");
|
||||
}
|
||||
|
||||
void RESTAPIHandler::ReturnStatus(Poco::Net::HTTPServerRequest &Request,
|
||||
void RESTAPIHandler::SendFile(Poco::File & File, Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
Response.set("Content-Type",Utils::FindMediaType(File));
|
||||
Poco::Path P(File.path());
|
||||
Response.set("Content-Disposition", "attachment; filename=" + P.getBaseName() );
|
||||
Response.set("Content-Transfer-Encoding","binary");
|
||||
Response.set("Accept-Ranges", "bytes");
|
||||
Response.set("Cache-Control", "private");
|
||||
Response.set("Pragma", "private");
|
||||
Response.set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response.set("Content-Length", std::to_string(File.getSize()));
|
||||
AddCORS(Request, Response);
|
||||
Response.sendFile(File.path(),Utils::FindMediaType(File));
|
||||
}
|
||||
|
||||
void RESTAPIHandler::SendHTMLFileBack(Poco::File & File,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response ,
|
||||
const Types::StringPairVec & FormVars) {
|
||||
Response.set("Pragma", "private");
|
||||
Response.set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response.set("Content-Length", std::to_string(File.getSize()));
|
||||
AddCORS(Request, Response);
|
||||
auto FormContent = Utils::LoadFile(File.path());
|
||||
Utils::ReplaceVariables(FormContent, FormVars);
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
Response.setContentType("text/html");
|
||||
std::ostream& ostr = Response.send();
|
||||
ostr << FormContent;
|
||||
}
|
||||
|
||||
void RESTAPIHandler::ReturnStatus(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
Poco::Net::HTTPResponse::HTTPStatus Status,
|
||||
bool CloseConnection) {
|
||||
|
||||
@@ -15,15 +15,72 @@
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/PartHandler.h"
|
||||
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/CountingStream.h"
|
||||
#include "Poco/NullStream.h"
|
||||
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
|
||||
class RESTAPI_PartHandler: public Poco::Net::PartHandler
|
||||
{
|
||||
public:
|
||||
RESTAPI_PartHandler():
|
||||
_length(0)
|
||||
{
|
||||
}
|
||||
|
||||
void handlePart(const Poco::Net::MessageHeader& header, std::istream& stream) override
|
||||
{
|
||||
_type = header.get("Content-Type", "(unspecified)");
|
||||
if (header.has("Content-Disposition"))
|
||||
{
|
||||
std::string disp;
|
||||
Poco::Net::NameValueCollection params;
|
||||
Poco::Net::MessageHeader::splitParameters(header["Content-Disposition"], disp, params);
|
||||
_name = params.get("name", "(unnamed)");
|
||||
_fileName = params.get("filename", "(unnamed)");
|
||||
}
|
||||
|
||||
Poco::CountingInputStream istr(stream);
|
||||
Poco::NullOutputStream ostr;
|
||||
Poco::StreamCopier::copyStream(istr, ostr);
|
||||
_length = (int)istr.chars();
|
||||
}
|
||||
|
||||
[[nodiscard]] int length() const
|
||||
{
|
||||
return _length;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string& name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string& fileName() const
|
||||
{
|
||||
return _fileName;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string& contentType() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
private:
|
||||
int _length;
|
||||
std::string _type;
|
||||
std::string _name;
|
||||
std::string _fileName;
|
||||
};
|
||||
|
||||
class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
struct QueryBlock {
|
||||
uint64_t StartDate = 0 , EndDate = 0 , Offset = 0 , Limit = 0, LogType = 0 ;
|
||||
@@ -64,7 +121,7 @@ namespace uCentral {
|
||||
|
||||
void BadRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response, const std::string &Reason = "");
|
||||
void UnAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
Poco::Net::HTTPServerResponse &Response, const std::string &Reason = "");
|
||||
void ReturnObject(Poco::Net::HTTPServerRequest &Request, Poco::JSON::Object &Object,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void NotFound(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
@@ -75,8 +132,14 @@ namespace uCentral {
|
||||
bool CloseConnection=false);
|
||||
void SendFile(Poco::File & File, const std::string & UUID,
|
||||
Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void SendHTMLFileBack(Poco::File & File,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response ,
|
||||
const Types::StringPairVec & FormVars);
|
||||
|
||||
const std::string &GetBinding(const std::string &Name, const std::string &Default);
|
||||
void SendFile(Poco::File & File, Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
|
||||
const std::string &GetBinding(const std::string &Name, const std::string &Default);
|
||||
void InitQueryBlock();
|
||||
|
||||
[[nodiscard]] static uint64_t Get(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, uint64_t Default=0);
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-09.
|
||||
//
|
||||
|
||||
#include "RESTAPI_latestFirmwareListHandler.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_latestFirmwareListHandler::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
ParseParameters(Request);
|
||||
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
DoGet(Request, Response);
|
||||
else
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
void RESTAPI_latestFirmwareListHandler::DoGet(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
|
||||
try {
|
||||
auto Offset = GetParameter("offset", 0);
|
||||
auto Limit = GetParameter("limit", 100);
|
||||
|
||||
std::vector<uCentral::Objects::LatestFirmware> List;
|
||||
if (uCentral::Storage()->GetLatestFirmwareList(Offset, Limit, List)) {
|
||||
|
||||
Poco::JSON::Array ObjectArray;
|
||||
|
||||
for (const auto &i:List) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
ObjectArray.add(Obj);
|
||||
}
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set("latestFirmwareList", ObjectArray);
|
||||
ReturnObject(Request, RetObj, Response);
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-09.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_RESTAPI_LATESTFIRMWARELISTHANDLER_H
|
||||
#define UCENTRALFWS_RESTAPI_LATESTFIRMWARELISTHANDLER_H
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
class RESTAPI_latestFirmwareListHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_latestFirmwareListHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/latestFirmwareList"};}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override;
|
||||
void DoGet(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRALFWS_RESTAPI_LATESTFIRMWARELISTHANDLER_H
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-06-02.
|
||||
//
|
||||
|
||||
#include "RESTAPI_newFirmwareAvailable.h"
|
||||
#include "ManifestCreator.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_newFirmwareAvailable::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
|
||||
if (!ValidateAPIKey(Request, Response)) {
|
||||
UnAuthorized(Request, Response);
|
||||
return;
|
||||
}
|
||||
|
||||
ParseParameters(Request);
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
DoGet(Request, Response);
|
||||
else
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
void RESTAPI_newFirmwareAvailable::DoGet(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
|
||||
auto Op = GetParameter("operation", "");
|
||||
|
||||
if (Op != "notify") {
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
}
|
||||
|
||||
uCentral::ManifestCreator()->Update();
|
||||
|
||||
Poco::JSON::Object O;
|
||||
O.set("status", "updating manifest");
|
||||
ReturnObject(Request, O, Response);
|
||||
return;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-06-02.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_RESTAPI_NEWFIRMWAREAVAILABLE_H
|
||||
#define UCENTRALFWS_RESTAPI_NEWFIRMWAREAVAILABLE_H
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
class RESTAPI_newFirmwareAvailable : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_newFirmwareAvailable(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/newFirmwareAvailable"};}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override;
|
||||
void DoGet(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRALFWS_RESTAPI_NEWFIRMWAREAVAILABLE_H
|
||||
@@ -1,94 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-07.
|
||||
//
|
||||
|
||||
#include "RESTAPI_objects.h"
|
||||
#include "RESTAPI_handler.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
namespace uCentral::Objects {
|
||||
|
||||
void EmbedDocument(const std::string & ObjName, Poco::JSON::Object & Obj, const std::string &ObjStr) {
|
||||
std::string D = ObjStr.empty() ? "{}" : ObjStr;
|
||||
Poco::JSON::Parser P;
|
||||
Poco::Dynamic::Var result = P.parse(D);
|
||||
const auto &DetailsObj = result.extract<Poco::JSON::Object::Ptr>();
|
||||
Obj.set(ObjName, DetailsObj);
|
||||
}
|
||||
|
||||
void Firmware::to_json(Poco::JSON::Object &Obj) const {
|
||||
Obj.set("uuid",UUID);
|
||||
Obj.set("description", Description);
|
||||
Obj.set("uploaded",Uploaded);
|
||||
Obj.set("firmwareDate",FirmwareDate);
|
||||
Obj.set("firmwareVersion", FirmwareVersion);
|
||||
Obj.set("firmwareHash", FirmwareHash);
|
||||
Obj.set("owner", Owner);
|
||||
Obj.set("location", Location);
|
||||
Obj.set("downloadCount", DownloadCount);
|
||||
Obj.set("uploader", Uploader);
|
||||
Obj.set("size", Size);
|
||||
Obj.set("digest", Digest);
|
||||
Obj.set("s3uri", S3URI);
|
||||
Obj.set("Compatible", Compatible);
|
||||
Obj.set("latest", (bool) (Latest ? true : false) );
|
||||
EmbedDocument("firmwareLatestDoc",Obj,FirmwareLatestDoc);
|
||||
}
|
||||
|
||||
void Callback::to_json(Poco::JSON::Object &Obj) const {
|
||||
Obj.set("uri", URI);
|
||||
Obj.set("uuid",UUID);
|
||||
Obj.set("location",Location);
|
||||
Obj.set("creator", Creator);
|
||||
Obj.set("token", Token);
|
||||
Obj.set("tokenType", TokenType);
|
||||
Obj.set("topics",Topics);
|
||||
Obj.set("created", Created);
|
||||
Obj.set("expires", Expires);
|
||||
}
|
||||
|
||||
bool Callback::from_json(Poco::JSON::Object::Ptr Obj) {
|
||||
Poco::DynamicStruct ds = *Obj;
|
||||
|
||||
if(ds.contains("uri"))
|
||||
URI = ds["uri"].toString();
|
||||
if(ds.contains("uuid"))
|
||||
UUID = ds["uuid"].toString();
|
||||
if(ds.contains("location"))
|
||||
Location = ds["location"].toString();
|
||||
if(ds.contains("token"))
|
||||
Token = ds["token"].toString();
|
||||
if(ds.contains("tokenType"))
|
||||
TokenType = ds["tokenType"].toString();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LatestFirmware::to_json(Poco::JSON::Object &Obj) const {
|
||||
Obj.set("Compatible", Compatible);
|
||||
Obj.set("uuid", UUID);
|
||||
Obj.set("lastUpdated", LastUpdated);
|
||||
}
|
||||
|
||||
void AclTemplate::to_json(Poco::JSON::Object &Obj) const {
|
||||
Obj.set("Read",Read_);
|
||||
Obj.set("ReadWrite",ReadWrite_);
|
||||
Obj.set("ReadWriteCreate",ReadWriteCreate_);
|
||||
Obj.set("Delete",Delete_);
|
||||
Obj.set("PortalLogin",PortalLogin_);
|
||||
}
|
||||
|
||||
void WebToken::to_json(Poco::JSON::Object & Obj) const {
|
||||
Poco::JSON::Object AclTemplateObj;
|
||||
acl_template_.to_json(AclTemplateObj);
|
||||
Obj.set("access_token",access_token_);
|
||||
Obj.set("refresh_token",refresh_token_);
|
||||
Obj.set("token_type",token_type_);
|
||||
Obj.set("expires_in",expires_in_);
|
||||
Obj.set("idle_timeout",idle_timeout_);
|
||||
Obj.set("created", created_);
|
||||
Obj.set("username",username_);
|
||||
Obj.set("aclTemplate",AclTemplateObj);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-07.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_RESTAPI_OBJECTS_H
|
||||
#define UCENTRALFWS_RESTAPI_OBJECTS_H
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
|
||||
namespace uCentral::Objects {
|
||||
|
||||
struct AclTemplate {
|
||||
bool Read_ = true ;
|
||||
bool ReadWrite_ = true ;
|
||||
bool ReadWriteCreate_ = true ;
|
||||
bool Delete_ = true ;
|
||||
bool PortalLogin_ = true ;
|
||||
void to_json(Poco::JSON::Object &Obj) const ;
|
||||
};
|
||||
|
||||
struct WebToken {
|
||||
std::string access_token_;
|
||||
std::string refresh_token_;
|
||||
std::string id_token_;
|
||||
std::string token_type_;
|
||||
std::string username_;
|
||||
unsigned int expires_in_;
|
||||
unsigned int idle_timeout_;
|
||||
AclTemplate acl_template_;
|
||||
uint64_t created_;
|
||||
void to_json(Poco::JSON::Object &Obj) const ;
|
||||
};
|
||||
|
||||
struct Firmware {
|
||||
std::string UUID;
|
||||
std::string Description;
|
||||
std::string Owner;
|
||||
std::string Location;
|
||||
std::string Compatible;
|
||||
std::string Uploader;
|
||||
std::string Digest;
|
||||
std::string FirmwareFileName;
|
||||
std::string FirmwareVersion;
|
||||
std::string FirmwareHash;
|
||||
std::string FirmwareLatestDoc;
|
||||
std::string S3URI;
|
||||
uint64_t FirmwareDate;
|
||||
uint64_t Uploaded;
|
||||
uint64_t DownloadCount;
|
||||
uint64_t Size;
|
||||
uint64_t Latest;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct Callback {
|
||||
std::string UUID;
|
||||
std::string URI;
|
||||
std::string Location;
|
||||
std::string Token;
|
||||
std::string TokenType;
|
||||
std::string Creator;
|
||||
std::string Topics;
|
||||
uint64_t Created;
|
||||
uint64_t Expires;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(Poco::JSON::Object::Ptr Obj);
|
||||
};
|
||||
|
||||
struct LatestFirmware {
|
||||
std::string Compatible;
|
||||
std::string UUID;
|
||||
uint64_t LastUpdated;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //UCENTRALFWS_RESTAPI_OBJECTS_H
|
||||
@@ -8,13 +8,8 @@
|
||||
#include "Utils.h"
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
#include "RESTAPI_callbackHandler.h"
|
||||
#include "RESTAPI_callbacksHandler.h"
|
||||
#include "RESTAPI_firmwareHandler.h"
|
||||
#include "RESTAPI_firmwaresHandler.h"
|
||||
#include "RESTAPI_latestFirmwareListHandler.h"
|
||||
#include "RESTAPI_callbackChannel.h"
|
||||
#include "RESTAPI_newFirmwareAvailable.h"
|
||||
#include "RESTAPI_system_command.h"
|
||||
|
||||
namespace uCentral {
|
||||
@@ -67,11 +62,6 @@ namespace uCentral {
|
||||
return RESTAPI_Router<
|
||||
RESTAPI_firmwaresHandler,
|
||||
RESTAPI_firmwareHandler,
|
||||
RESTAPI_callbacksHandler,
|
||||
RESTAPI_callbackHandler,
|
||||
RESTAPI_latestFirmwareListHandler,
|
||||
RESTAPI_callbackChannel,
|
||||
RESTAPI_newFirmwareAvailable,
|
||||
RESTAPI_system_command
|
||||
>(Path,Bindings,Logger_);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
|
||||
#include "uCentralTypes.h"
|
||||
#include "Utils.h"
|
||||
|
||||
@@ -193,13 +191,6 @@ namespace uCentral::RESTAPI_utils {
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<class T> bool from_request(T & Obj, Poco::Net::HTTPServerRequest &Request) {
|
||||
Poco::JSON::Parser IncomingParser;
|
||||
auto RawObject = IncomingParser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
Obj.from_json(RawObject);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // UCENTRALGW_RESTAPI_UTILS_H
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include <fstream>
|
||||
#include "StorageService.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
|
||||
#include "Daemon.h"
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
namespace uCentral {
|
||||
@@ -43,12 +46,25 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
int Storage::Start() {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
Logger_.setLevel(Poco::Message::PRIO_NOTICE);
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
Logger_.setLevel(Poco::Message::PRIO_NOTICE);
|
||||
Logger_.notice("Starting.");
|
||||
Setup_SQLite();
|
||||
Create_Tables();
|
||||
return 0;
|
||||
std::string DBType = Daemon()->ConfigGetString("storage.type");
|
||||
|
||||
if (DBType == "sqlite") {
|
||||
Setup_SQLite();
|
||||
} else if (DBType == "postgresql") {
|
||||
Setup_PostgreSQL();
|
||||
} else if (DBType == "mysql") {
|
||||
Setup_MySQL();
|
||||
} else if (DBType == "odbc") {
|
||||
Setup_ODBC();
|
||||
}
|
||||
|
||||
Create_Tables();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Storage::Stop() {
|
||||
|
||||
@@ -12,42 +12,49 @@
|
||||
#include "Poco/Data/Session.h"
|
||||
#include "Poco/Data/SessionPool.h"
|
||||
#include "Poco/Data/SQLite/Connector.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
|
||||
#include "RESTAPI_objects.h"
|
||||
#include "RESTAPI_FMSObjects.h"
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
#include "storage_firmwares.h"
|
||||
#include "storage_history.h"
|
||||
#include "storage_deviceTypes.h"
|
||||
|
||||
#ifndef SMALL_BUILD
|
||||
#include "Poco/Data/PostgreSQL/Connector.h"
|
||||
#include "Poco/Data/MySQL/Connector.h"
|
||||
#include "Poco/Data/ODBC/Connector.h"
|
||||
#endif
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
class Storage : public SubSystemServer {
|
||||
|
||||
public:
|
||||
|
||||
enum StorageType {
|
||||
sqlite,
|
||||
pgsql,
|
||||
mysql,
|
||||
odbc
|
||||
};
|
||||
|
||||
Storage() noexcept;
|
||||
|
||||
int Create_Tables();
|
||||
int Create_Firmwares();
|
||||
int Create_Callbacks();
|
||||
int Create_History();
|
||||
int Create_DeviceTypes();
|
||||
int Create_LatestFirmwareList();
|
||||
|
||||
bool AddCallback(uCentral::Objects::Callback & C);
|
||||
bool AddOrUpdateCallback(uCentral::Objects::Callback & C);
|
||||
bool UpdateCallback(std::string & UUID, uCentral::Objects::Callback & C);
|
||||
bool DeleteCallback(std::string & UUID);
|
||||
bool GetCallback(std::string & UUID, uCentral::Objects::Callback & C);
|
||||
bool GetCallbacks(uint64_t From, uint64_t HowMany, std::vector<uCentral::Objects::Callback> & Callbacks);
|
||||
|
||||
bool AddFirmware(uCentral::Objects::Firmware & F);
|
||||
bool UpdateFirmware(std::string & UUID, uCentral::Objects::Firmware & C);
|
||||
bool AddFirmware(FMSObjects::Firmware & F);
|
||||
bool UpdateFirmware(std::string & UUID, FMSObjects::Firmware & C);
|
||||
bool DeleteFirmware(std::string & UUID);
|
||||
bool GetFirmware(std::string & UUID, uCentral::Objects::Firmware & C);
|
||||
bool GetFirmwares(uint64_t From, uint64_t HowMany, std::vector<uCentral::Objects::Firmware> & Firmwares);
|
||||
bool GetFirmware(std::string & UUID, FMSObjects::Firmware & C);
|
||||
bool GetFirmwares(uint64_t From, uint64_t HowMany, std::vector<FMSObjects::Firmware> & Firmwares);
|
||||
bool BuildFirmwareManifest(Poco::JSON::Object & Manifest, uint64_t & Version);
|
||||
uint64_t FirmwareVersion();
|
||||
|
||||
bool AddLatestFirmware(std::string & Compatible, std::string &UUID);
|
||||
bool GetLatestFirmware(std::string & Compatible, uCentral::Objects::LatestFirmware &L);
|
||||
bool DeleteLatestFirmware(std::string & Compatible);
|
||||
bool GetLatestFirmwareList(uint64_t From, uint64_t HowMany, std::vector<uCentral::Objects::LatestFirmware> & LatestFirmwareList);
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
int Setup_SQLite();
|
||||
@@ -60,11 +67,23 @@ namespace uCentral {
|
||||
return instance_;
|
||||
}
|
||||
|
||||
#ifndef SMALL_BUILD
|
||||
int Setup_MySQL();
|
||||
int Setup_PostgreSQL();
|
||||
int Setup_ODBC();
|
||||
#endif
|
||||
|
||||
private:
|
||||
static Storage *instance_;
|
||||
std::unique_ptr<Poco::Data::SessionPool> Pool_= nullptr;
|
||||
std::unique_ptr<Poco::Data::SQLite::Connector> SQLiteConn_= nullptr;
|
||||
std::atomic_int64_t FirmwareVersion_ = 1 ;
|
||||
static Storage *instance_;
|
||||
std::unique_ptr<Poco::Data::SessionPool> Pool_= nullptr;
|
||||
StorageType dbType_ = sqlite;
|
||||
std::unique_ptr<Poco::Data::SQLite::Connector> SQLiteConn_= nullptr;
|
||||
#ifndef SMALL_BUILD
|
||||
std::unique_ptr<Poco::Data::PostgreSQL::Connector> PostgresConn_= nullptr;
|
||||
std::unique_ptr<Poco::Data::MySQL::Connector> MySQLConn_= nullptr;
|
||||
std::unique_ptr<Poco::Data::ODBC::Connector> ODBCConn_= nullptr;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
inline Storage * Storage() { return Storage::instance(); };
|
||||
|
||||
@@ -114,7 +114,7 @@ Poco::Net::SecureServerSocket PropertiesFileServerEntry::CreateSecureSocket(Poco
|
||||
P.dhUse2048Bits = true;
|
||||
P.caLocation = cas_;
|
||||
|
||||
auto Context = new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P);
|
||||
auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
|
||||
|
||||
if(!key_file_password_.empty()) {
|
||||
auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>( new MyPrivateKeyPassphraseHandler(KeyFilePassword(),L));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <regex>
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
@@ -17,9 +18,10 @@
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/DateTimeParser.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/Message.h"
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/Path.h"
|
||||
|
||||
#include "uCentralProtocol.h"
|
||||
#include "Daemon.h"
|
||||
@@ -390,4 +392,80 @@ namespace uCentral::Utils {
|
||||
}
|
||||
}
|
||||
|
||||
bool ValidEMailAddress(const std::string &email) {
|
||||
// define a regular expression
|
||||
const std::regex pattern
|
||||
("(\\w+)(\\.|_)?(\\w*)@(\\w+)(\\.(\\w+))+");
|
||||
|
||||
// try to match the string with the regular expression
|
||||
return std::regex_match(email, pattern);
|
||||
}
|
||||
|
||||
std::string LoadFile( const Poco::File & F) {
|
||||
std::string Result;
|
||||
try {
|
||||
std::ostringstream OS;
|
||||
std::ifstream IF(F.path());
|
||||
Poco::StreamCopier::copyStream(IF, OS);
|
||||
Result = OS.str();
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
void ReplaceVariables( std::string & Content , const Types::StringPairVec & P) {
|
||||
for(const auto &[Variable,Value]:P) {
|
||||
Poco::replaceInPlace(Content,"${" + Variable + "}", Value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string FindMediaType(const Poco::File &F) {
|
||||
Poco::Path P(F.path());
|
||||
const auto E = P.getExtension();
|
||||
if(E=="png")
|
||||
return "image/png";
|
||||
if(E=="gif")
|
||||
return "image/gif";
|
||||
if(E=="jpeg")
|
||||
return "image/jpeg";
|
||||
if(E=="jpg")
|
||||
return "image/jpeg";
|
||||
if(E=="svg")
|
||||
return "image/svg";
|
||||
if(E=="html")
|
||||
return "text/html";
|
||||
if(E=="css")
|
||||
return "text/css";
|
||||
if(E=="js")
|
||||
return "application/javascript";
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
std::string BinaryFileToHexString(const Poco::File &F) {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
std::string Result;
|
||||
try {
|
||||
std::ifstream IF(F.path());
|
||||
|
||||
int Count = 0;
|
||||
while (IF.good()) {
|
||||
if (Count)
|
||||
Result += ", ";
|
||||
if ((Count % 32) == 0)
|
||||
Result += "\r\n";
|
||||
Count++;
|
||||
unsigned char C = IF.get();
|
||||
Result += "0x";
|
||||
Result += (char) (hex[(C & 0xf0) >> 4]);
|
||||
Result += (char) (hex[(C & 0x0f)]);
|
||||
}
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
10
src/Utils.h
10
src/Utils.h
@@ -13,6 +13,9 @@
|
||||
#include <string>
|
||||
|
||||
#include "Poco/Net/NetworkInterface.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/File.h"
|
||||
#include "uCentralTypes.h"
|
||||
|
||||
#define DBGLINE { std::cout << __FILE__ << ":" << __func__ << ":" << __LINE__ << std::endl; };
|
||||
|
||||
@@ -48,5 +51,12 @@ namespace uCentral::Utils {
|
||||
|
||||
[[nodiscard]] uint64_t GetDefaultMacAsInt64();
|
||||
[[nodiscard]] uint64_t GetSystemId();
|
||||
|
||||
[[nodiscard]] bool ValidEMailAddress(const std::string &E);
|
||||
[[nodiscard]] std::string LoadFile( const Poco::File & F);
|
||||
void ReplaceVariables( std::string & Content , const Types::StringPairVec & P);
|
||||
|
||||
[[nodiscard]] std::string FindMediaType(const Poco::File &F);
|
||||
[[nodiscard]] std::string BinaryFileToHexString( const Poco::File &F);
|
||||
}
|
||||
#endif // UCENTRALGW_UTILS_H
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-09.
|
||||
//
|
||||
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
/*
|
||||
uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
uri:
|
||||
type: string
|
||||
creator:
|
||||
type: string
|
||||
location:
|
||||
type: string
|
||||
format: uri
|
||||
token:
|
||||
type: string
|
||||
tokenType:
|
||||
type: string
|
||||
created:
|
||||
type: string
|
||||
format: 'date-time'
|
||||
expires:
|
||||
type: string
|
||||
format: 'date-time'
|
||||
|
||||
*/
|
||||
|
||||
typedef Poco::Tuple<
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
uint64_t,
|
||||
uint64_t
|
||||
> CallbackRecordTuple;
|
||||
typedef std::vector<CallbackRecordTuple> CallbackRecordList;
|
||||
|
||||
/*
|
||||
"UUID VARCHAR(64) PRIMARY KEY, "
|
||||
"URI TEXT, "
|
||||
"Location VARCHAR(128),"
|
||||
"Token TEXT,"
|
||||
"TokenType VARCHAR(64), ",
|
||||
"Creator VARCHAR(128), "
|
||||
"Topics TEXT, "
|
||||
"Created BIGINT, "
|
||||
"Expires BIGINT",
|
||||
*/
|
||||
|
||||
bool Storage::AddCallback(uCentral::Objects::Callback & C) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
std::string st{"INSERT INTO Callbacks ("
|
||||
"UUID, URI, Location, Token, TokenType, Creator, Topics, Created, Expires"
|
||||
") VALUES(?,?,?,?,?,?,?,?,?)"
|
||||
};
|
||||
|
||||
Insert << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(C.UUID),
|
||||
Poco::Data::Keywords::use(C.URI),
|
||||
Poco::Data::Keywords::use(C.Location),
|
||||
Poco::Data::Keywords::use(C.Token),
|
||||
Poco::Data::Keywords::use(C.TokenType),
|
||||
Poco::Data::Keywords::use(C.Creator),
|
||||
Poco::Data::Keywords::use(C.Topics),
|
||||
Poco::Data::Keywords::use(C.Created),
|
||||
Poco::Data::Keywords::use(C.Expires);
|
||||
Insert.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::UpdateCallback(std::string & UUID, uCentral::Objects::Callback & C) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string st{"UPDATE Callbacks "
|
||||
" SET URI=?, Location=?, Token=?, TokenType=?, Creator=?, Topics=?, Created=?, Expires=?"
|
||||
" WHERE UUID=?"
|
||||
};
|
||||
|
||||
Update << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(C.URI),
|
||||
Poco::Data::Keywords::use(C.Location),
|
||||
Poco::Data::Keywords::use(C.Token),
|
||||
Poco::Data::Keywords::use(C.TokenType),
|
||||
Poco::Data::Keywords::use(C.Creator),
|
||||
Poco::Data::Keywords::use(C.Topics),
|
||||
Poco::Data::Keywords::use(C.Created),
|
||||
Poco::Data::Keywords::use(C.Expires),
|
||||
Poco::Data::Keywords::use(C.UUID);
|
||||
Update.execute();
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::AddOrUpdateCallback(uCentral::Objects::Callback & C) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{"SELECT UUID FROM Callbacks WHERE UUID=?"};
|
||||
std::string TmpUUID;
|
||||
Select << ConvertParams(st),
|
||||
Poco::Data::Keywords::into(TmpUUID),
|
||||
Poco::Data::Keywords::use(C.UUID);
|
||||
Select.execute();
|
||||
if(TmpUUID.empty()) {
|
||||
return AddCallback(C);
|
||||
}
|
||||
else {
|
||||
return UpdateCallback(TmpUUID, C);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::DeleteCallback(std::string & UUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string st{"DELETE FROM Callbacks WHERE UUID=?"};
|
||||
|
||||
Delete << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Delete.execute();
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetCallback(std::string & UUID, uCentral::Objects::Callback & C) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{"SELECT "
|
||||
"UUID, URI, Location, Token, TokenType, Creator, Topics, Created, Expires"
|
||||
" FROM Callbacks WHERE UUID=?"
|
||||
};
|
||||
Select << ConvertParams(st),
|
||||
Poco::Data::Keywords::into(C.UUID),
|
||||
Poco::Data::Keywords::into(C.URI),
|
||||
Poco::Data::Keywords::into(C.Location),
|
||||
Poco::Data::Keywords::into(C.Token),
|
||||
Poco::Data::Keywords::into(C.TokenType),
|
||||
Poco::Data::Keywords::into(C.Creator),
|
||||
Poco::Data::Keywords::into(C.Topics),
|
||||
Poco::Data::Keywords::into(C.Created),
|
||||
Poco::Data::Keywords::into(C.Expires),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Select.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetCallbacks(uint64_t From, uint64_t HowMany, std::vector<uCentral::Objects::Callback> & Callbacks) {
|
||||
try {
|
||||
CallbackRecordList Records;
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{ "SELECT "
|
||||
" UUID, URI, Location, Token, TokenType, Creator, Topics, Created, Expires"
|
||||
" FROM Callbacks"
|
||||
};
|
||||
Select << ConvertParams(st),
|
||||
Poco::Data::Keywords::into(Records),
|
||||
Poco::Data::Keywords::range(From,From+HowMany);
|
||||
Select.execute();
|
||||
|
||||
for(const auto &i:Records) {
|
||||
uCentral::Objects::Callback C{
|
||||
.UUID = i.get<0>(),
|
||||
.URI = i.get<1>(),
|
||||
.Location = i.get<2>(),
|
||||
.Token = i.get<3>(),
|
||||
.TokenType = i.get<4>(),
|
||||
.Creator = i.get<5>(),
|
||||
.Topics = i.get<6>(),
|
||||
.Created = i.get<7>(),
|
||||
.Expires = i.get<8>()
|
||||
};
|
||||
|
||||
Callbacks.push_back(C);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
5
src/storage_deviceTypes.cpp
Normal file
5
src/storage_deviceTypes.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-12.
|
||||
//
|
||||
|
||||
#include "storage_deviceTypes.h"
|
||||
47
src/storage_deviceTypes.h
Normal file
47
src/storage_deviceTypes.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-12.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFMS_STORAGE_DEVICETYPES_H
|
||||
#define UCENTRALFMS_STORAGE_DEVICETYPES_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace uCentral {
|
||||
static const std::string DBNAME_DEVICETYPES{"deviceTypes"};
|
||||
static const std::string DBFIELDS_DEVICETYPES_CREATION {
|
||||
" id varchar(36) UNIQUE PRIMARY KEY, "
|
||||
"deviceType varchar, "
|
||||
"manufacturer varchar, "
|
||||
"model varchar, "
|
||||
"policy varchar, "
|
||||
"notes varchar, "
|
||||
"lastUpdate bigint, "
|
||||
"created bigint "
|
||||
};
|
||||
|
||||
static const std::string DBFIELDS_DEVICETYPES_SELECT{
|
||||
" id, "
|
||||
"deviceType, "
|
||||
"manufacturer, "
|
||||
"model, "
|
||||
"policy, "
|
||||
"notes, "
|
||||
"lastUpdate, "
|
||||
"created "
|
||||
};
|
||||
|
||||
static const std::string DBFIELDS_DEVICETYPES_UPDATE {
|
||||
" id=?, "
|
||||
"deviceType=?, "
|
||||
"manufacturer=?, "
|
||||
"model=?, "
|
||||
"policy=?, "
|
||||
"notes=?, "
|
||||
"lastUpdate=?, "
|
||||
"created=? "
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //UCENTRALFMS_STORAGE_DEVICETYPES_H
|
||||
@@ -5,114 +5,91 @@
|
||||
#include "StorageService.h"
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
#include "RESTAPI_FMSObjects.h"
|
||||
#include "RESTAPI_utils.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
/*
|
||||
std::string UUID;
|
||||
std::string Description;
|
||||
std::string FirmwareFileName;
|
||||
std::string FirmwareVersion;
|
||||
std::string FirmwareHash;
|
||||
std::string FirmwareLatestDoc;
|
||||
std::string Owner;
|
||||
std::string Location;
|
||||
std::string Compatible;
|
||||
std::string Uploader;
|
||||
std::string Digest;
|
||||
std::string S3URI;
|
||||
uint64_t DownloadCount;
|
||||
uint64_t Size;
|
||||
uint64_t Uploaded;
|
||||
uint64_t FirmwareDate;
|
||||
uint64_t Latest;
|
||||
*/
|
||||
|
||||
typedef Poco::Tuple<
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
uint64_t
|
||||
> FirmwareRecordTuple;
|
||||
typedef std::vector<FirmwareRecordTuple> FirmwareRecordList;
|
||||
|
||||
uint64_t Storage::FirmwareVersion() {
|
||||
return FirmwareVersion_;
|
||||
bool Convert(const FirmwaresRecord &T, FMSObjects::Firmware & F) {
|
||||
F.id = T.get<0>();
|
||||
F.deviceType = T.get<1>();
|
||||
F.description = T.get<2>();
|
||||
F.revision = T.get<3>();
|
||||
F.uri = T.get<4>();
|
||||
F.image = T.get<5>();
|
||||
F.imageDate = T.get<6>();
|
||||
F.size = T.get<7>();
|
||||
F.downloadCount = T.get<8>();
|
||||
F.firmwareHash = T.get<9>();
|
||||
F.owner = T.get<10>();
|
||||
F.location = T.get<11>();
|
||||
F.uploader = T.get<12>();
|
||||
F.digest = T.get<13>();
|
||||
F.latest = T.get<14>();
|
||||
F.notes = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(T.get<15>());
|
||||
F.created = T.get<16>();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Storage::AddFirmware(uCentral::Objects::Firmware & F) {
|
||||
bool Convert(const FMSObjects::Firmware & F, FirmwaresRecord & T) {
|
||||
T.set<0>(F.id);
|
||||
T.set<1>(F.deviceType);
|
||||
T.set<2>(F.description);
|
||||
T.set<3>(F.revision);
|
||||
T.set<4>(F.uri);
|
||||
T.set<5>(F.image);
|
||||
T.set<6>(F.imageDate);
|
||||
T.set<7>(F.size);
|
||||
T.set<8>(F.downloadCount);
|
||||
T.set<9>(F.firmwareHash);
|
||||
T.set<10>(F.owner);
|
||||
T.set<11>(F.location);
|
||||
T.set<12>(F.uploader);
|
||||
T.set<13>(F.digest);
|
||||
T.set<14>(F.latest);
|
||||
T.set<15>(RESTAPI_utils::to_string(F.notes));
|
||||
T.set<16>(F.created);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Storage::AddFirmware(FMSObjects::Firmware & F) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
/*
|
||||
"UUID VARCHAR(64) PRIMARY KEY, "
|
||||
"Description VARCHAR(128), "
|
||||
"Owner VARCHAR(128), "
|
||||
"Location TEXT, ",
|
||||
"Compatible VARCHAR(128), "
|
||||
"Uploader VARCHAR(128), "
|
||||
"Digest TEXT, "
|
||||
"FirmwareFileName TEXT, "
|
||||
"FirmwareVersion VARCHAR(128), "
|
||||
"FirmwareHash VARCHAR(32), "
|
||||
"FirmwareLatestDoc TEXT, "
|
||||
"S3URI TEXT "
|
||||
"FirmwareDate BIGINT, "
|
||||
"Uploaded BIGINT, "
|
||||
"DownloadCount BIGINT, "
|
||||
"Size BIGINT,
|
||||
"Latest BIGINT"
|
||||
*/
|
||||
|
||||
// find the older software and change to latest = 0
|
||||
if(F.Latest)
|
||||
if(F.latest)
|
||||
{
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::string st{"UPDATE Firmwares SET Latest=0 WHERE Compatible=? AND Latest=1"};
|
||||
std::string st{"UPDATE " + DBNAME_FIRMWARES + " SET latest=0 WHERE deviceType=? AND Latest=1"};
|
||||
Update << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(F.Compatible);
|
||||
Poco::Data::Keywords::use(F.deviceType);
|
||||
Update.execute();
|
||||
}
|
||||
|
||||
std::string st{"INSERT INTO Firmwares ("
|
||||
"UUID, Description, Owner, Location, Compatible, Uploader, Digest, "
|
||||
"FirmwareFileName, FirmwareVersion, FirmwareHash, FirmwareLatestDoc, "
|
||||
"S3URI, FirmwareDate, Uploaded, DownloadCount, Size, Latest "
|
||||
auto Notes = RESTAPI_utils::to_string(F.notes);
|
||||
std::string st{"INSERT INTO " + DBNAME_FIRMWARES + " (" +
|
||||
DBFIELDS_FIRMWARES_SELECT +
|
||||
") VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"};
|
||||
|
||||
Insert << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(F.UUID),
|
||||
Poco::Data::Keywords::use(F.Description),
|
||||
Poco::Data::Keywords::use(F.Owner),
|
||||
Poco::Data::Keywords::use(F.Location),
|
||||
Poco::Data::Keywords::use(F.Compatible),
|
||||
Poco::Data::Keywords::use(F.Uploader),
|
||||
Poco::Data::Keywords::use(F.Digest),
|
||||
Poco::Data::Keywords::use(F.FirmwareFileName),
|
||||
Poco::Data::Keywords::use(F.FirmwareVersion),
|
||||
Poco::Data::Keywords::use(F.FirmwareHash),
|
||||
Poco::Data::Keywords::use(F.FirmwareLatestDoc),
|
||||
Poco::Data::Keywords::use(F.S3URI),
|
||||
Poco::Data::Keywords::use(F.FirmwareDate),
|
||||
Poco::Data::Keywords::use(F.Uploaded),
|
||||
Poco::Data::Keywords::use(F.DownloadCount),
|
||||
Poco::Data::Keywords::use(F.Size),
|
||||
Poco::Data::Keywords::use(F.Latest);
|
||||
Poco::Data::Keywords::use(F.id),
|
||||
Poco::Data::Keywords::use(F.deviceType),
|
||||
Poco::Data::Keywords::use(F.description),
|
||||
Poco::Data::Keywords::use(F.revision),
|
||||
Poco::Data::Keywords::use(F.uri),
|
||||
Poco::Data::Keywords::use(F.image),
|
||||
Poco::Data::Keywords::use(F.imageDate),
|
||||
Poco::Data::Keywords::use(F.size),
|
||||
Poco::Data::Keywords::use(F.downloadCount),
|
||||
Poco::Data::Keywords::use(F.firmwareHash),
|
||||
Poco::Data::Keywords::use(F.owner),
|
||||
Poco::Data::Keywords::use(F.location),
|
||||
Poco::Data::Keywords::use(F.uploader),
|
||||
Poco::Data::Keywords::use(F.digest),
|
||||
Poco::Data::Keywords::use(F.latest),
|
||||
Poco::Data::Keywords::use(Notes),
|
||||
Poco::Data::Keywords::use(F.created);
|
||||
Insert.execute();
|
||||
FirmwareVersion_++;
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -121,36 +98,35 @@ namespace uCentral {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::UpdateFirmware(std::string & UUID, uCentral::Objects::Firmware & F) {
|
||||
bool Storage::UpdateFirmware(std::string & ID, FMSObjects::Firmware & F) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string st{"UPDATE Firmwares "
|
||||
" Description, Owner, Location, Compatible, Uploader, Digest, "
|
||||
" FirmwareFileName, FirmwareVersion, FirmwareHash, FirmwareLatestDoc, "
|
||||
" S3URI, FirmwareDate, Uploaded, DownloadCount, Size"
|
||||
" WHERE UUID=?"};
|
||||
std::string st{"UPDATE " + DBNAME_FIRMWARES + " set " + DBFIELDS_DEVICETYPES_UPDATE +
|
||||
" WHERE id=?"};
|
||||
auto Notes = RESTAPI_utils::to_string(F.notes);
|
||||
|
||||
Update << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(F.Description),
|
||||
Poco::Data::Keywords::use(F.Owner),
|
||||
Poco::Data::Keywords::use(F.Location),
|
||||
Poco::Data::Keywords::use(F.Compatible),
|
||||
Poco::Data::Keywords::use(F.Uploader),
|
||||
Poco::Data::Keywords::use(F.Digest),
|
||||
Poco::Data::Keywords::use(F.FirmwareFileName),
|
||||
Poco::Data::Keywords::use(F.FirmwareVersion),
|
||||
Poco::Data::Keywords::use(F.FirmwareHash),
|
||||
Poco::Data::Keywords::use(F.FirmwareLatestDoc),
|
||||
Poco::Data::Keywords::use(F.S3URI),
|
||||
Poco::Data::Keywords::use(F.FirmwareDate),
|
||||
Poco::Data::Keywords::use(F.Uploaded),
|
||||
Poco::Data::Keywords::use(F.DownloadCount),
|
||||
Poco::Data::Keywords::use(F.Size),
|
||||
Poco::Data::Keywords::use(F.UUID);
|
||||
Update << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(F.id),
|
||||
Poco::Data::Keywords::use(F.deviceType),
|
||||
Poco::Data::Keywords::use(F.description),
|
||||
Poco::Data::Keywords::use(F.revision),
|
||||
Poco::Data::Keywords::use(F.uri),
|
||||
Poco::Data::Keywords::use(F.image),
|
||||
Poco::Data::Keywords::use(F.imageDate),
|
||||
Poco::Data::Keywords::use(F.size),
|
||||
Poco::Data::Keywords::use(F.downloadCount),
|
||||
Poco::Data::Keywords::use(F.firmwareHash),
|
||||
Poco::Data::Keywords::use(F.owner),
|
||||
Poco::Data::Keywords::use(F.location),
|
||||
Poco::Data::Keywords::use(F.uploader),
|
||||
Poco::Data::Keywords::use(F.digest),
|
||||
Poco::Data::Keywords::use(F.latest),
|
||||
Poco::Data::Keywords::use(Notes),
|
||||
Poco::Data::Keywords::use(F.created);
|
||||
Poco::Data::Keywords::use(ID);
|
||||
Update.execute();
|
||||
FirmwareVersion_++;
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -159,17 +135,15 @@ namespace uCentral {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::DeleteFirmware(std::string & UUID) {
|
||||
bool Storage::DeleteFirmware(std::string & ID) {
|
||||
try {
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string st{"DELETE FROM Firmwares WHERE UUID=?"};
|
||||
std::string st{"DELETE FROM " + DBNAME_FIRMWARES + " WHERE id=?"};
|
||||
Delete << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Poco::Data::Keywords::use(ID);
|
||||
Delete.execute();
|
||||
FirmwareVersion_++;
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -178,39 +152,25 @@ namespace uCentral {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetFirmware(std::string & UUID, uCentral::Objects::Firmware & F) {
|
||||
bool Storage::GetFirmware(std::string & ID, FMSObjects::Firmware & F) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{"SELECT "
|
||||
"UUID, Description, Owner, Location, Compatible, Uploader, Digest, "
|
||||
"FirmwareFileName, FirmwareVersion, FirmwareHash, FirmwareLatestDoc, "
|
||||
"S3URI, FirmwareDate, Uploaded, DownloadCount, Size, Latest "
|
||||
" FROM Firmwares WHERE UUID=?"};
|
||||
std::string st{"SELECT " + DBFIELDS_FIRMWARES_SELECT +
|
||||
" FROM " + DBNAME_FIRMWARES + " WHERE id=?"};
|
||||
|
||||
FirmwaresRecordList Records;
|
||||
Select << ConvertParams(st),
|
||||
Poco::Data::Keywords::into(F.UUID),
|
||||
Poco::Data::Keywords::into(F.Description),
|
||||
Poco::Data::Keywords::into(F.Owner),
|
||||
Poco::Data::Keywords::into(F.Location),
|
||||
Poco::Data::Keywords::into(F.Compatible),
|
||||
Poco::Data::Keywords::into(F.Uploader),
|
||||
Poco::Data::Keywords::into(F.Digest),
|
||||
Poco::Data::Keywords::into(F.FirmwareFileName),
|
||||
Poco::Data::Keywords::into(F.FirmwareVersion),
|
||||
Poco::Data::Keywords::into(F.FirmwareHash),
|
||||
Poco::Data::Keywords::into(F.FirmwareLatestDoc),
|
||||
Poco::Data::Keywords::into(F.S3URI),
|
||||
Poco::Data::Keywords::into(F.FirmwareDate),
|
||||
Poco::Data::Keywords::into(F.Uploaded),
|
||||
Poco::Data::Keywords::into(F.DownloadCount),
|
||||
Poco::Data::Keywords::into(F.Size),
|
||||
Poco::Data::Keywords::into(F.Latest),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Poco::Data::Keywords::into(Records),
|
||||
Poco::Data::Keywords::use(ID);
|
||||
Select.execute();
|
||||
|
||||
return !F.UUID.empty();
|
||||
if(Records.empty())
|
||||
return false;
|
||||
|
||||
Convert(Records[0],F);
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
@@ -218,118 +178,31 @@ namespace uCentral {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetFirmwares(uint64_t From, uint64_t HowMany, std::vector<uCentral::Objects::Firmware> & Firmwares) {
|
||||
bool Storage::GetFirmwares(uint64_t From, uint64_t HowMany, FMSObjects::FirmwareVec & Firmwares) {
|
||||
try {
|
||||
FirmwareRecordList Records;
|
||||
FirmwaresRecordList Records;
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{"SELECT "
|
||||
"UUID, Description, Owner, Location, Compatible, Uploader, Digest, "
|
||||
"FirmwareFileName, FirmwareVersion, FirmwareHash, FirmwareLatestDoc, "
|
||||
"S3URI, FirmwareDate, Uploaded, DownloadCount, Size, Latest "
|
||||
" FROM Firmwares"};
|
||||
std::string st{"SELECT " + DBFIELDS_FIRMWARES_SELECT +
|
||||
" FROM " + DBNAME_FIRMWARES };
|
||||
|
||||
Select << ConvertParams(st),
|
||||
Poco::Data::Keywords::into(Records),
|
||||
Poco::Data::Keywords::range(From, From + HowMany);
|
||||
Select.execute();
|
||||
|
||||
for(auto const &i:Records) {
|
||||
uCentral::Objects::Firmware F{
|
||||
.UUID = i.get<0>(),
|
||||
.Description= i.get<1>(),
|
||||
.Owner= i.get<2>(),
|
||||
.Location= i.get<3>(),
|
||||
.Compatible= i.get<4>(),
|
||||
.Uploader= i.get<5>(),
|
||||
.Digest= i.get<6>(),
|
||||
.FirmwareFileName= i.get<7>(),
|
||||
.FirmwareVersion= i.get<8>(),
|
||||
.FirmwareHash= i.get<9>(),
|
||||
.FirmwareLatestDoc= i.get<10>(),
|
||||
.S3URI= i.get<11>(),
|
||||
.FirmwareDate= i.get<12>(),
|
||||
.Uploaded= i.get<13>(),
|
||||
.DownloadCount= i.get<14>(),
|
||||
.Size= i.get<15>(),
|
||||
.Latest = (bool) (i.get<16>()!=0)
|
||||
};
|
||||
for(const auto &R:Records) {
|
||||
FMSObjects::Firmware F;
|
||||
Convert(R,F);
|
||||
Firmwares.push_back(F);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
"Compatible VARCHAR(128), "
|
||||
"Uploader VARCHAR(128), "
|
||||
"FirmwareVersion VARCHAR(128), "
|
||||
"S3URI TEXT )",
|
||||
"Uploaded BIGINT, "
|
||||
"Size BIGINT, "
|
||||
"FirmwareDate BIGINT, "
|
||||
*/
|
||||
|
||||
typedef Poco::Tuple<
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
uint64_t
|
||||
> FirmwareManifestTuple;
|
||||
typedef std::vector<FirmwareManifestTuple> FirmwareManifestList;
|
||||
|
||||
|
||||
bool Storage::BuildFirmwareManifest(Poco::JSON::Object & Manifest, uint64_t & Version) {
|
||||
try {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
FirmwareManifestList Records;
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{"SELECT Compatible,Uploader,FirmwareVersion,S3URI,Uploaded,Size,FirmwareDate,Latest FROM Firmwares"};
|
||||
|
||||
Select << ConvertParams(st),
|
||||
Poco::Data::Keywords::into(Records);
|
||||
Select.execute();
|
||||
|
||||
Poco::JSON::Array Elements;
|
||||
for(const auto &i:Records) {
|
||||
Poco::JSON::Object Obj;
|
||||
|
||||
Obj.set("compatible", i.get<0>());
|
||||
Obj.set("uploader",i.get<1>());
|
||||
Obj.set("version",i.get<2>());
|
||||
Obj.set("uri",i.get<3>());
|
||||
Obj.set("uploaded",i.get<4>());
|
||||
Obj.set("size",i.get<5>());
|
||||
Obj.set("date", i.get<6>());
|
||||
Obj.set("latest", (bool) (i.get<7>() != 0));
|
||||
|
||||
Elements.add(Obj);
|
||||
}
|
||||
|
||||
Manifest.set("firmwares",Elements);
|
||||
Version = FirmwareVersion_;
|
||||
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
93
src/storage_firmwares.h
Normal file
93
src/storage_firmwares.h
Normal file
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-12.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFMS_STORAGE_FIRMWARES_H
|
||||
#define UCENTRALFMS_STORAGE_FIRMWARES_H
|
||||
|
||||
#include "Poco/Tuple.h"
|
||||
|
||||
namespace uCentral {
|
||||
static const std::string DBNAME_FIRMWARES{"firmwares"};
|
||||
static const std::string DBFIELDS_FIRMWARES_CREATION {
|
||||
"Id varchar(36) UNIQUE PRIMARY KEY, "
|
||||
"deviceType varchar, "
|
||||
"description varchar, "
|
||||
"revision varchar, "
|
||||
"uri varchar, "
|
||||
"image varchar, "
|
||||
"imageDate bigint, "
|
||||
"size bigint, "
|
||||
"downloadCount bigint, "
|
||||
"firmwareHash varchar, "
|
||||
"owner varchar, "
|
||||
"location varchar, "
|
||||
"uploader varchar, "
|
||||
"digest varchar, "
|
||||
"latest int, "
|
||||
"notes text, "
|
||||
"created bigint"
|
||||
};
|
||||
|
||||
static const std::string DBFIELDS_FIRMWARES_SELECT{
|
||||
" Id, "
|
||||
"deviceType, "
|
||||
"description, "
|
||||
"revision, "
|
||||
"uri, "
|
||||
"image, "
|
||||
"imageDate, "
|
||||
"size, "
|
||||
"downloadCount, "
|
||||
"firmwareHash, "
|
||||
"owner, "
|
||||
"location, "
|
||||
"uploader, "
|
||||
"digest, "
|
||||
"latest, "
|
||||
"notes, "
|
||||
"created "
|
||||
};
|
||||
|
||||
static const std::string DBFIELDS_FIRMWARES_UPDATE {
|
||||
" Id=?, "
|
||||
"deviceType=?, "
|
||||
"description=?, "
|
||||
"revision=?, "
|
||||
"uri=?, "
|
||||
"image=?, "
|
||||
"imageDate=?, "
|
||||
"size=?, "
|
||||
"downloadCount=?, "
|
||||
"firmwareHash=?, "
|
||||
"owner=?, "
|
||||
"location=?, "
|
||||
"uploader=?, "
|
||||
"digest=?, "
|
||||
"latest=?, "
|
||||
"notes=?, "
|
||||
"created=? "
|
||||
};
|
||||
|
||||
typedef Poco::Tuple<
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
uint64_t,
|
||||
std::string,
|
||||
uint64_t> FirmwaresRecord;
|
||||
typedef std::vector<FirmwaresRecord> FirmwaresRecordList;
|
||||
|
||||
}
|
||||
#endif //UCENTRALFMS_STORAGE_FIRMWARES_H
|
||||
5
src/storage_history.cpp
Normal file
5
src/storage_history.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-12.
|
||||
//
|
||||
|
||||
#include "storage_history.h"
|
||||
35
src/storage_history.h
Normal file
35
src/storage_history.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-12.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFMS_STORAGE_HISTORY_H
|
||||
#define UCENTRALFMS_STORAGE_HISTORY_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace uCentral {
|
||||
static const std::string DBNAME_HISTORY{"history"};
|
||||
static const std::string DBFIELDS_HISTORY_CREATION {
|
||||
" id varchar(36) UNIQUE PRIMARY KEY, "
|
||||
"serialNumber varchar, "
|
||||
"upgraded bigint, "
|
||||
"commandUUID varchar "
|
||||
};
|
||||
|
||||
static const std::string DBFIELDS_HISTORY_SELECT{
|
||||
" id, "
|
||||
"serialNumber, "
|
||||
"upgraded, "
|
||||
"commandUUID "
|
||||
};
|
||||
|
||||
static const std::string DBFIELDS_HISTORY_UPDATE {
|
||||
" id=?, "
|
||||
"serialNumber=?, "
|
||||
"upgraded=?, "
|
||||
"commandUUID=? "
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALFMS_STORAGE_HISTORY_H
|
||||
@@ -1,124 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-05-09.
|
||||
//
|
||||
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
typedef Poco::Tuple<
|
||||
std::string,
|
||||
std::string,
|
||||
uint64_t> LatestFirmwareRecordTuple;
|
||||
typedef std::vector<LatestFirmwareRecordTuple> LatestFirmwareRecordList;
|
||||
|
||||
bool Storage::AddLatestFirmware(std::string & Compatible, std::string &UUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string TmpUUID;
|
||||
std::string st{"SELECT UUID From LatestFirmwares WHERE Compatible=?"};
|
||||
|
||||
Select << ConvertParams(st) ,
|
||||
Poco::Data::Keywords::into(TmpUUID),
|
||||
Poco::Data::Keywords::use(Compatible);
|
||||
Select.execute();
|
||||
|
||||
uint64_t LastUpdated = time(nullptr);
|
||||
|
||||
if(TmpUUID.empty()) {
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
std::string st1{"INSERT INTO LatestFirmwares (Compatible, UUID, LastUpdated) VALUES(?,?,?)"};
|
||||
Insert << ConvertParams(st1),
|
||||
Poco::Data::Keywords::use(Compatible),
|
||||
Poco::Data::Keywords::use(UUID),
|
||||
Poco::Data::Keywords::use(LastUpdated);
|
||||
Insert.execute();
|
||||
} else {
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::string st1{"UPDATE LatestFirmwares SET UUID=?, LastUpdated=? WHERE Compatible=?"};
|
||||
Update << ConvertParams(st1),
|
||||
Poco::Data::Keywords::use(UUID),
|
||||
Poco::Data::Keywords::use(LastUpdated),
|
||||
Poco::Data::Keywords::use(Compatible);
|
||||
Update.execute();
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetLatestFirmware(std::string & Compatible, uCentral::Objects::LatestFirmware &L) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string TmpUUID;
|
||||
std::string st{"SELECT Compatible, UUID, LastUpdated From LatestFirmwares WHERE Compatible=?"};
|
||||
|
||||
Select << ConvertParams(st) ,
|
||||
Poco::Data::Keywords::into(L.Compatible),
|
||||
Poco::Data::Keywords::into(L.UUID),
|
||||
Poco::Data::Keywords::into(L.LastUpdated),
|
||||
Poco::Data::Keywords::use(Compatible);
|
||||
Select.execute();
|
||||
|
||||
return !L.UUID.empty();
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::DeleteLatestFirmware(std::string & Compatible) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string TmpUUID;
|
||||
std::string st{"DELETE From LatestFirmwares WHERE Compatible=?"};
|
||||
|
||||
Delete << ConvertParams(st),
|
||||
Poco::Data::Keywords::use(Compatible);
|
||||
Delete.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetLatestFirmwareList(uint64_t From, uint64_t HowMany, std::vector<uCentral::Objects::LatestFirmware> & LatestFirmwareList) {
|
||||
try {
|
||||
LatestFirmwareRecordList Records;
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{"SELECT Compatible, UUID FROM LatestFirmwares"};
|
||||
|
||||
Select << ConvertParams(st),
|
||||
Poco::Data::Keywords::into(Records),
|
||||
Poco::Data::Keywords::range(From, From + HowMany);
|
||||
Select.execute();
|
||||
|
||||
for(const auto &i:Records) {
|
||||
uCentral::Objects::LatestFirmware L{
|
||||
.Compatible = i.get<0>(),
|
||||
.UUID = i.get<1>()
|
||||
};
|
||||
LatestFirmwareList.push_back(L);
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
46
src/storage_mysql.cpp
Normal file
46
src/storage_mysql.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Daemon.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
#ifdef SMALL_BUILD
|
||||
int Service::Setup_MySQL() { uCentral::instance()->exit(Poco::Util::Application::EXIT_CONFIG);}
|
||||
#else
|
||||
|
||||
int Storage::Setup_MySQL() {
|
||||
|
||||
dbType_ = mysql ;
|
||||
|
||||
Logger_.notice("MySQL Storage enabled.");
|
||||
auto NumSessions = Daemon()->ConfigGetInt("storage.type.mysql.maxsessions", 64);
|
||||
auto IdleTime = Daemon()->ConfigGetInt("storage.type.mysql.idletime", 60);
|
||||
auto Host = Daemon()->ConfigGetString("storage.type.mysql.host");
|
||||
auto Username = Daemon()->ConfigGetString("storage.type.mysql.username");
|
||||
auto Password = Daemon()->ConfigGetString("storage.type.mysql.password");
|
||||
auto Database = Daemon()->ConfigGetString("storage.type.mysql.database");
|
||||
auto Port = Daemon()->ConfigGetString("storage.type.mysql.port");
|
||||
|
||||
std::string ConnectionStr =
|
||||
"host=" + Host +
|
||||
";user=" + Username +
|
||||
";password=" + Password +
|
||||
";db=" + Database +
|
||||
";port=" + Port +
|
||||
";compress=true;auto-reconnect=true";
|
||||
|
||||
MySQLConn_ = std::make_unique<Poco::Data::MySQL::Connector>();
|
||||
MySQLConn_->registerConnector();
|
||||
Pool_ = std::make_unique<Poco::Data::SessionPool>(MySQLConn_->name(), ConnectionStr, 4, NumSessions, IdleTime);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
47
src/storage_odbc.cpp
Normal file
47
src/storage_odbc.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Daemon.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
#ifdef SMALL_BUILD
|
||||
int Service::Setup_ODBC() { uCentral::instance()->exit(Poco::Util::Application::EXIT_CONFIG);}
|
||||
#else
|
||||
int Storage::Setup_ODBC() {
|
||||
|
||||
dbType_ = odbc ;
|
||||
|
||||
Logger_.notice("ODBC Storage enabled.");
|
||||
|
||||
auto NumSessions = Daemon()->ConfigGetInt("storage.type.postgresql.maxsessions", 64);
|
||||
auto IdleTime = Daemon()->ConfigGetInt("storage.type.postgresql.idletime", 60);
|
||||
auto Host = Daemon()->ConfigGetString("storage.type.postgresql.host");
|
||||
auto Username = Daemon()->ConfigGetString("storage.type.postgresql.username");
|
||||
auto Password = Daemon()->ConfigGetString("storage.type.postgresql.password");
|
||||
auto Database = Daemon()->ConfigGetString("storage.type.postgresql.database");
|
||||
auto Port = Daemon()->ConfigGetString("storage.type.postgresql.port");
|
||||
auto ConnectionTimeout = Daemon()->ConfigGetString("storage.type.postgresql.connectiontimeout");
|
||||
|
||||
std::string ConnectionStr =
|
||||
"host=" + Host +
|
||||
" user=" + Username +
|
||||
" password=" + Password +
|
||||
" dbname=" + Database +
|
||||
" port=" + Port +
|
||||
" connect_timeout=" + ConnectionTimeout;
|
||||
|
||||
ODBCConn_ = std::make_unique<Poco::Data::ODBC::Connector>();
|
||||
ODBCConn_->registerConnector();
|
||||
Pool_ = std::make_unique<Poco::Data::SessionPool>(ODBCConn_->name(), ConnectionStr, 4, NumSessions, IdleTime);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
47
src/storage_pgql.cpp
Normal file
47
src/storage_pgql.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Daemon.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
#ifdef SMALL_BUILD
|
||||
int Service::Setup_PostgreSQL() { uCentral::instance()->exit(Poco::Util::Application::EXIT_CONFIG);}
|
||||
#else
|
||||
int Storage::Setup_PostgreSQL() {
|
||||
Logger_.notice("PostgreSQL Storage enabled.");
|
||||
|
||||
dbType_ = pgsql ;
|
||||
|
||||
auto NumSessions = Daemon()->ConfigGetInt("storage.type.postgresql.maxsessions", 64);
|
||||
auto IdleTime = Daemon()->ConfigGetInt("storage.type.postgresql.idletime", 60);
|
||||
auto Host = Daemon()->ConfigGetString("storage.type.postgresql.host");
|
||||
auto Username = Daemon()->ConfigGetString("storage.type.postgresql.username");
|
||||
auto Password = Daemon()->ConfigGetString("storage.type.postgresql.password");
|
||||
auto Database = Daemon()->ConfigGetString("storage.type.postgresql.database");
|
||||
auto Port = Daemon()->ConfigGetString("storage.type.postgresql.port");
|
||||
auto ConnectionTimeout = Daemon()->ConfigGetString("storage.type.postgresql.connectiontimeout");
|
||||
|
||||
std::string ConnectionStr =
|
||||
"host=" + Host +
|
||||
" user=" + Username +
|
||||
" password=" + Password +
|
||||
" dbname=" + Database +
|
||||
" port=" + Port +
|
||||
" connect_timeout=" + ConnectionTimeout;
|
||||
|
||||
PostgresConn_ = std::make_unique<Poco::Data::PostgreSQL::Connector>();
|
||||
PostgresConn_->registerConnector();
|
||||
Pool_ = std::make_unique<Poco::Data::SessionPool>(PostgresConn_->name(), ConnectionStr, 4, NumSessions, IdleTime);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -13,77 +13,27 @@ namespace uCentral {
|
||||
int Storage::Create_Tables() {
|
||||
|
||||
Create_Firmwares();
|
||||
Create_Callbacks();
|
||||
Create_LatestFirmwareList();
|
||||
Create_History();
|
||||
Create_DeviceTypes();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
description:
|
||||
type: string
|
||||
uploaded:
|
||||
type: string
|
||||
format: 'date-time'
|
||||
firmwareDate:
|
||||
type: string
|
||||
format: 'date-time'
|
||||
firmwareFileName:
|
||||
type: string
|
||||
firmwareVersion:
|
||||
type: string #the version the AP will report
|
||||
firmwareHash:
|
||||
type: string
|
||||
firmwareLatestDoc:
|
||||
type: string
|
||||
owner:
|
||||
type: string
|
||||
location:
|
||||
type: string
|
||||
format: uri
|
||||
Compatible:
|
||||
type: string
|
||||
downloadCount:
|
||||
type: integer
|
||||
format: int64
|
||||
uploader:
|
||||
type: string
|
||||
size:
|
||||
type: integer
|
||||
format: int64
|
||||
digest:
|
||||
type: string
|
||||
s3uri:
|
||||
type: string
|
||||
*/
|
||||
|
||||
int Storage::Create_Firmwares() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
Sess << "CREATE TABLE IF NOT EXISTS Firmwares ("
|
||||
"UUID VARCHAR(64) PRIMARY KEY, "
|
||||
"Description VARCHAR(128), "
|
||||
"Owner VARCHAR(128), "
|
||||
"Location TEXT, "
|
||||
"Compatible VARCHAR(128), "
|
||||
"Uploader VARCHAR(128), "
|
||||
"Uploaded BIGINT, "
|
||||
"DownloadCount BIGINT, "
|
||||
"Size BIGINT, "
|
||||
"Digest TEXT, "
|
||||
"FirmwareDate BIGINT, "
|
||||
"FirmwareFileName TEXT, "
|
||||
"FirmwareVersion VARCHAR(128), "
|
||||
"FirmwareHash VARCHAR(32), "
|
||||
"FirmwareLatestDoc TEXT, "
|
||||
"S3URI TEXT, "
|
||||
"Latest BIGINT"
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
if(dbType_==mysql) {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS " + DBNAME_FIRMWARES + " (" +
|
||||
DBFIELDS_FIRMWARES_CREATION +
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
} else {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS " + DBNAME_FIRMWARES + " (" +
|
||||
DBFIELDS_FIRMWARES_CREATION +
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
}
|
||||
return 0;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
@@ -91,84 +41,50 @@ namespace uCentral {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
properties:
|
||||
uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
uri:
|
||||
type: string
|
||||
format: uri
|
||||
location:
|
||||
type: string
|
||||
format: uri
|
||||
token:
|
||||
type: string
|
||||
creator:
|
||||
type: string
|
||||
tokenType:
|
||||
type: string
|
||||
topics:
|
||||
type: string
|
||||
created:
|
||||
type: string
|
||||
format: 'date-time'
|
||||
expires:
|
||||
type: string
|
||||
format: 'date-time'
|
||||
|
||||
*/
|
||||
|
||||
int Storage::Create_Callbacks() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
Sess << "CREATE TABLE IF NOT EXISTS Callbacks ("
|
||||
"UUID VARCHAR(64) PRIMARY KEY, "
|
||||
"URI TEXT, "
|
||||
"Location VARCHAR(128),"
|
||||
"Token TEXT,"
|
||||
"TokenType VARCHAR(64), "
|
||||
"Creator VARCHAR(128), "
|
||||
"Topics TEXT, "
|
||||
"Created BIGINT, "
|
||||
"Expires BIGINT)",
|
||||
Poco::Data::Keywords::now;
|
||||
return 0;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
LatestFirmware:
|
||||
type: object
|
||||
properties:
|
||||
Compatible:
|
||||
type: string
|
||||
uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
lastUpdated:
|
||||
type: string
|
||||
format: 'date-time'
|
||||
*/
|
||||
int Storage::Create_LatestFirmwareList() {
|
||||
int Storage::Create_History() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
Sess << "CREATE TABLE IF NOT EXISTS LatestFirmwares ("
|
||||
"Compatible VARCHAR(128) PRIMARY KEY, "
|
||||
"UUID TEXT, "
|
||||
"LastUpdated BIGINT"
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
if(dbType_==mysql) {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS " + DBNAME_HISTORY + " (" +
|
||||
DBFIELDS_HISTORY_CREATION +
|
||||
",INDEX Serial (SerialNumber ASC, upgraded ASC))"
|
||||
, Poco::Data::Keywords::now;
|
||||
} else {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS " + DBNAME_HISTORY + " (" +
|
||||
DBFIELDS_HISTORY_CREATION +
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
Sess << "CREATE INDEX IF NOT EXISTS Serial ON " + DBNAME_HISTORY + " (SerialNumber ASC, upgraded ASC)", Poco::Data::Keywords::now;
|
||||
}
|
||||
return 0;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Storage::Create_DeviceTypes() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
if(dbType_==mysql) {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS " + DBNAME_DEVICETYPES + " (" +
|
||||
DBFIELDS_DEVICETYPES_CREATION +
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
} else {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS " + DBNAME_DEVICETYPES + " (" +
|
||||
DBFIELDS_DEVICETYPES_CREATION +
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
}
|
||||
return 0;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user