Reword with microservice arch.

This commit is contained in:
stephb9959
2021-07-12 22:39:05 -07:00
parent 8099f13761
commit 8ac2c3b287
54 changed files with 1920 additions and 2407 deletions

View File

@@ -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 )

View 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
View 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
View 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
View 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()

View File

@@ -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'

View File

@@ -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()
});
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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_;

View File

@@ -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_);
}
}

View File

@@ -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
View 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
View 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
View 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
View 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

View File

@@ -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_);
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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_);
}

View File

@@ -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

View File

@@ -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() {

View File

@@ -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(); };

View File

@@ -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));

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -0,0 +1,5 @@
//
// Created by stephane bourque on 2021-07-12.
//
#include "storage_deviceTypes.h"

47
src/storage_deviceTypes.h Normal file
View 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

View File

@@ -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
View 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
View File

@@ -0,0 +1,5 @@
//
// Created by stephane bourque on 2021-07-12.
//
#include "storage_history.h"

35
src/storage_history.h Normal file
View 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

View File

@@ -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
View 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
View 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
View 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
}

View File

@@ -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;
}
}