整理代码
This commit is contained in:
commit
c7b4e178ec
364 changed files with 59691 additions and 0 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
**/.build
|
||||
**/build
|
||||
**/.vscode
|
||||
**/.vs
|
||||
|
||||
# 运行时生成:配置目录与日志
|
||||
config/
|
||||
logs/
|
||||
*.log
|
||||
|
||||
*.o
|
||||
*.a
|
||||
*.exe
|
||||
*.ilk
|
||||
*.pdb
|
||||
308
Application.cpp
Normal file
308
Application.cpp
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Application.h"
|
||||
#ifdef USING_NETWORK_SUBSYSTEM
|
||||
#include "NetworkSubsystem.h"
|
||||
#endif
|
||||
#ifdef USING_GRAPHICS_SUBSYSTEM
|
||||
#include "GraphicsSubsystem.h"
|
||||
#endif
|
||||
|
||||
#include <Poco/Dynamic/Var.h>
|
||||
#include <Poco/File.h>
|
||||
#include <Poco/FileStream.h>
|
||||
#include <Poco/JSON/Object.h>
|
||||
#include <Poco/JSON/Parser.h>
|
||||
#include <Poco/JSON/PrintHandler.h>
|
||||
#include <Poco/Net/DNS.h>
|
||||
#include <Poco/Net/IPAddress.h>
|
||||
#include <Poco/Net/NetworkInterface.h>
|
||||
#include <Poco/Path.h>
|
||||
#include <Poco/Pipe.h>
|
||||
#include <Poco/PipeStream.h>
|
||||
#include <Poco/Process.h>
|
||||
#include <Poco/StreamCopier.h>
|
||||
#include <Poco/Timespan.h>
|
||||
#include <Poco/Util/JSONConfiguration.h>
|
||||
#include <Poco/Util/Timer.h>
|
||||
#include <Poco/Checksum.h>
|
||||
#include <atca_basic.h>
|
||||
#include <atca_cfgs.h>
|
||||
#include <atca_device.h>
|
||||
#include <host/atca_host.h>
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include "hardware/BoardInfo.h"
|
||||
#include "hardware/GPIO.h"
|
||||
#include "hardware/HardwareSubsystem.h"
|
||||
#include "util/HexBinaryCodec.h"
|
||||
#include "util/SystemInfo.h"
|
||||
#include "util/Temperature.h"
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CONSTANTS
|
||||
*******************************************************************************
|
||||
*/
|
||||
static const std::string CONFIG_ROOT_PATH = "/customer/conf";
|
||||
static const std::string ROOTCFG_FILENAME = CONFIG_ROOT_PATH + "/config.json";
|
||||
static const std::string DEFAULT_ROOTCFG_FILENAME = CONFIG_ROOT_PATH + "/config_default.json";
|
||||
const std::string VERSION_FILE = "/customer/VERSION";
|
||||
const std::string IMAGE_VERSION_FILE = "/etc/IMAGE_VERSION";
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
const std::string Application::ROOT_CONFIG = "config";
|
||||
|
||||
void Application::initialize(Poco::Util::Application& self)
|
||||
{
|
||||
_exitRequst = false;
|
||||
initConfigAll();
|
||||
|
||||
Poco::Util::Application::initialize(self);
|
||||
}
|
||||
|
||||
void Application::uninitialize()
|
||||
{
|
||||
Poco::Util::Application::uninitialize();
|
||||
}
|
||||
|
||||
int Application::main(const std::vector<std::string>& args)
|
||||
{
|
||||
while (!_exitRequst)
|
||||
Poco::Thread::sleep(1000);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
std::string Application::getConfigFilePath(const std::string& label)
|
||||
{
|
||||
Poco::Path path(getConfig(Application::ROOT_CONFIG).getString("buss_params_path"));
|
||||
if (path.isRelative())
|
||||
path = path.makeAbsolute(Poco::Path::current());
|
||||
|
||||
return path.toString() + label + ".json";
|
||||
}
|
||||
|
||||
void Application::initConfigAll()
|
||||
{
|
||||
config().add(new Poco::Util::JSONConfiguration(ROOTCFG_FILENAME), ROOT_CONFIG, PRIO_SYSTEM, true);
|
||||
}
|
||||
|
||||
void Application::initConfig(const std::string& label)
|
||||
{
|
||||
int retry = 0;
|
||||
while (retry++ < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
config().add(new Poco::Util::JSONConfiguration(getConfigFilePath(label)), label, PRIO_APPLICATION, true);
|
||||
break;
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
logger().error("Load config file '%s' FAIL: %s, USE DEFAULT CONFIG FILE INSTEAD!", label, e.displayText());
|
||||
Poco::File dFile(getConfigFilePath(label + "_default"));
|
||||
if (dFile.exists())
|
||||
{
|
||||
dFile.copyTo(getConfigFilePath(label));
|
||||
}
|
||||
else
|
||||
{
|
||||
logger().error("Load config file '%s' FAIL: %s, DEFAULT CONFIG FILE IS NOT EXIST", label,
|
||||
e.displayText());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Application::version() const
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::FileInputStream istr(VERSION_FILE);
|
||||
std::string version;
|
||||
istr >> version;
|
||||
return version;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return "0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Util::AbstractConfiguration& Application::getConfig() const
|
||||
{
|
||||
return config();
|
||||
}
|
||||
|
||||
Poco::Util::AbstractConfiguration& Application::getConfig(const std::string& label) const
|
||||
{
|
||||
return findConfig<Poco::Util::JSONConfiguration>(label);
|
||||
}
|
||||
|
||||
void Application::saveConfig(const std::string& label)
|
||||
{
|
||||
logger().information("Saving config...");
|
||||
std::string tmpFilePath = "/tmp/" + label + ".json.tmp";
|
||||
std::string filePath = getConfigFilePath(label);
|
||||
|
||||
Poco::FileOutputStream fost(tmpFilePath);
|
||||
dumpConfig(label, fost);
|
||||
fost.flush();
|
||||
fost.close();
|
||||
|
||||
try
|
||||
{
|
||||
Poco::File(tmpFilePath).moveTo(filePath);
|
||||
logger().information("Config saved successfully.");
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
logger().error("Save config file ERROR: %s", e.displayText());
|
||||
}
|
||||
}
|
||||
|
||||
void Application::loadConfig(const std::string& label, std::istream& istr)
|
||||
{
|
||||
auto& config = findConfig<Poco::Util::JSONConfiguration>(label);
|
||||
config.load(istr);
|
||||
saveConfig(label);
|
||||
ConfigChanged.notifyAsync(this, label);
|
||||
}
|
||||
|
||||
void Application::loadConfig(const std::string& label, const std::string& str)
|
||||
{
|
||||
std::istringstream istr(str);
|
||||
loadConfig(label, istr);
|
||||
}
|
||||
|
||||
void Application::dumpConfig(const std::string& label, std::ostream& os)
|
||||
{
|
||||
auto& config = findConfig<Poco::Util::JSONConfiguration>(label);
|
||||
config.save(os);
|
||||
}
|
||||
|
||||
void Application::configNotifyAsync(const std::string& label)
|
||||
{
|
||||
ConfigChanged.notifyAsync(this, label);
|
||||
}
|
||||
|
||||
void Application::restoreFactorySettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
printf("Restore system factory settings...\r\n");
|
||||
system("/customer/reset-key -Pweb");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
reboot(2000);
|
||||
}
|
||||
|
||||
void Application::reboot(uint32_t delay)
|
||||
{
|
||||
_delayRebootThread.startFunc([=]() -> void {
|
||||
logger().warning("Reboot after %u ms ...", delay);
|
||||
Poco::Thread::sleep(delay);
|
||||
|
||||
exit();
|
||||
::sync();
|
||||
|
||||
if (system("reboot") != 0)
|
||||
logger().error("System reboot command failed!");
|
||||
|
||||
::reboot(RB_AUTOBOOT);
|
||||
});
|
||||
}
|
||||
|
||||
void Application::setSystemTime(uint32_t timestamp, int timezone)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = timestamp;
|
||||
tv.tv_usec = 0;
|
||||
settimeofday(&tv, NULL);
|
||||
|
||||
try
|
||||
{
|
||||
std::string cmd = "";
|
||||
if (timezone >= 0)
|
||||
{
|
||||
cmd = Poco::format("ln -snf /customer/zoneinfo/Etc/GMT-%d /etc/localtime", timezone);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = Poco::format("ln -snf /customer/zoneinfo/Etc/GMT+%d /etc/localtime", -1 * timezone);
|
||||
}
|
||||
system(cmd.c_str());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
}
|
||||
system("hwclock -w -l");
|
||||
}
|
||||
|
||||
void Application::exit()
|
||||
{
|
||||
ApplicationExitNotify.notify(this);
|
||||
_exitRequst = true;
|
||||
}
|
||||
|
||||
void Application::upgrade(const std::string& file)
|
||||
{
|
||||
#if defined(FIRMWARE_UPGRADE_FROM_BACKUP_PARTITION)
|
||||
Poco::File("/customer/DIRTY").createFile();
|
||||
logger().warning("Reboot to upgrade firmware ....");
|
||||
#else
|
||||
|
||||
std::string specCharacters[] = {
|
||||
"\\", " ", "\"", "'", "(", ")", "*", "!", "$", "%", "&", ">", "<", "|", "`",
|
||||
};
|
||||
|
||||
for (auto& c : specCharacters)
|
||||
file = Poco::replace(file, c, "\\" + c);
|
||||
|
||||
Poco::Pipe inPipe, outPipe;
|
||||
Poco::Process::Args args;
|
||||
Poco::ProcessHandle handle = Poco::Process::launch("sh", args, &inPipe, &outPipe, 0);
|
||||
|
||||
Poco::PipeOutputStream outputStream(inPipe);
|
||||
std::string tmpdir = "/tmp/upgrade";
|
||||
outputStream << Poco::format("mkdir -p %s", tmpdir) << std::endl;
|
||||
outputStream << Poco::format("tar xf %s -C %s", file, tmpdir) << std::endl;
|
||||
outputStream << Poco::format("%s/upgrade.sh", tmpdir) << std::endl;
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
handle.wait();
|
||||
|
||||
Poco::PipeInputStream inputStream(outPipe);
|
||||
std::string str;
|
||||
Poco::StreamCopier::copyToString(inputStream, str);
|
||||
logger().information("Firmware upgrade complete, reboot....");
|
||||
#endif
|
||||
reboot(2000);
|
||||
}
|
||||
115
Application.h
Normal file
115
Application.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#ifndef C7F1A9D3_4E28_4B60_9C15_8A3E6D2F0B94
|
||||
#define C7F1A9D3_4E28_4B60_9C15_8A3E6D2F0B94
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/BasicEvent.h>
|
||||
#include <Poco/Dynamic/Var.h>
|
||||
#include <Poco/JSON/Array.h>
|
||||
#include <Poco/JSON/Object.h>
|
||||
#include <Poco/JSON/Parser.h>
|
||||
#include <Poco/Net/IPAddress.h>
|
||||
#include <Poco/Net/NetworkInterface.h>
|
||||
#include <Poco/Util/Application.h>
|
||||
#include <atomic>
|
||||
#include "util/JsonUtil.h"
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CONSTANTS
|
||||
*******************************************************************************
|
||||
*/
|
||||
#define APPLICATION_VERSION application().version()
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* MACROS
|
||||
*******************************************************************************
|
||||
*/
|
||||
#define application() (*(Application::getInstance()))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* TYPEDEFS
|
||||
*******************************************************************************
|
||||
*/
|
||||
using ConfigurationPtr = Poco::Util::AbstractConfiguration::Ptr;
|
||||
using Configuration = Poco::Util::AbstractConfiguration;
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Application: public Poco::Util::Application
|
||||
{
|
||||
public:
|
||||
struct SystemStatus
|
||||
{
|
||||
};
|
||||
|
||||
public:
|
||||
static const std::string ROOT_CONFIG;
|
||||
|
||||
Poco::BasicEvent<std::string> ConfigChanged;
|
||||
Poco::BasicEvent<void> ApplicationExitNotify;
|
||||
|
||||
protected:
|
||||
void initialize(Poco::Util::Application& self) override;
|
||||
void uninitialize() override;
|
||||
int main(const std::vector<std::string>& args) override;
|
||||
|
||||
std::string getConfigFilePath(const std::string& label);
|
||||
|
||||
template <class T> T& findConfig(const std::string& label) const
|
||||
{
|
||||
return *static_cast<T*>(config().find(label).get());
|
||||
}
|
||||
|
||||
void initConfigAll();
|
||||
void initConfig(const std::string& label);
|
||||
|
||||
public:
|
||||
std::string version() const;
|
||||
Poco::Util::AbstractConfiguration& getConfig() const;
|
||||
Poco::Util::AbstractConfiguration& getConfig(const std::string& label) const;
|
||||
|
||||
void saveConfig(const std::string& label);
|
||||
|
||||
void loadConfig(const std::string& label, std::istream& istr);
|
||||
|
||||
void loadConfig(const std::string& label, const std::string& istr);
|
||||
|
||||
void dumpConfig(const std::string& label, std::ostream& ostr);
|
||||
|
||||
void configNotifyAsync(const std::string& label);
|
||||
|
||||
void restoreFactorySettings();
|
||||
|
||||
void reboot(uint32_t delay = 2000);
|
||||
|
||||
void setSystemTime(uint32_t timestamp, int timezone = 8);
|
||||
|
||||
void exit();
|
||||
|
||||
void upgrade(const std::string& file);
|
||||
|
||||
static Application* getInstance()
|
||||
{
|
||||
Poco::Util::Application& app = instance();
|
||||
return static_cast<Application*>(&app);
|
||||
}
|
||||
|
||||
private:
|
||||
Poco::Thread _delayRebootThread;
|
||||
std::atomic<bool> _exitRequst;
|
||||
};
|
||||
|
||||
#endif
|
||||
162
CMakeLists.txt
Normal file
162
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
set(PROJNAME encoder)
|
||||
include(config.cmake)
|
||||
include(FetchContent)
|
||||
|
||||
project(${PROJNAME})
|
||||
|
||||
set(ARCH arm)
|
||||
|
||||
if (USING_HISIMPP5)
|
||||
add_compile_definitions(
|
||||
-DUSING_HISIMPP5
|
||||
)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(
|
||||
-DFIRMWARE_UPGRADE_FROM_BACKUP_PARTITION
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND git log -1 --format=%h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
add_compile_definitions(-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\")
|
||||
|
||||
# 未定义或为空
|
||||
if (NOT DEFINED CMAKE_BUILD_TYPE OR NOT CMAKE_BUILD_TYPE)
|
||||
set (CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
message("Project \"${GIT_COMMIT_HASH}\" build type: " ${CMAKE_BUILD_TYPE})
|
||||
|
||||
if (CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
add_compile_definitions(-DDEBUG)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
set(Poco_DIR $ENV{POCO_PATH}/lib/cmake/Poco)
|
||||
link_libraries(
|
||||
pthread
|
||||
dl
|
||||
m
|
||||
atomic
|
||||
)
|
||||
if (CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
# 定义Debug编译参数
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -Og -Wall -g3 -Wno-psabi -std=c++1z -mfpu=neon -mfloat-abi=softfp") # GDB调试
|
||||
# SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -Og -Wall -g3 -Wno-psabi -std=c++1z -mfpu=neon -mfloat-abi=softfp -fsanitize=address -fno-eliminate-unused-debug-types -fno-omit-frame-pointer") # 内存检测
|
||||
# SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -Wno-psabi")
|
||||
# SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -Wno-psabi -rdynamic -funwind-tables -ffunction-sections") # 可以在应用里捕获SIGSEGV信号,然后用backtrace()函数把堆栈信息打印出来
|
||||
else()
|
||||
# 定义Release编译参数
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -Wno-psabi -mfpu=neon -mfloat-abi=softfp")
|
||||
endif()
|
||||
add_compile_definitions(-DOS_LINUX)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
set(Poco_DIR $ENV{POCO_PATH}/cmake)
|
||||
# 强制Visual Studio使用UTF-8编码
|
||||
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
|
||||
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||
# 忽略部分警告
|
||||
add_compile_definitions(/wd"4828")
|
||||
# 使用Unicode字符集
|
||||
add_compile_definitions(-DUNICODE -D_UNICODE)
|
||||
if (USING_LVGL_PLATFORM OR USING_SOUI_PLATFORM)
|
||||
# 设置为窗口程序
|
||||
set(GUI_EXECUTABLE WIN32)
|
||||
add_compile_definitions(-DWINDOWS_GUI_APPLICATION)
|
||||
endif()
|
||||
link_directories($ENV{POCO_PATH}/lib)
|
||||
endif()
|
||||
|
||||
find_package(Poco REQUIRED COMPONENTS Foundation Net XML Encodings Util Zip Crypto)
|
||||
include_directories(
|
||||
.
|
||||
${Poco_LIBRARIES}
|
||||
$ENV{JSONC_PATH}/include
|
||||
$ENV{CRYPTOAUTHLIB_PATH}/include/cryptoauthlib
|
||||
$ENV{OPENSSL_PATH}/include
|
||||
$ENV{PAHO_MQTTC_PATH}/include
|
||||
)
|
||||
link_libraries(
|
||||
${Poco_LIBRARIES}
|
||||
$ENV{CRYPTOAUTHLIB_PATH}/lib/libcryptoauth.a
|
||||
$ENV{OPENSSL_PATH}/lib/libssl.a
|
||||
$ENV{OPENSSL_PATH}/lib/libcrypto.a
|
||||
#$ENV{PAHO_MQTTC_PATH}/lib/libpaho-mqtt3a.a
|
||||
#$ENV{PAHO_MQTTC_PATH}/lib/libpaho-mqtt3as.a
|
||||
$ENV{PAHO_MQTTC_PATH}/lib/libpaho-mqtt3c.a
|
||||
#$ENV{PAHO_MQTTC_PATH}/lib/libpaho-mqtt3cs.a
|
||||
)
|
||||
|
||||
if (USING_HISIMPP5)
|
||||
include_directories(
|
||||
$ENV{MPP_PATH}/include
|
||||
)
|
||||
|
||||
link_libraries(
|
||||
$ENV{MPP_PATH}/lib/libmpi.a
|
||||
$ENV{MPP_PATH}/lib/libdnvqe.a
|
||||
$ENV{MPP_PATH}/lib/libupvqe.a
|
||||
$ENV{MPP_PATH}/lib/libvqe_res.a
|
||||
$ENV{MPP_PATH}/lib/libVoiceEngine.a
|
||||
$ENV{MPP_PATH}/lib/libsecurec.so
|
||||
$ENV{MPP_PATH}/lib/libhdmi.a
|
||||
$ENV{MPP_PATH}/lib/libtde.a
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
aux_source_directory(. MAIN_SOURCES)
|
||||
add_executable(${PROJNAME} ${GUI_EXECUTABLE} ${MAIN_SOURCES})
|
||||
|
||||
# target_compile_options(${PROJNAME} PRIVATE
|
||||
# -fsanitize=address,undefined
|
||||
# -fsanitize=float-divide-by-zero
|
||||
# -fsanitize=null
|
||||
# -fsanitize=bounds-strict
|
||||
# )
|
||||
|
||||
# target_link_options(${PROJNAME} PRIVATE
|
||||
# -fsanitize=address,undefined
|
||||
# )
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
SET_PROPERTY (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJNAME} )
|
||||
endif()
|
||||
|
||||
if (USING_VIDEO_SUBSYSTEM)
|
||||
add_compile_definitions(-DUSING_VIDEO_SUBSYSTEM)
|
||||
endif()
|
||||
|
||||
# 网络
|
||||
if (USING_NETWORK_SUBSYSTEM)
|
||||
add_compile_definitions(-DUSING_NETWORK_SUBSYSTEM)
|
||||
endif()
|
||||
|
||||
# 板级设备
|
||||
if (USING_HARDWARE_SUBSYSTEM)
|
||||
add_compile_definitions(-DUSING_HARDWARE_SUBSYSTEM)
|
||||
endif()
|
||||
|
||||
if (USING_VIDEO_SUBSYSTEM)
|
||||
include(video/video.cmake)
|
||||
endif()
|
||||
|
||||
# 网络
|
||||
if (USING_NETWORK_SUBSYSTEM)
|
||||
include(network/network.cmake)
|
||||
endif()
|
||||
|
||||
# 板级设备
|
||||
if (USING_HARDWARE_SUBSYSTEM)
|
||||
include(hardware/hardware.cmake)
|
||||
endif()
|
||||
|
||||
# Util
|
||||
include(util/util.cmake)
|
||||
|
||||
6
Logger.cpp
Normal file
6
Logger.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Logger.h"
|
||||
16
Logger.h
Normal file
16
Logger.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef E4B8FD4A_9AEF_4A23_9C62_8D091F7306FE
|
||||
#define E4B8FD4A_9AEF_4A23_9C62_8D091F7306FE
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Application.h"
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* MACROS
|
||||
*******************************************************************************
|
||||
*/
|
||||
#define logger() (application().logger())
|
||||
#endif
|
||||
32
config.cmake
Normal file
32
config.cmake
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
message(BOARD..${BOARD})
|
||||
option(USING_HARDWARE_SUBSYSTEM "Using Hardware subsystem" ON)
|
||||
option(USING_HISIMPP5 "Using Hisilicon MPP5" ON)
|
||||
|
||||
# Video
|
||||
option(USING_VIDEO_SUBSYSTEM "Using Video subsystem" ON)
|
||||
option(USING_FFMPEG "Using ffmpeg library" ON)
|
||||
option(USING_MEDIA_FRAMEWORK "Using Media-Framework" ON)
|
||||
option(USING_ZLMEDIAKIT "Using ZLMediaKit" ON)
|
||||
option(USING_ONVIF "Using ONVIF" ON)
|
||||
option(USING_ITE_FRONTEND "Using ITE IT66021" ON)
|
||||
option(USING_SEMTECH_DEVICE "Using SEMTECH device" OFF)
|
||||
option(USING_MEDIASERVER "Using media-server" ON)
|
||||
option(USING_LIBOPUS "Using libopus" ON)
|
||||
option(USING_SHINE "Using shine MP3" ON)
|
||||
|
||||
# Serialization
|
||||
option(USING_PROTOBUF "Using Google's data interchange format" OFF)
|
||||
|
||||
# Network
|
||||
option(USING_NETWORK_SUBSYSTEM "Using Network subsystem" ON)
|
||||
option(USING_TCPIP "Using TCP/IP protocol" ON)
|
||||
|
||||
# Licence
|
||||
option(USING_LICENCE_FROM_LOCAL_ENABLE "Using Licence form local enable" ON)
|
||||
|
||||
set(CMAKE_C_COMPILER $ENV{GCC_PATH}/$ENV{GCC_PREFIX}gcc)
|
||||
set(CMAKE_CXX_COMPILER $ENV{GCC_PATH}/$ENV{GCC_PREFIX}g++)
|
||||
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
# set(CMAKE_BUILD_TYPE Debug)
|
||||
|
||||
28
hardware/BoardInfo.cpp
Normal file
28
hardware/BoardInfo.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "BoardInfo.h"
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Board::Ptr BoardInfo::_pBoard = nullptr;
|
||||
|
||||
Board::~Board()
|
||||
{
|
||||
}
|
||||
|
||||
std::string BoardInfo::serialNumber()
|
||||
{
|
||||
if (_pBoard.isNull())
|
||||
return "NOT IMPLEMENTED";
|
||||
|
||||
return _pBoard->serialNumber();
|
||||
}
|
||||
}
|
||||
45
hardware/BoardInfo.h
Normal file
45
hardware/BoardInfo.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef FD5BB51A_6CF1_4A59_B157_25E320495F52
|
||||
#define FD5BB51A_6CF1_4A59_B157_25E320495F52
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/SharedPtr.h>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Board
|
||||
{
|
||||
public:
|
||||
using Ptr = Poco::SharedPtr<Board>;
|
||||
|
||||
public:
|
||||
~Board();
|
||||
|
||||
public:
|
||||
virtual std::string serialNumber() = 0;
|
||||
};
|
||||
|
||||
class BoardInfo
|
||||
{
|
||||
public:
|
||||
static void registerBoard(Board::Ptr pBoard);
|
||||
|
||||
static std::string serialNumber();
|
||||
|
||||
private:
|
||||
static Board::Ptr _pBoard;
|
||||
};
|
||||
|
||||
inline void BoardInfo::registerBoard(Board::Ptr pBoard)
|
||||
{
|
||||
_pBoard = pBoard;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
29
hardware/CMakeLists.txt
Normal file
29
hardware/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
set(TARGET hardware)
|
||||
|
||||
aux_source_directory(. HARDWARE_SRCS)
|
||||
aux_source_directory(user USER_SOURCES)
|
||||
|
||||
|
||||
if (USING_HISIMPP5)
|
||||
aux_source_directory(hisilicon HISI_SOURCES)
|
||||
list(APPEND HARDWARE_SRCS ${HISI_SOURCES})
|
||||
include_directories($ENV{MPP_PATH}/include)
|
||||
endif()
|
||||
|
||||
if (USING_ITE_DEVICE)
|
||||
message("Using ITE device ...")
|
||||
aux_source_directory(ite ITE_SOURCES)
|
||||
list(APPEND HARDWARE_SRCS ${ITE_SOURCES})
|
||||
endif()
|
||||
|
||||
if (USING_SEMTECH_DEVICE)
|
||||
message("Using SEMTECH device ...")
|
||||
aux_source_directory(semtech SEMTECH_SOURCES)
|
||||
list(APPEND HARDWARE_SRCS ${SEMTECH_SOURCES})
|
||||
endif()
|
||||
|
||||
add_library(${TARGET} STATIC
|
||||
${HARDWARE_SRCS}
|
||||
${USER_SOURCES}
|
||||
)
|
||||
|
||||
81
hardware/GPIO.cpp
Normal file
81
hardware/GPIO.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "GPIO.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <Poco/Exception.h>
|
||||
#include <Poco/Format.h>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
GPIO::GPIO(int pinno): _pinno(pinno)
|
||||
{
|
||||
std::string s = std::to_string(_pinno);
|
||||
writeFile("/sys/class/gpio/export", s.c_str(), s.length());
|
||||
_fd = ::open(Poco::format("/sys/class/gpio/gpio%d/value", _pinno).c_str(), O_RDWR);
|
||||
if (_fd < 0)
|
||||
throw Poco::InvalidAccessException("Open FAIL");
|
||||
}
|
||||
|
||||
GPIO::~GPIO()
|
||||
{
|
||||
::close(_fd);
|
||||
std::string s = std::to_string(_pinno);
|
||||
writeFile("/sys/class/gpio/unexport", s.c_str(), s.length());
|
||||
}
|
||||
|
||||
void GPIO::direction(Direction dir)
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case Direction::OUT:
|
||||
default:
|
||||
writeDirection("out");
|
||||
break;
|
||||
|
||||
case Direction::IN:
|
||||
writeDirection("in");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GPIO::write(unsigned level)
|
||||
{
|
||||
if (level)
|
||||
::write(_fd, "1", 1);
|
||||
else
|
||||
::write(_fd, "0", 1);
|
||||
}
|
||||
|
||||
unsigned GPIO::read()
|
||||
{
|
||||
char value;
|
||||
::read(_fd, &value, 1);
|
||||
return value != '0';
|
||||
}
|
||||
|
||||
void GPIO::writeFile(const std::string& path, const void* pData, int len)
|
||||
{
|
||||
int fd = ::open(path.c_str(), O_WRONLY);
|
||||
if (fd < 0)
|
||||
throw Poco::InvalidAccessException("Open FAIL");
|
||||
|
||||
::write(fd, pData, len);
|
||||
::close(fd);
|
||||
}
|
||||
|
||||
void GPIO::writeDirection(const std::string& value)
|
||||
{
|
||||
writeFile(Poco::format("/sys/class/gpio/gpio%d/direction", _pinno), value.c_str(), value.length());
|
||||
}
|
||||
}
|
||||
44
hardware/GPIO.h
Normal file
44
hardware/GPIO.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef C88B7A31_D4F3_4E43_B4CE_45003C99E915
|
||||
#define C88B7A31_D4F3_4E43_B4CE_45003C99E915
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <string>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class GPIO
|
||||
{
|
||||
public:
|
||||
enum class Direction
|
||||
{
|
||||
IN,
|
||||
OUT,
|
||||
};
|
||||
|
||||
public:
|
||||
GPIO(int pinno);
|
||||
~GPIO();
|
||||
|
||||
public:
|
||||
void direction(Direction dir);
|
||||
void write(unsigned level);
|
||||
unsigned read();
|
||||
|
||||
private:
|
||||
void writeFile(const std::string& path, const void* pData, int len);
|
||||
void writeDirection(const std::string& value);
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
int _pinno;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
35
hardware/HardwareSubsystem.cpp
Normal file
35
hardware/HardwareSubsystem.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "HardwareSubsystem.h"
|
||||
#include "BoardInfo.h"
|
||||
#include "hisilicon/Board.h"
|
||||
#include "Sensor.h"
|
||||
#include "hisilicon/TemperatureSensor.h"
|
||||
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
const char* HardwareSubsystem::name() const
|
||||
{
|
||||
return "Hardware";
|
||||
}
|
||||
|
||||
void HardwareSubsystem::initialize(Poco::Util::Application& app)
|
||||
{
|
||||
BoardInfo::registerBoard(new Hisilicon::Board());
|
||||
SensorManager::registerSensor(Sensor::Type::TEMPERATURE, new Hisilicon::TemperatureSensor());
|
||||
}
|
||||
|
||||
void HardwareSubsystem::uninitialize()
|
||||
{
|
||||
stopAll();
|
||||
}
|
||||
}
|
||||
30
hardware/HardwareSubsystem.h
Normal file
30
hardware/HardwareSubsystem.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef CEE64BF6_3FB0_4B34_9E98_BCFE7C712DA1
|
||||
#define CEE64BF6_3FB0_4B34_9E98_BCFE7C712DA1
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/Subsystem.h"
|
||||
#include "Application.h"
|
||||
#include "util/Subsystem.h"
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class HardwareSubsystem: public Util::Subsystem
|
||||
{
|
||||
public:
|
||||
virtual const char* name() const override;
|
||||
|
||||
protected:
|
||||
virtual void initialize(Poco::Util::Application& app) override;
|
||||
virtual void uninitialize();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
73
hardware/SPI.cpp
Normal file
73
hardware/SPI.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "SPI.h"
|
||||
#include <Poco/Format.h>
|
||||
#include <Poco/Exception.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
const uint8_t SPI::MODE_0 = SPI_MODE_0;
|
||||
const uint8_t SPI::MODE_1 = SPI_MODE_1;
|
||||
const uint8_t SPI::MODE_2 = SPI_MODE_2;
|
||||
const uint8_t SPI::MODE_3 = SPI_MODE_3;
|
||||
|
||||
SPI::SPI(int bus, int cs)
|
||||
{
|
||||
_fd = open(Poco::format("/dev/spidev%d.%d", bus, cs).c_str(), O_RDWR);
|
||||
if (_fd < 0)
|
||||
throw Poco::IOException("SPI: Open device FAIL");
|
||||
}
|
||||
|
||||
SPI::~SPI()
|
||||
{
|
||||
close(_fd);
|
||||
}
|
||||
|
||||
int SPI::setSpeed(uint32_t speed)
|
||||
{
|
||||
return ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
|
||||
}
|
||||
|
||||
int SPI::setMode(uint8_t mode)
|
||||
{
|
||||
return ioctl(_fd, SPI_IOC_WR_MODE, &mode);
|
||||
}
|
||||
|
||||
int SPI::setBitsPerWord(uint8_t bits)
|
||||
{
|
||||
return ioctl(_fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
|
||||
}
|
||||
|
||||
int SPI::setLSBFirst(bool enable)
|
||||
{
|
||||
uint8_t lsb = enable ? 1 : 0;
|
||||
return ioctl(_fd, SPI_IOC_WR_LSB_FIRST, &lsb);
|
||||
}
|
||||
|
||||
int SPI::writeThenRead(const uint8_t* tx, int txlen, uint8_t* rx, int rxlen)
|
||||
{
|
||||
struct spi_ioc_transfer trans[2] = {{0}, {0}};
|
||||
|
||||
trans[0].tx_buf = (unsigned long)tx;
|
||||
trans[0].rx_buf = 0;
|
||||
trans[0].len = txlen;
|
||||
|
||||
trans[1].tx_buf = 0;
|
||||
trans[1].rx_buf = (unsigned long)rx;
|
||||
trans[1].len = rxlen;
|
||||
return ioctl(_fd, SPI_IOC_MESSAGE(2), trans);
|
||||
}
|
||||
}
|
||||
41
hardware/SPI.h
Normal file
41
hardware/SPI.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef C9ED230E_05FF_4E41_87B9_664DF1FD835C
|
||||
#define C9ED230E_05FF_4E41_87B9_664DF1FD835C
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class SPI
|
||||
{
|
||||
public:
|
||||
static const uint8_t MODE_0;
|
||||
static const uint8_t MODE_1;
|
||||
static const uint8_t MODE_2;
|
||||
static const uint8_t MODE_3;
|
||||
|
||||
public:
|
||||
SPI(int bus, int cs);
|
||||
~SPI();
|
||||
|
||||
public:
|
||||
int setSpeed(uint32_t speed);
|
||||
int setMode(uint8_t mode);
|
||||
int setBitsPerWord(uint8_t bits);
|
||||
int setLSBFirst(bool enable);
|
||||
|
||||
int writeThenRead(const uint8_t* tx, int txlen, uint8_t* rx, int rxlen);
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
47
hardware/Sensor.cpp
Normal file
47
hardware/Sensor.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Sensor.h"
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Sensor::Sensor(Type type): _type(type)
|
||||
{
|
||||
}
|
||||
|
||||
Sensor::~Sensor()
|
||||
{
|
||||
}
|
||||
|
||||
void Sensor::read(float& value)
|
||||
{
|
||||
}
|
||||
|
||||
void Sensor::read(float values[])
|
||||
{
|
||||
}
|
||||
|
||||
Sensor::Type Sensor::type()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
SensorManager::SensorCollection SensorManager::_sensorCollection;
|
||||
|
||||
Sensor& SensorManager::getDefaultSensor(Sensor::Type type)
|
||||
{
|
||||
return *_sensorCollection[type][0];
|
||||
}
|
||||
|
||||
void SensorManager::registerSensor(Sensor::Type type, Sensor::Ptr pSensor)
|
||||
{
|
||||
_sensorCollection[type].push_back(pSensor);
|
||||
}
|
||||
}
|
||||
57
hardware/Sensor.h
Normal file
57
hardware/Sensor.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef F49794A5_C3E3_4955_B9B2_6BAA267D3436
|
||||
#define F49794A5_C3E3_4955_B9B2_6BAA267D3436
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/SharedPtr.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Sensor
|
||||
{
|
||||
public:
|
||||
using Ptr = Poco::SharedPtr<Sensor>;
|
||||
|
||||
enum Type
|
||||
{
|
||||
TEMPERATURE,
|
||||
};
|
||||
|
||||
public:
|
||||
Sensor(Type type);
|
||||
virtual ~Sensor();
|
||||
|
||||
public:
|
||||
virtual void read(float& value);
|
||||
virtual void read(float values[]);
|
||||
|
||||
Type type();
|
||||
|
||||
private:
|
||||
Type _type;
|
||||
};
|
||||
|
||||
class SensorManager
|
||||
{
|
||||
public:
|
||||
static Sensor& getDefaultSensor(Sensor::Type type);
|
||||
static void registerSensor(Sensor::Type type, Sensor::Ptr pSensor);
|
||||
|
||||
private:
|
||||
using SensorList = std::vector<Sensor::Ptr>;
|
||||
using SensorCollection = std::map<Sensor::Type, SensorList>;
|
||||
|
||||
private:
|
||||
static SensorCollection _sensorCollection;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
313
hardware/SerialPort.cpp
Normal file
313
hardware/SerialPort.cpp
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "SerialPort.h"
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <Poco/Exception.h>
|
||||
#include <Poco/Format.h>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
SerialPort::SerialPort(): _fd(-1)
|
||||
{
|
||||
}
|
||||
|
||||
SerialPort::~SerialPort()
|
||||
{
|
||||
if (isOpen())
|
||||
close();
|
||||
}
|
||||
|
||||
void SerialPort::open()
|
||||
{
|
||||
if (isOpen())
|
||||
return;
|
||||
|
||||
if (_path.empty())
|
||||
throw Poco::InvalidArgumentException("Empty path");
|
||||
|
||||
struct termios options = {0};
|
||||
options.c_cflag |= CLOCAL | getBaudRateFlag(_baudRate);
|
||||
switch (_dataBits)
|
||||
{
|
||||
case 5:
|
||||
options.c_cflag |= CS5;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
options.c_cflag |= CS6;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Poco::InvalidArgumentException(Poco::format("Invalid data bits: %d", _dataBits));
|
||||
}
|
||||
|
||||
switch (_stopBits)
|
||||
{
|
||||
case 1:
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
options.c_cflag |= CSTOPB;
|
||||
break;
|
||||
|
||||
default:
|
||||
case 3:
|
||||
case 4:
|
||||
throw Poco::InvalidArgumentException(Poco::format("Invalid stop bits: %d", _stopBits));
|
||||
}
|
||||
|
||||
switch (_parity)
|
||||
{
|
||||
default:
|
||||
case Parity::NONE:
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_iflag &= ~INPCK;
|
||||
break;
|
||||
|
||||
case Parity::ODD:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag |= PARODD;
|
||||
options.c_iflag |= INPCK;
|
||||
options.c_iflag |= ISTRIP;
|
||||
break;
|
||||
|
||||
case Parity::EVEN:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
options.c_iflag |= INPCK;
|
||||
options.c_iflag |= ISTRIP;
|
||||
break;
|
||||
}
|
||||
|
||||
options.c_cflag |= CREAD;
|
||||
|
||||
switch (_flowControl)
|
||||
{
|
||||
default:
|
||||
case FlowControl::NONE:
|
||||
options.c_cflag &= ~CRTSCTS;
|
||||
break;
|
||||
|
||||
case FlowControl::RTSCTS:
|
||||
options.c_cflag |= CRTSCTS;
|
||||
break;
|
||||
}
|
||||
|
||||
_fd = ::open(_path.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if (_fd < 0)
|
||||
throw Poco::InvalidAccessException(Poco::format("Open '%s' FAIL: %d", _path, _fd));
|
||||
|
||||
tcflush(_fd, TCIOFLUSH);
|
||||
cfmakeraw(&options);
|
||||
tcsetattr(_fd, TCSANOW, &options);
|
||||
}
|
||||
|
||||
void SerialPort::close()
|
||||
{
|
||||
if (!isOpen())
|
||||
return;
|
||||
|
||||
::close(_fd);
|
||||
_fd = -1;
|
||||
}
|
||||
|
||||
bool SerialPort::isOpen()
|
||||
{
|
||||
return _fd != -1;
|
||||
}
|
||||
|
||||
int SerialPort::write(const void* pData, uint32_t size)
|
||||
{
|
||||
if (!isOpen())
|
||||
return 0;
|
||||
|
||||
return ::write(_fd, pData, size);
|
||||
}
|
||||
|
||||
int SerialPort::read(void* pBuffer, uint32_t length, uint32_t timeout)
|
||||
{
|
||||
if (!isOpen())
|
||||
return 0;
|
||||
|
||||
struct timeval tm;
|
||||
tm.tv_sec = timeout / 1000;
|
||||
tm.tv_usec = (timeout % 1000) * 1000;
|
||||
|
||||
fd_set reads;
|
||||
FD_ZERO(&reads);
|
||||
FD_SET(_fd, &reads);
|
||||
|
||||
int rc = ::select(_fd + 1, &reads, NULL, NULL, &tm);
|
||||
if (rc < 0)
|
||||
return 0;
|
||||
|
||||
if (FD_ISSET(_fd, &reads))
|
||||
return ::read(_fd, pBuffer, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SerialPort& SerialPort::setPath(const std::string& path)
|
||||
{
|
||||
_path = path;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SerialPort& SerialPort::setBaudRate(uint32_t baudRate)
|
||||
{
|
||||
_baudRate = baudRate;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SerialPort& SerialPort::setParity(Parity parity)
|
||||
{
|
||||
_parity = parity;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SerialPort& SerialPort::setDataBits(uint32_t bits)
|
||||
{
|
||||
_dataBits = bits;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SerialPort& SerialPort::setStopBits(uint32_t bits)
|
||||
{
|
||||
_stopBits = bits;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SerialPort& SerialPort::setFlowControl(FlowControl flowControl)
|
||||
{
|
||||
_flowControl = flowControl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32_t SerialPort::getBaudRateFlag(uint32_t br)
|
||||
{
|
||||
uint32_t flag;
|
||||
|
||||
switch (br)
|
||||
{
|
||||
case 0:
|
||||
flag = B0;
|
||||
break;
|
||||
case 50:
|
||||
flag = B50;
|
||||
break;
|
||||
case 75:
|
||||
flag = B75;
|
||||
break;
|
||||
case 110:
|
||||
flag = B110;
|
||||
break;
|
||||
case 134:
|
||||
flag = B134;
|
||||
break;
|
||||
case 150:
|
||||
flag = B150;
|
||||
break;
|
||||
case 200:
|
||||
flag = B200;
|
||||
break;
|
||||
case 300:
|
||||
flag = B300;
|
||||
break;
|
||||
case 600:
|
||||
flag = B600;
|
||||
break;
|
||||
case 1200:
|
||||
flag = B1200;
|
||||
break;
|
||||
case 1800:
|
||||
flag = B1800;
|
||||
break;
|
||||
case 2400:
|
||||
flag = B2400;
|
||||
break;
|
||||
case 4800:
|
||||
flag = B4800;
|
||||
break;
|
||||
case 9600:
|
||||
flag = B9600;
|
||||
break;
|
||||
case 19200:
|
||||
flag = B19200;
|
||||
break;
|
||||
case 38400:
|
||||
flag = B38400;
|
||||
break;
|
||||
case 57600:
|
||||
flag = B57600;
|
||||
break;
|
||||
case 115200:
|
||||
flag = B115200;
|
||||
break;
|
||||
case 230400:
|
||||
flag = B230400;
|
||||
break;
|
||||
case 460800:
|
||||
flag = B460800;
|
||||
break;
|
||||
case 500000:
|
||||
flag = B500000;
|
||||
break;
|
||||
case 576000:
|
||||
flag = B576000;
|
||||
break;
|
||||
case 921600:
|
||||
flag = B921600;
|
||||
break;
|
||||
case 1000000:
|
||||
flag = B1000000;
|
||||
break;
|
||||
case 1152000:
|
||||
flag = B1152000;
|
||||
break;
|
||||
case 1500000:
|
||||
flag = B1500000;
|
||||
break;
|
||||
case 2000000:
|
||||
flag = B2000000;
|
||||
break;
|
||||
case 2500000:
|
||||
flag = B2500000;
|
||||
break;
|
||||
case 3000000:
|
||||
flag = B3000000;
|
||||
break;
|
||||
case 3500000:
|
||||
flag = B3500000;
|
||||
break;
|
||||
case 4000000:
|
||||
flag = B4000000;
|
||||
break;
|
||||
|
||||
default:
|
||||
flag = B9600;
|
||||
break;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
101
hardware/SerialPort.h
Normal file
101
hardware/SerialPort.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#ifndef FA788814_8B75_424F_99DB_D04B4977DD8C
|
||||
#define FA788814_8B75_424F_99DB_D04B4977DD8C
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/Thread.h>
|
||||
#include <atomic>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class SerialPort
|
||||
{
|
||||
public:
|
||||
enum class Parity
|
||||
{
|
||||
NONE,
|
||||
ODD,
|
||||
EVEN,
|
||||
};
|
||||
|
||||
enum class FlowControl
|
||||
{
|
||||
NONE,
|
||||
RTSCTS,
|
||||
};
|
||||
|
||||
public:
|
||||
SerialPort();
|
||||
~SerialPort();
|
||||
|
||||
public:
|
||||
SerialPort& setPath(const std::string& path);
|
||||
SerialPort& setBaudRate(uint32_t baudRate);
|
||||
SerialPort& setParity(Parity parity);
|
||||
SerialPort& setDataBits(uint32_t bits);
|
||||
SerialPort& setStopBits(uint32_t bits);
|
||||
SerialPort& setFlowControl(FlowControl flowControl);
|
||||
void open();
|
||||
void close();
|
||||
bool isOpen();
|
||||
int write(const void* pData, uint32_t size);
|
||||
int read(void* pBuffer, uint32_t length, uint32_t timeout);
|
||||
|
||||
const std::string& getPath();
|
||||
uint32_t getBaudRate();
|
||||
Parity getParity();
|
||||
uint32_t getDataBits();
|
||||
uint32_t getStopBits();
|
||||
FlowControl getFlowControl();
|
||||
|
||||
protected:
|
||||
uint32_t getBaudRateFlag(uint32_t baudRate);
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
int _fd;
|
||||
uint32_t _baudRate;
|
||||
Parity _parity;
|
||||
uint32_t _dataBits;
|
||||
uint32_t _stopBits;
|
||||
FlowControl _flowControl;
|
||||
};
|
||||
|
||||
inline const std::string& SerialPort::getPath()
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
inline uint32_t SerialPort::getBaudRate()
|
||||
{
|
||||
return _baudRate;
|
||||
}
|
||||
|
||||
inline SerialPort::Parity SerialPort::getParity()
|
||||
{
|
||||
return _parity;
|
||||
}
|
||||
|
||||
inline uint32_t SerialPort::getDataBits()
|
||||
{
|
||||
return _dataBits;
|
||||
}
|
||||
|
||||
inline uint32_t SerialPort::getStopBits()
|
||||
{
|
||||
return _stopBits;
|
||||
}
|
||||
|
||||
inline SerialPort::FlowControl SerialPort::getFlowControl()
|
||||
{
|
||||
return _flowControl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
3
hardware/hardware.cmake
Normal file
3
hardware/hardware.cmake
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
add_subdirectory(hardware)
|
||||
include_directories(hardware)
|
||||
target_link_libraries(${PROJNAME} PRIVATE hardware)
|
||||
42
hardware/hisilicon/Board.cpp
Normal file
42
hardware/hisilicon/Board.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "../BoardInfo.h"
|
||||
#include "Board.h"
|
||||
#include <Poco/Format.h>
|
||||
#include <Poco/MD5Engine.h>
|
||||
#include <iostream>
|
||||
#include <hi_mpi_sys.h>
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
namespace Hisilicon
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Board::Board()
|
||||
{
|
||||
hi_unique_id id;
|
||||
hi_mpi_sys_get_unique_id(&id);
|
||||
for (size_t i = 0; i < HI_UNIQUE_ID_NUM; i++)
|
||||
{
|
||||
std::cout << "#" << i << ": " << Poco::format("%08x", id.id[i]) << std::endl;
|
||||
}
|
||||
|
||||
Poco::MD5Engine md5;
|
||||
md5.update(id.id, sizeof(id.id));
|
||||
_serialNumber = Poco::DigestEngine::digestToHex(md5.digest());
|
||||
std::cout << "Serial Number: " << _serialNumber << std::endl;
|
||||
}
|
||||
|
||||
std::string Hisilicon::Board::serialNumber()
|
||||
{
|
||||
return _serialNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
hardware/hisilicon/Board.h
Normal file
33
hardware/hisilicon/Board.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef A6A48FAD_A41E_4AF4_A92C_A3CFE3D065B1
|
||||
#define A6A48FAD_A41E_4AF4_A92C_A3CFE3D065B1
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "../BoardInfo.h"
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
namespace Hisilicon
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Board: public Hardware::Board
|
||||
{
|
||||
public:
|
||||
Board();
|
||||
~Board();
|
||||
|
||||
public:
|
||||
virtual std::string serialNumber() override;
|
||||
|
||||
private:
|
||||
std::string _serialNumber;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
51
hardware/hisilicon/TemperatureSensor.cpp
Normal file
51
hardware/hisilicon/TemperatureSensor.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "TemperatureSensor.h"
|
||||
#include "memmap.h"
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
namespace Hisilicon
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#define TSENSOR_CTRL_REG_BASE 0x1102A000
|
||||
|
||||
TemperatureSensor::TemperatureSensor(): Sensor(Sensor::Type::TEMPERATURE)
|
||||
{
|
||||
_pRegisters = getRegisters();
|
||||
|
||||
_pRegisters->ctrl0 |= (1 << 31) | (1 << 30);
|
||||
|
||||
_pRegisters->ctrl1 |= (3 << 2);
|
||||
}
|
||||
|
||||
TemperatureSensor::~TemperatureSensor()
|
||||
{
|
||||
_pRegisters->ctrl0 = 0;
|
||||
releaseRegisters(_pRegisters);
|
||||
}
|
||||
|
||||
void TemperatureSensor::read(float& value)
|
||||
{
|
||||
uint32_t rval = _pRegisters->ctrl2 & 0x3ff;
|
||||
value = (float)(rval - 117) / 784 * 165 - 40;
|
||||
}
|
||||
|
||||
TemperatureSensor::Registers* TemperatureSensor::getRegisters()
|
||||
{
|
||||
return (Registers*)memmap(TSENSOR_CTRL_REG_BASE, sizeof(Registers));
|
||||
}
|
||||
|
||||
void TemperatureSensor::releaseRegisters(Registers* pRegisters)
|
||||
{
|
||||
memunmap(pRegisters);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
hardware/hisilicon/TemperatureSensor.h
Normal file
48
hardware/hisilicon/TemperatureSensor.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef CBEF59CE_2DB7_43B5_AFA8_524952A27AF9
|
||||
#define CBEF59CE_2DB7_43B5_AFA8_524952A27AF9
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "../Sensor.h"
|
||||
|
||||
namespace Hardware
|
||||
{
|
||||
namespace Hisilicon
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class TemperatureSensor: public Sensor
|
||||
{
|
||||
protected:
|
||||
struct Registers
|
||||
{
|
||||
uint32_t ctrl0;
|
||||
uint32_t ctrl1;
|
||||
uint32_t ctrl2;
|
||||
uint32_t ctrl3;
|
||||
uint32_t ctrl4;
|
||||
uint32_t ctrl5;
|
||||
};
|
||||
|
||||
public:
|
||||
TemperatureSensor();
|
||||
~TemperatureSensor();
|
||||
|
||||
public:
|
||||
virtual void read(float& value) override;
|
||||
|
||||
protected:
|
||||
Registers* getRegisters();
|
||||
void releaseRegisters(Registers* pRegisters);
|
||||
|
||||
private:
|
||||
Registers* _pRegisters;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
275
hardware/hisilicon/memmap.c
Normal file
275
hardware/hisilicon/memmap.c
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
/************************************************************/
|
||||
/* file name : memmap.c */
|
||||
/* linux /dev/mem mmap support func */
|
||||
/* */
|
||||
/* */
|
||||
/* Copyright 2005 huawei com. */
|
||||
/* Author :zhouaidi(42136) */
|
||||
/* Create date: 2005-04-07 */
|
||||
/* Modify history */
|
||||
/* 2005-12-21: add memunmap function */
|
||||
/************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
typedef struct tag_MMAP_Node
|
||||
{
|
||||
unsigned long Start_P;
|
||||
unsigned long Start_V;
|
||||
unsigned long length;
|
||||
unsigned long refcount;
|
||||
struct tag_MMAP_Node * next;
|
||||
}TMMAP_Node_t;
|
||||
|
||||
TMMAP_Node_t * pTMMAPNode = NULL;
|
||||
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define PAGE_SIZE_MASK (~(0xfff))
|
||||
|
||||
static int fd = -1;
|
||||
static const char dev[]="/dev/mem";
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* MACROS
|
||||
*******************************************************************************
|
||||
*/
|
||||
#define WRITE_LOG_DEBUG(fmt, ...) printf("%05d:[debug] "fmt"\r\n", __LINE__, ##__VA_ARGS__)
|
||||
#define WRITE_LOG_INFO(fmt, ...) printf("%05d:[info ] "fmt"\r\n", __LINE__, ##__VA_ARGS__)
|
||||
#define WRITE_LOG_ERROR(fmt, ...) printf("%05d:[error] "fmt"\r\n", __LINE__, ##__VA_ARGS__)
|
||||
|
||||
|
||||
/* no need considering page_size of 4K */
|
||||
void * memmap(unsigned long phy_addr, unsigned long size)
|
||||
{
|
||||
unsigned long phy_addr_in_page;
|
||||
unsigned long page_diff;
|
||||
|
||||
unsigned long size_in_page;
|
||||
|
||||
TMMAP_Node_t * pTmp;
|
||||
TMMAP_Node_t * pNew;
|
||||
|
||||
void *addr=NULL;
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
WRITE_LOG_ERROR("memmap():size can't be zero!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check if the physical memory space have been mmaped */
|
||||
pTmp = pTMMAPNode;
|
||||
while(pTmp != NULL)
|
||||
{
|
||||
if( (phy_addr >= pTmp->Start_P) &&
|
||||
( (phy_addr + size) <= (pTmp->Start_P + pTmp->length) ) )
|
||||
{
|
||||
pTmp->refcount++; /* referrence count increase by 1 */
|
||||
return (void *)(pTmp->Start_V + phy_addr - pTmp->Start_P);
|
||||
}
|
||||
|
||||
pTmp = pTmp->next;
|
||||
}
|
||||
|
||||
/* not mmaped yet */
|
||||
if(fd < 0)
|
||||
{
|
||||
/* dev not opened yet, so open it */
|
||||
fd = open (dev, O_RDWR | O_SYNC);
|
||||
if (fd < 0)
|
||||
{
|
||||
WRITE_LOG_ERROR("memmap():open %s error!\n", dev);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* addr align in page_size(4K) */
|
||||
phy_addr_in_page = phy_addr & PAGE_SIZE_MASK;
|
||||
page_diff = phy_addr - phy_addr_in_page;
|
||||
|
||||
/* size in page_size */
|
||||
size_in_page =((size + page_diff - 1) & PAGE_SIZE_MASK) + PAGE_SIZE;
|
||||
|
||||
addr = mmap((void *)0, size_in_page, PROT_READ|PROT_WRITE, MAP_SHARED, fd, phy_addr_in_page);
|
||||
if (addr == MAP_FAILED)
|
||||
{
|
||||
WRITE_LOG_ERROR("memmap():mmap @ 0x%x error!\n", phy_addr_in_page);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* add this mmap to MMAP Node */
|
||||
pNew = (TMMAP_Node_t *)malloc(sizeof(TMMAP_Node_t));
|
||||
if(NULL == pNew)
|
||||
{
|
||||
WRITE_LOG_ERROR("memmap():malloc new node failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
pNew->Start_P = phy_addr_in_page;
|
||||
pNew->Start_V = (unsigned long)addr;
|
||||
pNew->length = size_in_page;
|
||||
pNew->refcount = 1;
|
||||
pNew->next = NULL;
|
||||
|
||||
if(pTMMAPNode == NULL)
|
||||
{
|
||||
pTMMAPNode = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTmp = pTMMAPNode;
|
||||
while(pTmp->next != NULL)
|
||||
{
|
||||
pTmp = pTmp->next;
|
||||
}
|
||||
|
||||
pTmp->next = pNew;
|
||||
}
|
||||
|
||||
return (void *)(addr+page_diff);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : memunmap
|
||||
Description :
|
||||
Input : void * addr_mapped
|
||||
Output : None
|
||||
Return Value : On success, returns 0, on failure -1
|
||||
Calls :
|
||||
Called By :
|
||||
|
||||
History :
|
||||
1.Date : 2005/12/21
|
||||
Author : Z42136
|
||||
Modification : Created function
|
||||
|
||||
*****************************************************************************/
|
||||
int memunmap(void * addr_mapped)
|
||||
{
|
||||
TMMAP_Node_t * pPre;
|
||||
TMMAP_Node_t * pTmp;
|
||||
|
||||
if(pTMMAPNode == NULL)
|
||||
{
|
||||
WRITE_LOG_ERROR("memunmap(): address have not been mmaped!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check if the physical memory space have been mmaped */
|
||||
pTmp = pTMMAPNode;
|
||||
pPre = pTMMAPNode;
|
||||
|
||||
do
|
||||
{
|
||||
if( ((unsigned long)addr_mapped >= pTmp->Start_V) &&
|
||||
((unsigned long)addr_mapped <= (pTmp->Start_V + pTmp->length)) )
|
||||
{
|
||||
pTmp->refcount--; /* referrence count decrease by 1 */
|
||||
if(0 == pTmp->refcount)
|
||||
{
|
||||
|
||||
// WRITE_LOG_INFO("memunmap(): map node will be remove!\n");
|
||||
|
||||
/* delete this map node from pMMAPNode */
|
||||
if(pTmp == pTMMAPNode)
|
||||
{
|
||||
pTMMAPNode = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPre->next = pTmp->next;
|
||||
}
|
||||
|
||||
/* munmap */
|
||||
if(munmap((void *)pTmp->Start_V, pTmp->length) != 0 )
|
||||
{
|
||||
WRITE_LOG_INFO("memunmap(): munmap failed!\n");
|
||||
}
|
||||
|
||||
free(pTmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pPre = pTmp;
|
||||
pTmp = pTmp->next;
|
||||
}while(pTmp != NULL);
|
||||
|
||||
WRITE_LOG_ERROR("memunmap(): address have not been mmaped!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void * mmapfile(char* fn, unsigned long size)
|
||||
{
|
||||
int fd;
|
||||
void * pShm = NULL;
|
||||
if (fn == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
/* Open the file. */
|
||||
fd = open (fn, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | O_SYNC);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
WRITE_LOG_DEBUG("Open file %s error: %i.\n",fn, errno );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the memory-mapping. */
|
||||
pShm = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
close (fd);
|
||||
if (pShm != NULL)
|
||||
{
|
||||
WRITE_LOG_DEBUG("Memory Map OK. Map File: %s, length:%#X, addr:0x%08lX",
|
||||
fn, size, (unsigned long)pShm);
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE_LOG_DEBUG("Memory Map Failure. Map File %s, length:0x%08lX",
|
||||
fn, size);
|
||||
}
|
||||
return pShm;
|
||||
}
|
||||
|
||||
void * mmapfile_r(char* fn, unsigned long size)
|
||||
{
|
||||
int fd;
|
||||
void * pShm = NULL;
|
||||
if (fn == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
/* Open the file. */
|
||||
fd = open (fn, O_RDONLY | O_SYNC);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
WRITE_LOG_INFO("Open file %s error: %d.\n",fn, errno );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the memory-mapping. */
|
||||
pShm = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
close (fd);
|
||||
if (pShm != NULL)
|
||||
{
|
||||
WRITE_LOG_DEBUG("Memory Map OK. Map File: %s, length:%#X, addr:0x%08lX\n",
|
||||
fn, size, (unsigned long)pShm);
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE_LOG_DEBUG("Memory Map Failure. Map File %s, length:0x%08lX\n",
|
||||
fn, size);
|
||||
}
|
||||
return pShm;
|
||||
}
|
||||
|
||||
33
hardware/hisilicon/memmap.h
Normal file
33
hardware/hisilicon/memmap.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
/* file name : memmap.h */
|
||||
/* linux /dev/mem mmap support head file */
|
||||
/* */
|
||||
/* */
|
||||
/* Copyright 2005 huawei com. */
|
||||
/* Author :zhouaidi(42136) */
|
||||
/* Create date: 2005-04-07 */
|
||||
/* Modify history */
|
||||
/* */
|
||||
|
||||
#ifndef __MEM_MAP_H__
|
||||
#define __MEM_MAP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
extern void * memmap(unsigned long phy_addr, unsigned long size);
|
||||
extern int memunmap(void * addr_mapped);
|
||||
extern void * mmapfile(char* fn, unsigned int size);
|
||||
extern void * mmapfile_r(char* fn, unsigned int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
|
||||
75
main.cpp
Normal file
75
main.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Application.h"
|
||||
#ifdef USING_HARDWARE_SUBSYSTEM
|
||||
#include "HardwareSubsystem.h"
|
||||
#endif
|
||||
|
||||
#ifdef USING_NETWORK_SUBSYSTEM
|
||||
#include "NetworkSubsystem.h"
|
||||
#endif
|
||||
|
||||
#ifdef USING_GRAPHICS_SUBSYSTEM
|
||||
#include "GraphicsSubsystem.h"
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_GUI_APPLICATION
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
#ifdef USING_VIDEO_SUBSYSTEM
|
||||
#include "VideoSubsystem.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* FUNCTIONS
|
||||
*******************************************************************************
|
||||
*/
|
||||
#ifdef WINDOWS_GUI_APPLICATION
|
||||
int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine,
|
||||
_In_ INT nCmdShow)
|
||||
#else
|
||||
int main()
|
||||
#endif
|
||||
{
|
||||
Application app;
|
||||
|
||||
#ifdef USING_HARDWARE_SUBSYSTEM
|
||||
app.addSubsystem(new Hardware::HardwareSubsystem());
|
||||
#endif
|
||||
|
||||
#ifdef USING_NETWORK_SUBSYSTEM
|
||||
app.addSubsystem(new Network::NetworkSubsystem());
|
||||
#endif
|
||||
|
||||
#ifdef USING_GRAPHICS_SUBSYSTEM
|
||||
app.addSubsystem(new Graphics::GraphicsSubsystem());
|
||||
#endif
|
||||
|
||||
#ifdef USING_VIDEO_SUBSYSTEM
|
||||
app.addSubsystem(new Video::VideoSubsystem());
|
||||
#endif
|
||||
|
||||
int rc = 0;
|
||||
|
||||
try
|
||||
{
|
||||
rc = app.run();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "Unknown exception" << std::endl;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
6
network/CMakeLists.txt
Normal file
6
network/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
set(target network)
|
||||
aux_source_directory(. NETWORK_SOURCES)
|
||||
|
||||
add_library(${target} STATIC
|
||||
${NETWORK_SOURCES}
|
||||
)
|
||||
53
network/HTTPServer.cpp
Normal file
53
network/HTTPServer.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "HTTPServer.h"
|
||||
|
||||
using namespace Poco::Net;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
class RouterRequestHandlerFactory: public HTTPRequestHandlerFactory
|
||||
{
|
||||
public:
|
||||
HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request) override
|
||||
{
|
||||
throw Poco::NotFoundException("Not found");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
std::string HTTPServer::HOST = "host";
|
||||
std::string HTTPServer::PORT = "port";
|
||||
|
||||
HTTPServer::HTTPServer(): _pHTTPServer(nullptr)
|
||||
{
|
||||
setParameter(HOST, std::string("::"));
|
||||
setParameter(PORT, 80);
|
||||
}
|
||||
|
||||
HTTPServer::~HTTPServer()
|
||||
{
|
||||
}
|
||||
|
||||
void HTTPServer::start()
|
||||
{
|
||||
Poco::Net::SocketAddress address(getParameter<std::string>(HOST), getParameter<int>(PORT));
|
||||
Poco::Net::ServerSocket socket(address);
|
||||
Poco::Net::HTTPServerParams* pParams = new Poco::Net::HTTPServerParams();
|
||||
pParams->setKeepAlive(false);
|
||||
_pHTTPServer = new Poco::Net::HTTPServer(new RouterRequestHandlerFactory, socket, pParams);
|
||||
_pHTTPServer->start();
|
||||
}
|
||||
|
||||
void HTTPServer::stop()
|
||||
{
|
||||
_pHTTPServer->stopAll();
|
||||
}
|
||||
}
|
||||
37
network/HTTPServer.h
Normal file
37
network/HTTPServer.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef DC9BEC60_0C80_41F2_B1F7_289C63388DC1
|
||||
#define DC9BEC60_0C80_41F2_B1F7_289C63388DC1
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include "util/Configuration.h"
|
||||
|
||||
namespace Network
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class HTTPServer: public Util::Configuration
|
||||
{
|
||||
public:
|
||||
static std::string HOST;
|
||||
|
||||
static std::string PORT;
|
||||
|
||||
public:
|
||||
HTTPServer();
|
||||
~HTTPServer();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
Poco::SharedPtr<Poco::Net::HTTPServer> _pHTTPServer;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
40
network/NetworkSubsystem.cpp
Normal file
40
network/NetworkSubsystem.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "NetworkSubsystem.h"
|
||||
#include "Application.h"
|
||||
#include "Logger.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Net/DNS.h"
|
||||
|
||||
namespace Network
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
NetworkSubsystem::NetworkSubsystem()
|
||||
{
|
||||
}
|
||||
|
||||
NetworkSubsystem::~NetworkSubsystem()
|
||||
{
|
||||
}
|
||||
|
||||
const char* NetworkSubsystem::name() const
|
||||
{
|
||||
return "Network";
|
||||
}
|
||||
|
||||
void NetworkSubsystem::initialize(Poco::Util::Application& app)
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkSubsystem::uninitialize()
|
||||
{
|
||||
stopAll();
|
||||
}
|
||||
}
|
||||
47
network/NetworkSubsystem.h
Normal file
47
network/NetworkSubsystem.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef __NETWORK_SUBSYSTEM__H__
|
||||
#define __NETWORK_SUBSYSTEM__H__
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "util/Subsystem.h"
|
||||
|
||||
namespace Network
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class NetworkSubsystem: public Util::Subsystem
|
||||
{
|
||||
public:
|
||||
NetworkSubsystem();
|
||||
~NetworkSubsystem();
|
||||
|
||||
virtual const char* name() const override;
|
||||
|
||||
protected:
|
||||
virtual void initialize(Poco::Util::Application& app);
|
||||
virtual void uninitialize();
|
||||
|
||||
public:
|
||||
struct ZLStreamPushMessage
|
||||
{
|
||||
std::string appname;
|
||||
std::string streamid;
|
||||
short type;
|
||||
ZLStreamPushMessage(const std::string& appname, const std::string& streamid, short type)
|
||||
: appname(appname), streamid(streamid), type(type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Poco::BasicEvent<ZLStreamPushMessage> ZLStreamPushMessageEvent;
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
#endif
|
||||
148
network/TCPClient.cpp
Normal file
148
network/TCPClient.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "TCPClient.h"
|
||||
#include <Poco/Net/NetException.h>
|
||||
|
||||
|
||||
namespace Network
|
||||
{
|
||||
|
||||
TCPClient::TCPClient(std::string host, int port, Poco::Timespan timeout, uint32_t sz)
|
||||
: Poco::Task("TCPClient"), _address(host, port), _timeout(timeout), _bufsz(sz), _pBuffer(new uint8_t[sz])
|
||||
{
|
||||
}
|
||||
|
||||
TCPClient::~TCPClient()
|
||||
{
|
||||
}
|
||||
|
||||
int TCPClient::send(const uint8_t* data, uint32_t len)
|
||||
{
|
||||
try
|
||||
{
|
||||
int rc = _socket.sendBytes(data, len);
|
||||
return rc;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TCPClient::start()
|
||||
{
|
||||
if (!_thread.isRunning())
|
||||
_thread.start(*this);
|
||||
}
|
||||
|
||||
void TCPClient::stop()
|
||||
{
|
||||
if (_thread.isRunning())
|
||||
{
|
||||
cancel();
|
||||
_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPClient::setStateChangedCallback(const StateChangedCallback& callback)
|
||||
{
|
||||
_stateChanged = std::move(callback);
|
||||
}
|
||||
|
||||
void TCPClient::setDataIncomingCallback(const DataIncomingCallback& callback)
|
||||
{
|
||||
_dataIncoming = std::move(callback);
|
||||
}
|
||||
|
||||
bool TCPClient::connect()
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket.connect(_address, _timeout);
|
||||
_socket.setReceiveTimeout(Poco::Timespan(1000));
|
||||
setState(State::CONNECTED, "Connected");
|
||||
return true;
|
||||
}
|
||||
catch (Poco::TimeoutException& e)
|
||||
{
|
||||
setState(State::CONNECT_TIMEOUT, e.displayText());
|
||||
}
|
||||
catch (Poco::Net::ConnectionRefusedException& e)
|
||||
{
|
||||
setState(State::CONNECT_REFUSED, e.displayText());
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
setState(State::CONNECT_REFUSED, e.displayText());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TCPClient::runTask()
|
||||
{
|
||||
while (!isCancelled())
|
||||
{
|
||||
while (!isCancelled())
|
||||
{
|
||||
setState(State::CONNECTING, "Connecting");
|
||||
if (connect())
|
||||
break;
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
}
|
||||
|
||||
while (!isCancelled())
|
||||
{
|
||||
try
|
||||
{
|
||||
int rc = _socket.receiveBytes(_pBuffer, _bufsz);
|
||||
if (rc <= 0)
|
||||
{
|
||||
setState(State::DISCONNECTED, "Connection lost");
|
||||
_socket.close();
|
||||
break;
|
||||
}
|
||||
|
||||
receive(_pBuffer, rc);
|
||||
}
|
||||
catch (Poco::TimeoutException& e)
|
||||
{
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
setState(State::DISCONNECTED, "Connection lost");
|
||||
_socket.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_socket.close();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void TCPClient::setState(State state, const std::string& desc)
|
||||
{
|
||||
if (_stateChanged)
|
||||
_stateChanged(state, desc);
|
||||
}
|
||||
|
||||
void TCPClient::receive(const uint8_t* data, uint32_t len)
|
||||
{
|
||||
if (_dataIncoming)
|
||||
_dataIncoming(data, len);
|
||||
}
|
||||
|
||||
}
|
||||
65
network/TCPClient.h
Normal file
65
network/TCPClient.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef __TCP_CLIENT_H__
|
||||
#define __TCP_CLIENT_H__
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/Net/StreamSocket.h>
|
||||
#include <Poco/Task.h>
|
||||
#include <Poco/Timespan.h>
|
||||
#include <functional>
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
namespace Network
|
||||
{
|
||||
|
||||
class TCPClient: public Poco::Task
|
||||
{
|
||||
public:
|
||||
enum class State
|
||||
{
|
||||
DISCONNECTED,
|
||||
CONNECT_TIMEOUT,
|
||||
CONNECT_REFUSED,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
};
|
||||
|
||||
using StateChangedCallback = std::function<void(State, const std::string&)>;
|
||||
using DataIncomingCallback = std::function<void(const uint8_t*, uint32_t)>;
|
||||
|
||||
public:
|
||||
TCPClient(std::string host, int port, Poco::Timespan timeout, uint32_t sz = 10240);
|
||||
~TCPClient();
|
||||
|
||||
int send(const uint8_t* data, uint32_t len);
|
||||
void start();
|
||||
void stop();
|
||||
void setStateChangedCallback(const StateChangedCallback& callback);
|
||||
void setDataIncomingCallback(const DataIncomingCallback& callback);
|
||||
|
||||
protected:
|
||||
bool connect();
|
||||
void receive(const uint8_t* data, uint32_t len);
|
||||
virtual void runTask() override;
|
||||
void setState(State state, const std::string& desc);
|
||||
|
||||
private:
|
||||
Poco::Thread _thread;
|
||||
Poco::Net::StreamSocket _socket;
|
||||
Poco::Net::SocketAddress _address;
|
||||
Poco::Timespan _timeout;
|
||||
uint32_t _bufsz;
|
||||
Poco::SharedPtr<uint8_t> _pBuffer;
|
||||
StateChangedCallback _stateChanged;
|
||||
DataIncomingCallback _dataIncoming;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
3
network/network.cmake
Normal file
3
network/network.cmake
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
add_subdirectory(network)
|
||||
include_directories(network)
|
||||
target_link_libraries(${PROJNAME} PRIVATE network)
|
||||
57
util/AESUtil.h
Normal file
57
util/AESUtil.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef A89D0C3C_4F05_4631_A720_D8B2CEA5E99A
|
||||
#define A89D0C3C_4F05_4631_A720_D8B2CEA5E99A
|
||||
#include <Poco/Base64Decoder.h>
|
||||
#include <Poco/Base64Encoder.h>
|
||||
#include <Poco/Crypto/Cipher.h>
|
||||
#include <Poco/Crypto/CipherFactory.h>
|
||||
#include <Poco/Crypto/CipherKey.h>
|
||||
#include <Poco/StreamCopier.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Logger.h"
|
||||
namespace Util
|
||||
{
|
||||
class AESUtil
|
||||
{
|
||||
public:
|
||||
static std::string encryptAES(const std::string& plaintext, const std::string& key, const std::string& iv)
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::Crypto::CipherKey cipherKey("aes-256-cbc", key, iv);
|
||||
Poco::Crypto::CipherFactory& factory = Poco::Crypto::CipherFactory::defaultFactory();
|
||||
std::unique_ptr<Poco::Crypto::Cipher> pCipher(factory.createCipher(cipherKey));
|
||||
|
||||
std::string ciphertext = pCipher->encryptString(plaintext, Poco::Crypto::Cipher::ENC_BASE64_NO_LF);
|
||||
return ciphertext;
|
||||
}
|
||||
catch (const Poco::Exception& e)
|
||||
{
|
||||
logger().error("encryptAES error: %s", std::string(e.what()));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string decryptAES(const std::string& ciphertext, const std::string& key, const std::string& iv)
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::Crypto::CipherKey cipherKey("aes-256-cbc", key, iv);
|
||||
Poco::Crypto::CipherFactory& factory = Poco::Crypto::CipherFactory::defaultFactory();
|
||||
std::unique_ptr<Poco::Crypto::Cipher> pCipher(factory.createCipher(cipherKey));
|
||||
|
||||
std::string plaintext = pCipher->decryptString(ciphertext, Poco::Crypto::Cipher::ENC_BASE64_NO_LF);
|
||||
return plaintext;
|
||||
}
|
||||
catch (const Poco::Exception& e)
|
||||
{
|
||||
logger().error("decryptAES error: %s", std::string(e.what()));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
35
util/Base64Util.h
Normal file
35
util/Base64Util.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef CFCB972C_1202_49D2_AAD4_9066BA17F94F
|
||||
#define CFCB972C_1202_49D2_AAD4_9066BA17F94F
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/Base64Encoder.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
class Base64Util
|
||||
{
|
||||
private:
|
||||
public:
|
||||
static std::string base64Encode(const std::string& input)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
Poco::Base64Encoder encoder(oss, 0);
|
||||
encoder.write(input.data(), input.size());
|
||||
encoder.close();
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static std::string base64Decode(const std::string& input)
|
||||
{
|
||||
std::istringstream iss(input);
|
||||
Poco::Base64Decoder decoder(iss);
|
||||
std::ostringstream oss;
|
||||
Poco::StreamCopier::copyStream(decoder, oss);
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
144
util/Broadcast.cpp
Normal file
144
util/Broadcast.cpp
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Broadcast.h"
|
||||
#include <Poco/Mutex.h>
|
||||
#include <Poco/ScopedLock.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class BroadcastObserver
|
||||
{
|
||||
public:
|
||||
BroadcastObserver(BroadcastReceiver& receiver, IntentFilter::Ptr pFilter): _pReceiver(&receiver), _pFilter(pFilter)
|
||||
{
|
||||
}
|
||||
|
||||
void broadcast(Intent::Ptr pIntent)
|
||||
{
|
||||
if (_pFilter->match(pIntent))
|
||||
_pReceiver->onReceive(pIntent);
|
||||
}
|
||||
|
||||
bool equals(const BroadcastObserver& observer)
|
||||
{
|
||||
return _pReceiver == observer._pReceiver;
|
||||
}
|
||||
|
||||
bool isBoundTo(BroadcastReceiver& receiver)
|
||||
{
|
||||
return _pReceiver == &receiver;
|
||||
}
|
||||
|
||||
private:
|
||||
BroadcastReceiver* _pReceiver;
|
||||
IntentFilter::Ptr _pFilter;
|
||||
};
|
||||
|
||||
class BroadcastCore
|
||||
{
|
||||
public:
|
||||
void sendBroadcast(Intent::Ptr pIntent)
|
||||
{
|
||||
Poco::ScopedLockWithUnlock<Poco::Mutex> lock(_mutex);
|
||||
BroadcastObserverList list(_broadcastObservers);
|
||||
lock.unlock();
|
||||
for (auto& p : list)
|
||||
p->broadcast(pIntent);
|
||||
}
|
||||
|
||||
void registerReceiver(BroadcastReceiver& receiver, IntentFilter::Ptr pFilter)
|
||||
{
|
||||
Poco::Mutex::ScopedLock lock(_mutex);
|
||||
for (auto& obs : _broadcastObservers)
|
||||
{
|
||||
if (obs->isBoundTo(receiver))
|
||||
return;
|
||||
}
|
||||
|
||||
_broadcastObservers.push_back(new BroadcastObserver(receiver, pFilter));
|
||||
}
|
||||
|
||||
void unregisterReceiver(BroadcastReceiver& receiver)
|
||||
{
|
||||
Poco::Mutex::ScopedLock lock(_mutex);
|
||||
for (BroadcastObserverList::iterator it = _broadcastObservers.begin(); it != _broadcastObservers.end();)
|
||||
{
|
||||
if ((*it)->isBoundTo(receiver))
|
||||
it = _broadcastObservers.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using BroadcastObserverPtr = Poco::SharedPtr<BroadcastObserver>;
|
||||
using BroadcastObserverList = std::vector<BroadcastObserverPtr>;
|
||||
|
||||
BroadcastObserverList _broadcastObservers;
|
||||
mutable Poco::Mutex _mutex;
|
||||
};
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Intent& Intent::putExtra(const std::string& key, const char* value)
|
||||
{
|
||||
return putExtra(key, std::string(value));
|
||||
}
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
void IntentFilter::addAction(const std::string& action)
|
||||
{
|
||||
_actions.push_back(action);
|
||||
}
|
||||
|
||||
bool IntentFilter::match(Intent::Ptr pIntent) const
|
||||
{
|
||||
const std::string& target = pIntent->getAction();
|
||||
return std::find(_actions.begin(), _actions.end(), target) != _actions.end();
|
||||
}
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* LOCAL VARIABLES
|
||||
*******************************************************************************
|
||||
*/
|
||||
namespace
|
||||
{
|
||||
static BroadcastCore core;
|
||||
}
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
void BroadcastSender::sendBroadcast(Intent::Ptr pIntent)
|
||||
{
|
||||
core.sendBroadcast(pIntent);
|
||||
}
|
||||
|
||||
void BroadcastReceiverRegistry::registerReceiver(BroadcastReceiver& receiver, IntentFilter::Ptr pFilter)
|
||||
{
|
||||
core.registerReceiver(receiver, pFilter);
|
||||
}
|
||||
|
||||
void BroadcastReceiverRegistry::unregisterReceiver(BroadcastReceiver& receiver)
|
||||
{
|
||||
core.unregisterReceiver(receiver);
|
||||
}
|
||||
}
|
||||
117
util/Broadcast.h
Normal file
117
util/Broadcast.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
#ifndef C81E1B2C_54AF_4E7D_800B_F21E0DACFD8B
|
||||
#define C81E1B2C_54AF_4E7D_800B_F21E0DACFD8B
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <Poco/Format.h>
|
||||
#include <Poco/SharedPtr.h>
|
||||
#include <Poco/Any.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Intent
|
||||
{
|
||||
public:
|
||||
using Ptr = Poco::SharedPtr<Intent>;
|
||||
|
||||
template <class T> Intent& putExtra(const std::string& key, const T& value);
|
||||
Intent& putExtra(const std::string& key, const char* value);
|
||||
|
||||
template <class T> const T getExtra(const std::string& key) const;
|
||||
|
||||
const std::string& getAction() const;
|
||||
void setAction(const std::string& action);
|
||||
|
||||
private:
|
||||
using Value = Poco::Any;
|
||||
using Values = std::unordered_map<std::string, Value>;
|
||||
Values _values;
|
||||
|
||||
std::string _action;
|
||||
};
|
||||
|
||||
template <class T> inline Intent& Intent::putExtra(const std::string& key, const T& value)
|
||||
{
|
||||
_values[key] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T> inline const T Intent::getExtra(const std::string& key) const
|
||||
{
|
||||
if (_values.find(key) == _values.end())
|
||||
throw Poco::NotFoundException(Poco::format("Intent: Can't find value: %s", key), -ENODATA);
|
||||
|
||||
return Poco::AnyCast<T>(_values.at(key));
|
||||
}
|
||||
|
||||
inline const std::string& Intent::getAction() const
|
||||
{
|
||||
return _action;
|
||||
}
|
||||
|
||||
inline void Intent::setAction(const std::string& action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class IntentFilter
|
||||
{
|
||||
public:
|
||||
using Ptr = Poco::SharedPtr<IntentFilter>;
|
||||
|
||||
void addAction(const std::string& action);
|
||||
bool match(Intent::Ptr pIntent) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> _actions;
|
||||
};
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class BroadcastReceiver
|
||||
{
|
||||
public:
|
||||
virtual void onReceive(Intent::Ptr pIntent) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class BroadcastSender
|
||||
{
|
||||
public:
|
||||
void sendBroadcast(Intent::Ptr pIntent);
|
||||
};
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class BroadcastReceiverRegistry
|
||||
{
|
||||
public:
|
||||
void registerReceiver(BroadcastReceiver& receiver, IntentFilter::Ptr pFilter);
|
||||
void unregisterReceiver(BroadcastReceiver& receiver);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
15
util/BuilderSet.cpp
Normal file
15
util/BuilderSet.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "BuilderSet.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
}
|
||||
63
util/BuilderSet.h
Normal file
63
util/BuilderSet.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef BE7ED734_3D5C_4600_89C3_4082EB263BE0
|
||||
#define BE7ED734_3D5C_4600_89C3_4082EB263BE0
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/SharedPtr.h>
|
||||
#include <map>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
template <class T, class TKey, class TSelector, class... TArgs> class BuilderSet
|
||||
{
|
||||
private:
|
||||
class IBuilder
|
||||
{
|
||||
public:
|
||||
using Ptr = Poco::SharedPtr<IBuilder>;
|
||||
virtual ~IBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
virtual T* build(TArgs... args) = 0;
|
||||
};
|
||||
|
||||
template <class C> class Builder: public IBuilder
|
||||
{
|
||||
public:
|
||||
C* build(TArgs... args) override
|
||||
{
|
||||
C* p = new C(args...);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
using Builders = std::map<TKey, typename IBuilder::Ptr>;
|
||||
|
||||
public:
|
||||
static T* build(TArgs... args)
|
||||
{
|
||||
TKey key = TSelector::select(args...);
|
||||
return _builders[key]->build(args...);
|
||||
}
|
||||
|
||||
template <class C> static void registerClass(TKey key)
|
||||
{
|
||||
_builders[key] = new Builder<C>();
|
||||
}
|
||||
|
||||
private:
|
||||
static Builders _builders;
|
||||
};
|
||||
|
||||
template <class T, class TKey, class TSelect, class... TArgs>
|
||||
typename BuilderSet<T, TKey, TSelect, TArgs...>::Builders BuilderSet<T, TKey, TSelect, TArgs...>::_builders;
|
||||
}
|
||||
#endif
|
||||
5
util/CMakeLists.txt
Normal file
5
util/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
set(target util)
|
||||
|
||||
aux_source_directory(. UTIL_SOURCES)
|
||||
add_library(${target} STATIC ${UTIL_SOURCES} )
|
||||
|
||||
28
util/ClassAssistant.cpp
Normal file
28
util/ClassAssistant.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "ClassAssistant.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
std::string Util::ClassAssistant::demangle(const std::type_info& ti)
|
||||
{
|
||||
int status;
|
||||
char* demangled = abi::__cxa_demangle(ti.name(), nullptr, nullptr, &status);
|
||||
if (status == 0)
|
||||
{
|
||||
std::string result(demangled);
|
||||
free(demangled);
|
||||
return result;
|
||||
}
|
||||
|
||||
return ti.name();
|
||||
}
|
||||
}
|
||||
68
util/ClassAssistant.h
Normal file
68
util/ClassAssistant.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef AD5404F9_7A8A_45FF_8ABE_66F7E9E53212
|
||||
#define AD5404F9_7A8A_45FF_8ABE_66F7E9E53212
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* MACROS
|
||||
*******************************************************************************
|
||||
*/
|
||||
#define PROPERTY_DECLARE(name, type, defaultValue, setAccessibility, getAccessibility) \
|
||||
private: \
|
||||
type _##name = defaultValue; \
|
||||
setAccessibility: \
|
||||
void set##name(const type& value) \
|
||||
{ \
|
||||
_##name = value; \
|
||||
} \
|
||||
getAccessibility: \
|
||||
type get##name() \
|
||||
{ \
|
||||
return _##name; \
|
||||
}
|
||||
|
||||
#define READONLY_PROPERTY_DECLARE(name, type) \
|
||||
private: \
|
||||
type _##name; \
|
||||
\
|
||||
public: \
|
||||
const type& name() \
|
||||
{ \
|
||||
return _##name; \
|
||||
}
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* FUNCTIONS
|
||||
*******************************************************************************
|
||||
*/
|
||||
class ClassAssistant
|
||||
{
|
||||
public:
|
||||
template <typename T> static std::string demangle();
|
||||
|
||||
template <typename T> static std::string demangle(const T& object);
|
||||
|
||||
static std::string demangle(const std::type_info& ti);
|
||||
};
|
||||
|
||||
template <typename T> std::string ClassAssistant::demangle()
|
||||
{
|
||||
return demangle(typeid(T));
|
||||
}
|
||||
|
||||
template <typename T> inline std::string ClassAssistant::demangle(const T& object)
|
||||
{
|
||||
return demangle(typeid(object));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
26
util/Configurable.cpp
Normal file
26
util/Configurable.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Configurable.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
void Configurable::commit()
|
||||
{
|
||||
ParameterNames names;
|
||||
config().getChangedParameters(names);
|
||||
if (names.size())
|
||||
{
|
||||
onConfigChanged(names);
|
||||
for (auto& name : names)
|
||||
config().confirmParameterChanged(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
util/Configurable.h
Normal file
55
util/Configurable.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef E6D074E1_FEDB_4EFB_902B_95FF6BD2EB09
|
||||
#define E6D074E1_FEDB_4EFB_902B_95FF6BD2EB09
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Configuration.h"
|
||||
#include <unordered_set>
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* MACROS
|
||||
*******************************************************************************
|
||||
*/
|
||||
#define CONFIGURABLE_DECLARE_PARAMETER(name, type) \
|
||||
type get##name() \
|
||||
{ \
|
||||
return config().getParameter<type>(#name); \
|
||||
} \
|
||||
void set##name(const type value) \
|
||||
{ \
|
||||
config().setParameter(#name, value); \
|
||||
} \
|
||||
const std::string _##name = (#name);
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Configurable
|
||||
{
|
||||
public:
|
||||
using ParameterNames = Configuration::ParameterNames;
|
||||
|
||||
public:
|
||||
void commit();
|
||||
Configuration& config();
|
||||
|
||||
protected:
|
||||
virtual void onConfigChanged(ParameterNames& names) = 0;
|
||||
|
||||
private:
|
||||
Configuration _config;
|
||||
};
|
||||
|
||||
inline Configuration& Configurable::config()
|
||||
{
|
||||
return _config;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
33
util/Configuration.cpp
Normal file
33
util/Configuration.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Configuration.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
bool Configuration::ParameterNames::exists(std::string name) const
|
||||
{
|
||||
return find(name) != end();
|
||||
}
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Configuration::~Configuration()
|
||||
{
|
||||
}
|
||||
|
||||
void Configuration::copyTo(Configuration& other)
|
||||
{
|
||||
other._parameters = _parameters;
|
||||
}
|
||||
}
|
||||
140
util/Configuration.h
Normal file
140
util/Configuration.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#ifndef __CONFIG_CONFIGURATION_H__
|
||||
#define __CONFIG_CONFIGURATION_H__
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include "Poco/Any.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Format.h"
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Configuration
|
||||
{
|
||||
private:
|
||||
class Parameter
|
||||
{
|
||||
public:
|
||||
template <class T> T getValue()
|
||||
{
|
||||
return Poco::AnyCast<T>(_value);
|
||||
}
|
||||
|
||||
void setValue(const Poco::Any& value)
|
||||
{
|
||||
this->_value = value;
|
||||
}
|
||||
|
||||
void setChanged(bool changed)
|
||||
{
|
||||
this->_changed = changed;
|
||||
}
|
||||
|
||||
bool getChanged()
|
||||
{
|
||||
return _changed;
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return _value.empty();
|
||||
}
|
||||
|
||||
Poco::Any& value()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
private:
|
||||
Poco::Any _value;
|
||||
bool _changed;
|
||||
};
|
||||
|
||||
public:
|
||||
class ParameterNames: public std::unordered_set<std::string>
|
||||
{
|
||||
public:
|
||||
bool exists(std::string name) const;
|
||||
};
|
||||
|
||||
public:
|
||||
virtual ~Configuration();
|
||||
|
||||
template <class T> Configuration& setParameter(const std::string& name, const T& value)
|
||||
{
|
||||
Parameter& parameter = _parameters[name];
|
||||
if (parameter.empty() || parameter.getValue<T>() != value)
|
||||
{
|
||||
parameter.setChanged(true);
|
||||
parameter.setValue(value);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T> T getParameter(const std::string& name)
|
||||
{
|
||||
return findParameter(name).getValue<T>();
|
||||
}
|
||||
|
||||
bool isParameterChanged(const std::string& name)
|
||||
{
|
||||
return findParameter(name).getChanged();
|
||||
}
|
||||
|
||||
void confirmParameterChanged(const std::string& name)
|
||||
{
|
||||
findParameter(name).setChanged(false);
|
||||
}
|
||||
|
||||
void getChangedParameters(ParameterNames& names)
|
||||
{
|
||||
names.clear();
|
||||
for (auto& p : _parameters)
|
||||
{
|
||||
if (p.second.getChanged())
|
||||
names.insert(p.first);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
void copyTo(Configuration& other);
|
||||
|
||||
protected:
|
||||
void setName(std::string& name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
Parameter& findParameter(const std::string& name)
|
||||
{
|
||||
if (_parameters.find(name) == _parameters.end())
|
||||
throw Poco::NotFoundException(Poco::format("Can't find parameter: %s", name), -ENODATA);
|
||||
|
||||
return _parameters[name];
|
||||
}
|
||||
|
||||
private:
|
||||
using Parameters = std::map<std::string, Parameter>;
|
||||
|
||||
Parameters _parameters;
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
467
util/DateTimeUtils.h
Normal file
467
util/DateTimeUtils.h
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
#ifndef A283B06E_3ED5_4D78_A2B5_4B87495A80A6
|
||||
#define A283B06E_3ED5_4D78_A2B5_4B87495A80A6
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/DateTimeFormat.h"
|
||||
#include "Poco/DateTimeFormatter.h"
|
||||
#include "Poco/DateTimeParser.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/LocalDateTime.h"
|
||||
#include "Poco/Timespan.h"
|
||||
#include "Poco/Timestamp.h"
|
||||
namespace Util
|
||||
{
|
||||
class DateTimeUtils
|
||||
{
|
||||
public:
|
||||
static Poco::DateTime now()
|
||||
{
|
||||
return Poco::DateTime();
|
||||
}
|
||||
|
||||
static Poco::LocalDateTime localNow()
|
||||
{
|
||||
return Poco::LocalDateTime();
|
||||
}
|
||||
|
||||
static std::string nowStr(const std::string& formatStr = "%Y-%m-%d %H:%M:%S")
|
||||
{
|
||||
return format(Poco::DateTime(), formatStr);
|
||||
}
|
||||
|
||||
static std::string localNowStr(const std::string& formatStr = "%Y-%m-%d %H:%M:%S")
|
||||
{
|
||||
return Poco::DateTimeFormatter::format(Poco::LocalDateTime(), formatStr);
|
||||
}
|
||||
|
||||
static Poco::DateTime parse(const std::string& str, const std::string& formatStr = "")
|
||||
{
|
||||
auto dt = Poco::DateTime(1970, 1, 1);
|
||||
if (str.empty())
|
||||
{
|
||||
return dt;
|
||||
}
|
||||
int timeZoneDifferential = 0;
|
||||
if (!formatStr.empty())
|
||||
{
|
||||
if (Poco::DateTimeParser::tryParse(formatStr, str, dt, timeZoneDifferential))
|
||||
{
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Poco::DateTimeParser::tryParse(Poco::DateTimeFormat::ISO8601_FORMAT, str, dt, timeZoneDifferential) ||
|
||||
Poco::DateTimeParser::tryParse("%Y-%m-%d %H:%M:%S", str, dt, timeZoneDifferential) ||
|
||||
Poco::DateTimeParser::tryParse("%Y/%m/%d %H:%M:%S", str, dt, timeZoneDifferential) ||
|
||||
Poco::DateTimeParser::tryParse("%Y%m%d%H%M%S", str, dt, timeZoneDifferential))
|
||||
{
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
static std::string format(const Poco::DateTime& dt, const std::string& formatStr = "%Y-%m-%d %H:%M:%S")
|
||||
{
|
||||
return Poco::DateTimeFormatter::format(dt, formatStr);
|
||||
}
|
||||
|
||||
static std::string toISO8601(const Poco::DateTime& dt)
|
||||
{
|
||||
return Poco::DateTimeFormatter::format(dt, Poco::DateTimeFormat::ISO8601_FORMAT);
|
||||
}
|
||||
|
||||
static std::string toRFC1123(const Poco::DateTime& dt)
|
||||
{
|
||||
return Poco::DateTimeFormatter::format(dt, Poco::DateTimeFormat::RFC1123_FORMAT);
|
||||
}
|
||||
|
||||
static Poco::DateTime addDays(const Poco::DateTime& dt, int days)
|
||||
{
|
||||
return dt + Poco::Timespan(days, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static Poco::DateTime addHours(const Poco::DateTime& dt, int hours)
|
||||
{
|
||||
return dt + Poco::Timespan(0, hours, 0, 0, 0);
|
||||
}
|
||||
|
||||
static Poco::DateTime addMinutes(const Poco::DateTime& dt, int minutes)
|
||||
{
|
||||
return dt + Poco::Timespan(0, 0, minutes, 0, 0);
|
||||
}
|
||||
|
||||
static Poco::DateTime addSeconds(const Poco::DateTime& dt, int seconds)
|
||||
{
|
||||
return dt + Poco::Timespan(0, 0, 0, seconds, 0);
|
||||
}
|
||||
|
||||
static Poco::Timespan diff(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timestamp ts1 = dt1.timestamp();
|
||||
Poco::Timestamp ts2 = dt2.timestamp();
|
||||
|
||||
Poco::Timestamp::TimeDiff diffMicroseconds = 0;
|
||||
|
||||
if (ts1 > ts2)
|
||||
{
|
||||
diffMicroseconds = ts1 - ts2;
|
||||
}
|
||||
else
|
||||
{
|
||||
diffMicroseconds = ts2 - ts1;
|
||||
}
|
||||
|
||||
return Poco::Timespan(diffMicroseconds);
|
||||
}
|
||||
|
||||
static long diffSeconds(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timestamp ts1 = dt1.timestamp();
|
||||
Poco::Timestamp ts2 = dt2.timestamp();
|
||||
|
||||
Poco::Timestamp::TimeDiff diffMicroseconds = 0;
|
||||
|
||||
if (ts1 > ts2)
|
||||
{
|
||||
diffMicroseconds = ts1 - ts2;
|
||||
}
|
||||
else
|
||||
{
|
||||
diffMicroseconds = ts2 - ts1;
|
||||
}
|
||||
|
||||
Poco::Timespan ts(diffMicroseconds);
|
||||
return ts.totalSeconds();
|
||||
}
|
||||
|
||||
static long long diffMilliseconds(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timestamp ts1 = dt1.timestamp();
|
||||
Poco::Timestamp ts2 = dt2.timestamp();
|
||||
|
||||
Poco::Timestamp::TimeDiff diffMicroseconds = 0;
|
||||
|
||||
if (ts1 > ts2)
|
||||
{
|
||||
diffMicroseconds = ts1 - ts2;
|
||||
}
|
||||
else
|
||||
{
|
||||
diffMicroseconds = ts2 - ts1;
|
||||
}
|
||||
|
||||
return diffMicroseconds / 1000;
|
||||
}
|
||||
|
||||
static long long diffMicroseconds(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timestamp ts1 = dt1.timestamp();
|
||||
Poco::Timestamp ts2 = dt2.timestamp();
|
||||
|
||||
Poco::Timestamp::TimeDiff diffMicroseconds = 0;
|
||||
|
||||
if (ts1 > ts2)
|
||||
{
|
||||
diffMicroseconds = ts1 - ts2;
|
||||
}
|
||||
else
|
||||
{
|
||||
diffMicroseconds = ts2 - ts1;
|
||||
}
|
||||
|
||||
return diffMicroseconds;
|
||||
}
|
||||
|
||||
static void diffComponents(const Poco::DateTime& dt1, const Poco::DateTime& dt2, int& days, int& hours,
|
||||
int& minutes, int& seconds)
|
||||
{
|
||||
Poco::Timespan ts = diff(dt1, dt2);
|
||||
days = ts.days();
|
||||
hours = ts.hours();
|
||||
minutes = ts.minutes();
|
||||
seconds = ts.seconds();
|
||||
}
|
||||
|
||||
static Poco::Timespan calculateDifference(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timestamp::TimeVal us1 = dt1.timestamp().epochMicroseconds();
|
||||
Poco::Timestamp::TimeVal us2 = dt2.timestamp().epochMicroseconds();
|
||||
|
||||
Poco::Timestamp::TimeVal diff = 0;
|
||||
if (us1 > us2)
|
||||
{
|
||||
diff = us1 - us2;
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = us2 - us1;
|
||||
}
|
||||
|
||||
return Poco::Timespan(diff);
|
||||
}
|
||||
|
||||
static bool isBefore(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timestamp ts1 = dt1.timestamp();
|
||||
Poco::Timestamp ts2 = dt2.timestamp();
|
||||
return ts1 < ts2;
|
||||
}
|
||||
|
||||
static bool isAfter(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timestamp ts1 = dt1.timestamp();
|
||||
Poco::Timestamp ts2 = dt2.timestamp();
|
||||
return ts1 > ts2;
|
||||
}
|
||||
|
||||
static bool isEqual(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timestamp ts1 = dt1.timestamp();
|
||||
Poco::Timestamp ts2 = dt2.timestamp();
|
||||
return ts1 == ts2;
|
||||
}
|
||||
|
||||
static bool isLeapYear(int year)
|
||||
{
|
||||
return Poco::DateTime::isLeapYear(year);
|
||||
}
|
||||
|
||||
static int daysInMonth(int year, int month)
|
||||
{
|
||||
if (month < 1 || month > 12)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Poco::DateTime nextMonth;
|
||||
if (month == 12)
|
||||
{
|
||||
nextMonth = Poco::DateTime(year + 1, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextMonth = Poco::DateTime(year, month + 1, 1);
|
||||
}
|
||||
|
||||
Poco::DateTime lastDay = nextMonth - Poco::Timespan(1, 0, 0, 0, 0);
|
||||
return lastDay.day();
|
||||
}
|
||||
|
||||
static std::string getWeekdayName(int dayOfWeek)
|
||||
{
|
||||
static const std::string weekdays[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
|
||||
|
||||
if (dayOfWeek >= 0 && dayOfWeek <= 6)
|
||||
{
|
||||
return weekdays[dayOfWeek];
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
|
||||
static time_t getTimestamp()
|
||||
{
|
||||
Poco::Timestamp ts;
|
||||
return ts.epochTime();
|
||||
}
|
||||
|
||||
static long long getTimestampMs()
|
||||
{
|
||||
Poco::Timestamp ts;
|
||||
return ts.epochMicroseconds() / 1000;
|
||||
}
|
||||
|
||||
static long long getTimestampUs()
|
||||
{
|
||||
Poco::Timestamp ts;
|
||||
return ts.epochMicroseconds();
|
||||
}
|
||||
|
||||
static Poco::DateTime fromTimestamp(time_t timestamp)
|
||||
{
|
||||
Poco::Timestamp ts(static_cast<Poco::Timestamp::TimeVal>(timestamp) * 1000000);
|
||||
return Poco::DateTime(ts);
|
||||
}
|
||||
|
||||
static Poco::DateTime fromTimestampMs(long long timestampMs)
|
||||
{
|
||||
Poco::Timestamp ts(static_cast<Poco::Timestamp::TimeVal>(timestampMs) * 1000);
|
||||
return Poco::DateTime(ts);
|
||||
}
|
||||
|
||||
static Poco::DateTime fromTimestampUs(long long timestampUs)
|
||||
{
|
||||
Poco::Timestamp ts(static_cast<Poco::Timestamp::TimeVal>(timestampUs));
|
||||
return Poco::DateTime(ts);
|
||||
}
|
||||
|
||||
static Poco::Timestamp toTimestamp(const Poco::DateTime& dt)
|
||||
{
|
||||
return dt.timestamp();
|
||||
}
|
||||
|
||||
static Poco::DateTime toDateTime(const Poco::Timestamp& ts)
|
||||
{
|
||||
return Poco::DateTime(ts);
|
||||
}
|
||||
|
||||
static Poco::DateTime getStartOfDay(const Poco::DateTime& dt)
|
||||
{
|
||||
return Poco::DateTime(dt.year(), dt.month(), dt.day());
|
||||
}
|
||||
|
||||
static Poco::DateTime getEndOfDay(const Poco::DateTime& dt)
|
||||
{
|
||||
return Poco::DateTime(dt.year(), dt.month(), dt.day(), 23, 59, 59, 999999);
|
||||
}
|
||||
|
||||
static int getAge(const Poco::DateTime& birthDate)
|
||||
{
|
||||
Poco::DateTime now = DateTimeUtils::now();
|
||||
|
||||
int age = now.year() - birthDate.year();
|
||||
|
||||
if (now.month() < birthDate.month() || (now.month() == birthDate.month() && now.day() < birthDate.day()))
|
||||
{
|
||||
age--;
|
||||
}
|
||||
|
||||
return age;
|
||||
}
|
||||
|
||||
static bool isSameDay(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
return dt1.year() == dt2.year() && dt1.month() == dt2.month() && dt1.day() == dt2.day();
|
||||
}
|
||||
|
||||
static std::string formatTimespan(const Poco::Timespan& ts)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
if (ts.days() > 0)
|
||||
{
|
||||
result += std::to_string(ts.days()) + "天";
|
||||
}
|
||||
|
||||
if (ts.hours() > 0)
|
||||
{
|
||||
result += std::to_string(ts.hours()) + "小时";
|
||||
}
|
||||
|
||||
if (ts.minutes() > 0)
|
||||
{
|
||||
result += std::to_string(ts.minutes()) + "分";
|
||||
}
|
||||
|
||||
if (ts.seconds() > 0)
|
||||
{
|
||||
result += std::to_string(ts.seconds()) + "秒";
|
||||
}
|
||||
|
||||
if (result.empty())
|
||||
{
|
||||
result = "0秒";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string formatTimeDifference(const Poco::DateTime& dt1, const Poco::DateTime& dt2)
|
||||
{
|
||||
Poco::Timespan diff = calculateDifference(dt1, dt2);
|
||||
return formatTimespan(diff);
|
||||
}
|
||||
|
||||
static std::string formatTimespanWithMs(const Poco::Timespan& ts)
|
||||
{
|
||||
std::string result = formatTimespan(ts);
|
||||
|
||||
int milliseconds = ts.milliseconds();
|
||||
if (milliseconds > 0)
|
||||
{
|
||||
result += std::to_string(milliseconds) + "毫秒";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int getWeekOfYear(const Poco::DateTime& dt)
|
||||
{
|
||||
Poco::DateTime firstDay(dt.year(), 1, 1);
|
||||
|
||||
Poco::Timespan diff = dt - firstDay;
|
||||
int dayOfYear = diff.days() + 1;
|
||||
|
||||
int firstDayWeek = firstDay.dayOfWeek();
|
||||
int week = (dayOfYear + firstDayWeek - 1) / 7 + 1;
|
||||
|
||||
return week;
|
||||
}
|
||||
|
||||
static Poco::DateTime getFirstDayOfMonth(const Poco::DateTime& dt)
|
||||
{
|
||||
return Poco::DateTime(dt.year(), dt.month(), 1);
|
||||
}
|
||||
|
||||
static Poco::DateTime getLastDayOfMonth(const Poco::DateTime& dt)
|
||||
{
|
||||
int lastDay = daysInMonth(dt.year(), dt.month());
|
||||
return Poco::DateTime(dt.year(), dt.month(), lastDay);
|
||||
}
|
||||
|
||||
static Poco::DateTime getFirstDayOfWeek(const Poco::DateTime& dt)
|
||||
{
|
||||
int dayOfWeek = dt.dayOfWeek();
|
||||
int daysToMonday = (dayOfWeek == 0) ? 6 : (dayOfWeek - 1);
|
||||
return addDays(dt, -daysToMonday);
|
||||
}
|
||||
|
||||
static Poco::DateTime getLastDayOfWeek(const Poco::DateTime& dt)
|
||||
{
|
||||
int dayOfWeek = dt.dayOfWeek();
|
||||
int daysToSunday = (dayOfWeek == 0) ? 0 : (7 - dayOfWeek);
|
||||
return addDays(dt, daysToSunday);
|
||||
}
|
||||
|
||||
static long long getTime(const Poco::DateTime& dt)
|
||||
{
|
||||
Poco::Timestamp ts = dt.timestamp();
|
||||
return ts.epochMicroseconds() / 1000;
|
||||
}
|
||||
|
||||
static time_t getTimeSeconds(const Poco::DateTime& dt)
|
||||
{
|
||||
Poco::Timestamp ts = dt.timestamp();
|
||||
return ts.epochTime();
|
||||
}
|
||||
|
||||
static Poco::DateTime fromTime(long long milliseconds)
|
||||
{
|
||||
Poco::Timestamp ts(static_cast<Poco::Timestamp::TimeVal>(milliseconds) * 1000);
|
||||
return Poco::DateTime(ts);
|
||||
}
|
||||
|
||||
static Poco::DateTime fromTimeSeconds(time_t seconds)
|
||||
{
|
||||
Poco::Timestamp ts(static_cast<Poco::Timestamp::TimeVal>(seconds) * 1000000);
|
||||
return Poco::DateTime(ts);
|
||||
}
|
||||
|
||||
static long long currentTimeMillis()
|
||||
{
|
||||
Poco::Timestamp ts;
|
||||
return ts.epochMicroseconds() / 1000;
|
||||
}
|
||||
|
||||
static time_t currentTimeSeconds()
|
||||
{
|
||||
Poco::Timestamp ts;
|
||||
return ts.epochTime();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
104
util/Device.cpp
Normal file
104
util/Device.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Device.h"
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Format.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Device::Device(std::string path, Mode mode): _path(path), _mode(mode), _fd(-1)
|
||||
{
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void Device::open()
|
||||
{
|
||||
int flags;
|
||||
|
||||
switch (_mode)
|
||||
{
|
||||
default:
|
||||
case Mode::RD_ONLY:
|
||||
flags = O_RDONLY;
|
||||
break;
|
||||
|
||||
case Mode::WR_ONLY:
|
||||
flags = O_WRONLY;
|
||||
break;
|
||||
|
||||
case Mode::RDWR:
|
||||
flags = O_RDWR;
|
||||
break;
|
||||
}
|
||||
|
||||
_fd = ::open(_path.c_str(), flags);
|
||||
if (_fd < 0)
|
||||
throw Poco::InvalidAccessException(Poco::format("Access %s error: %d", _path, _fd), _fd);
|
||||
}
|
||||
|
||||
int Device::write(uint8_t* data, int size)
|
||||
{
|
||||
return ::write(_fd, data, size);
|
||||
}
|
||||
|
||||
int Device::read(uint8_t* buffer, int count)
|
||||
{
|
||||
return ::read(_fd, buffer, count);
|
||||
}
|
||||
|
||||
void Device::close()
|
||||
{
|
||||
if (_fd >= 0)
|
||||
::close(_fd);
|
||||
}
|
||||
|
||||
int Device::fcntl(int cmd)
|
||||
{
|
||||
return ::fcntl(_fd, cmd);
|
||||
}
|
||||
|
||||
int Device::fcntl(int cmd, long arg)
|
||||
{
|
||||
return ::fcntl(_fd, cmd, arg);
|
||||
}
|
||||
|
||||
int Device::fcntl(int cmd, long arg, void* lock)
|
||||
{
|
||||
return ::fcntl(_fd, cmd, arg, lock);
|
||||
}
|
||||
|
||||
int Device::poll(unsigned int& revents, int timeout)
|
||||
{
|
||||
struct pollfd pollfd;
|
||||
int rc;
|
||||
|
||||
pollfd.fd = _fd;
|
||||
pollfd.events = POLLIN;
|
||||
|
||||
rc = ::poll(&pollfd, 1, timeout);
|
||||
if (rc > 0)
|
||||
revents = pollfd.revents;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
47
util/Device.h
Normal file
47
util/Device.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef C5ADE9DB_6B16_4E4F_8C58_0101E9832DE0
|
||||
#define C5ADE9DB_6B16_4E4F_8C58_0101E9832DE0
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <string>
|
||||
#include <poll.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
RD_ONLY,
|
||||
WR_ONLY,
|
||||
RDWR,
|
||||
};
|
||||
|
||||
public:
|
||||
Device(std::string path, Mode mode = Mode::RD_ONLY);
|
||||
~Device();
|
||||
|
||||
virtual void open();
|
||||
virtual int write(uint8_t* data, int size);
|
||||
virtual int read(uint8_t* buffer, int count);
|
||||
virtual void close();
|
||||
virtual int fcntl(int cmd);
|
||||
virtual int fcntl(int cmd, long arg);
|
||||
virtual int fcntl(int cmd, long arg, void* lock);
|
||||
virtual int poll(unsigned int& revents, int timeout);
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
Mode _mode;
|
||||
int _fd;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
15
util/FactoryManager.cpp
Normal file
15
util/FactoryManager.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "FactoryManager.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
}
|
||||
79
util/FactoryManager.h
Normal file
79
util/FactoryManager.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef BE13A370_B199_43EC_A4E6_E2D4FD197D63
|
||||
#define BE13A370_B199_43EC_A4E6_E2D4FD197D63
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "ClassAssistant.h"
|
||||
#include <map>
|
||||
#include <Poco/SharedPtr.h>
|
||||
#include <Poco/Format.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
template <class T> class SimpleSelector
|
||||
{
|
||||
public:
|
||||
static T select(T val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class TKey, class TSelector, class... TArgs> class FactoryManager
|
||||
{
|
||||
private:
|
||||
class IFactory
|
||||
{
|
||||
public:
|
||||
using Ptr = Poco::SharedPtr<IFactory>;
|
||||
virtual ~IFactory()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual T* create(TArgs... args) = 0;
|
||||
};
|
||||
|
||||
template <class C> class Factory: public IFactory
|
||||
{
|
||||
public:
|
||||
C* create(TArgs... args) override
|
||||
{
|
||||
return new C(args...);
|
||||
}
|
||||
};
|
||||
|
||||
using Factories = std::map<TKey, typename IFactory::Ptr>;
|
||||
|
||||
public:
|
||||
static T* create(TArgs... args)
|
||||
{
|
||||
TKey key = TSelector::select(args...);
|
||||
if (_factories.find(key) == _factories.end())
|
||||
throw Poco::NotFoundException(
|
||||
Poco::format("FactoryManager: Factory '%s' does not exists.", Util::ClassAssistant::demangle<T>()),
|
||||
-EINVAL);
|
||||
|
||||
return _factories[key]->create(args...);
|
||||
}
|
||||
|
||||
template <class C> static void registerClass(TKey key)
|
||||
{
|
||||
_factories[key] = new Factory<C>();
|
||||
}
|
||||
|
||||
private:
|
||||
static Factories _factories;
|
||||
};
|
||||
|
||||
template <class T, class TKey, class TSelect, class... TArgs>
|
||||
typename FactoryManager<T, TKey, TSelect, TArgs...>::Factories FactoryManager<T, TKey, TSelect, TArgs...>::_factories;
|
||||
}
|
||||
#endif
|
||||
71
util/FileUtil.h
Normal file
71
util/FileUtil.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef B2D3FCFE_BBC5_4EFD_9AA7_7EEB5C58E2AE
|
||||
#define B2D3FCFE_BBC5_4EFD_9AA7_7EEB5C58E2AE
|
||||
#include <Poco/File.h>
|
||||
#include <Poco/FileStream.h>
|
||||
#include <Poco/StreamCopier.h>
|
||||
#include <string>
|
||||
#include "Logger.h"
|
||||
namespace Util
|
||||
{
|
||||
class FileUtil
|
||||
{
|
||||
private:
|
||||
public:
|
||||
static std::string readFile(const std::string& fileFullName)
|
||||
{
|
||||
std::string content;
|
||||
Poco::File file(fileFullName);
|
||||
if (file.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::FileInputStream fis(fileFullName);
|
||||
Poco::StreamCopier::copyToString(fis, content);
|
||||
fis.close();
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
logger().error("readFile read error: %s", std::string(e.what()));
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
static bool writeFile(const std::string& fileFullName, const std::string& content)
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::FileOutputStream fos(fileFullName, std::ios::trunc);
|
||||
fos << content;
|
||||
fos.close();
|
||||
|
||||
int fd = ::open(fileFullName.c_str(), O_RDWR);
|
||||
if (fd != -1)
|
||||
{
|
||||
::fsync(fd);
|
||||
::close(fd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
logger().error("writeFile file error: %s", std::string(e.what()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void delFile(const std::string& fileFullName)
|
||||
{
|
||||
if (!fileFullName.empty())
|
||||
{
|
||||
if (Poco::File(fileFullName).exists())
|
||||
{
|
||||
Poco::File(fileFullName).remove();
|
||||
logger().debug("删除文件: %s", fileFullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
125
util/FrpUtil.h
Normal file
125
util/FrpUtil.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#ifndef FRP_UTIL_H
|
||||
#define FRP_UTIL_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include "Application.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "util/SystemInfo.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
class FrpUtil
|
||||
{
|
||||
private:
|
||||
public:
|
||||
static constexpr const char* frpcConfigPathName = "/customer/frp/frpc.toml";
|
||||
static constexpr const char* frpcPathName = "/customer/frp/frpc";
|
||||
|
||||
public:
|
||||
static int getFrpcPid()
|
||||
{
|
||||
return Util::SystemInfo::getProcessPID(frpcPathName);
|
||||
}
|
||||
|
||||
static void startFrpc(std::string serialNum, Poco::JSON::Object::Ptr service_ports, bool forceRestart)
|
||||
{
|
||||
int http_local_port = service_ports->get("http_port");
|
||||
int http_remote_port = service_ports->get("http_port_nat_port");
|
||||
int http_api_local_port = service_ports->get("http_api_port");
|
||||
int http_api_remote_port = service_ports->get("http_api_port_nat_port");
|
||||
int rtmp_local_port = service_ports->get("rtmp_port");
|
||||
int rtmp_remote_port = service_ports->get("rtmp_port_nat_port");
|
||||
int rtsp_local_port = service_ports->get("rtsp_port");
|
||||
int rtsp_remote_port = service_ports->get("rtsp_port_nat_port");
|
||||
int srt_local_port = service_ports->get("srt_port");
|
||||
int srt_remote_port = service_ports->get("srt_port_nat_port");
|
||||
int nat_frp_enable = service_ports->get("nat_frp_enable");
|
||||
try
|
||||
{
|
||||
int pid = getFrpcPid();
|
||||
if (nat_frp_enable == 0)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
stopFrpc(pid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
if (forceRestart)
|
||||
{
|
||||
stopFrpc(pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t child = fork();
|
||||
if (child < 0)
|
||||
{
|
||||
logger().information("frpc fork failed");
|
||||
return;
|
||||
}
|
||||
if (child > 0)
|
||||
{
|
||||
logger().information("frpc daemon starting...");
|
||||
return;
|
||||
}
|
||||
|
||||
setsid();
|
||||
|
||||
for (int i = 3; i < 1024; ++i)
|
||||
{
|
||||
close(i);
|
||||
}
|
||||
|
||||
int fd = open("/dev/null", O_RDWR);
|
||||
if (fd >= 0)
|
||||
{
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
setenv("FRP_SERIAL_NUM", serialNum.c_str(), 1);
|
||||
setenv("FRP_HTTP_LOCAL_PORT", std::to_string(http_local_port).c_str(), 1);
|
||||
setenv("FRP_HTTP_REMOTE_PORT", std::to_string(http_remote_port).c_str(), 1);
|
||||
setenv("FRP_HTTP_API_LOCAL_PORT", std::to_string(http_api_local_port).c_str(), 1);
|
||||
setenv("FRP_HTTP_API_REMOTE_PORT", std::to_string(http_api_remote_port).c_str(), 1);
|
||||
setenv("FRP_RTMP_LOCAL_PORT", std::to_string(rtmp_local_port).c_str(), 1);
|
||||
setenv("FRP_RTMP_REMOTE_PORT", std::to_string(rtmp_remote_port).c_str(), 1);
|
||||
setenv("FRP_RTSP_LOCAL_PORT", std::to_string(rtsp_local_port).c_str(), 1);
|
||||
setenv("FRP_RTSP_REMOTE_PORT", std::to_string(rtsp_remote_port).c_str(), 1);
|
||||
setenv("FRP_SRT_LOCAL_PORT", std::to_string(srt_local_port).c_str(), 1);
|
||||
setenv("FRP_SRT_REMOTE_PORT", std::to_string(srt_remote_port).c_str(), 1);
|
||||
|
||||
execlp(frpcPathName, frpcPathName, "-c", frpcConfigPathName, (char*)NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
logger().information("doStartFrpc,error: %s", std::string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
static void stopFrpc(int pid)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
Util::SystemInfo::executeCommand("kill -9 " + std::to_string(pid));
|
||||
logger().information("frpc stoped,pid=%d........", pid);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
386
util/HTTPClient.h
Normal file
386
util/HTTPClient.h
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
#ifndef C99FBF1C_5805_40A3_963F_5BC1CA998C5C
|
||||
#define C99FBF1C_5805_40A3_963F_5BC1CA998C5C
|
||||
|
||||
#include <Poco/Exception.h>
|
||||
#include <Poco/Net/HTMLForm.h>
|
||||
#include <Poco/Net/HTTPClientSession.h>
|
||||
#include <Poco/Net/HTTPRequest.h>
|
||||
#include <Poco/Net/HTTPResponse.h>
|
||||
|
||||
#include <Poco/Net/MessageHeader.h>
|
||||
#include <Poco/StreamCopier.h>
|
||||
#include <Poco/URI.h>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Logger.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
class HTTPClient
|
||||
{
|
||||
public:
|
||||
struct HttpResponse
|
||||
{
|
||||
int statusCode;
|
||||
std::string statusMessage;
|
||||
std::string content;
|
||||
std::string contentType;
|
||||
std::map<std::string, std::string> headers;
|
||||
bool success;
|
||||
|
||||
HttpResponse(): statusCode(0), success(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ProxyConfig
|
||||
{
|
||||
std::string host;
|
||||
int port;
|
||||
bool enabled;
|
||||
|
||||
ProxyConfig(): port(0), enabled(false)
|
||||
{
|
||||
}
|
||||
ProxyConfig(const std::string& h, int p): host(h), port(p), enabled(true)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct RequestConfig
|
||||
{
|
||||
int timeout;
|
||||
std::string userAgent;
|
||||
std::map<std::string, std::string> headers;
|
||||
bool followRedirects;
|
||||
ProxyConfig proxy;
|
||||
|
||||
RequestConfig(): timeout(30), userAgent("HTTPClient/1.0"), followRedirects(true)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static HttpResponse get(const std::string& url, const RequestConfig& config = RequestConfig())
|
||||
{
|
||||
return executeRequest("GET", url, "", config);
|
||||
}
|
||||
|
||||
static bool downloadFile(const std::string& url, const std::string& localFilePath,
|
||||
const RequestConfig& config = RequestConfig())
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::URI uri(url);
|
||||
auto session = createSession(uri, config.proxy);
|
||||
session->setTimeout(Poco::Timespan(config.timeout, 0));
|
||||
|
||||
std::string path = getPathAndQuery(uri);
|
||||
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path);
|
||||
setupRequest(request, config);
|
||||
|
||||
session->sendRequest(request);
|
||||
|
||||
Poco::Net::HTTPResponse response;
|
||||
std::istream& responseStream = session->receiveResponse(response);
|
||||
|
||||
if (response.getStatus() != Poco::Net::HTTPResponse::HTTP_OK)
|
||||
{
|
||||
std::cerr << "Download failed: HTTP " << response.getStatus() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream file(localFilePath, std::ios::binary);
|
||||
if (!file.is_open())
|
||||
{
|
||||
std::cerr << "Cannot open file: " << localFilePath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
Poco::StreamCopier::copyStream(responseStream, file);
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
std::cerr << "Download exception: " << e.displayText() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static HttpResponse postJson(const std::string& url, const std::string& jsonData,
|
||||
const RequestConfig& config = RequestConfig())
|
||||
{
|
||||
RequestConfig jsonConfig = config;
|
||||
jsonConfig.headers["Content-Type"] = "application/json";
|
||||
return executeRequest("POST", url, jsonData, jsonConfig);
|
||||
}
|
||||
|
||||
static HttpResponse postForm(const std::string& url, const std::map<std::string, std::string>& formData,
|
||||
const RequestConfig& config = RequestConfig())
|
||||
{
|
||||
std::string formString = buildFormData(formData);
|
||||
|
||||
RequestConfig formConfig = config;
|
||||
formConfig.headers["Content-Type"] = "application/x-www-form-urlencoded";
|
||||
|
||||
return executeRequest("POST", url, formString, formConfig);
|
||||
}
|
||||
|
||||
static HttpResponse postFormWithPoco(const std::string& url, const std::map<std::string, std::string>& formData,
|
||||
const RequestConfig& config = RequestConfig())
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::URI uri(url);
|
||||
auto session = createSession(uri, config.proxy);
|
||||
session->setTimeout(Poco::Timespan(config.timeout, 0));
|
||||
|
||||
std::string path = getPathAndQuery(uri);
|
||||
|
||||
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, path);
|
||||
setupRequest(request, config);
|
||||
request.setContentType("application/x-www-form-urlencoded");
|
||||
|
||||
Poco::Net::HTMLForm form;
|
||||
for (const auto& field : formData)
|
||||
{
|
||||
form.set(field.first, field.second);
|
||||
}
|
||||
|
||||
std::ostream& requestStream = session->sendRequest(request);
|
||||
form.write(requestStream);
|
||||
|
||||
Poco::Net::HTTPResponse response;
|
||||
std::istream& responseStream = session->receiveResponse(response);
|
||||
|
||||
HttpResponse result;
|
||||
result.statusCode = response.getStatus();
|
||||
result.statusMessage = response.getReason();
|
||||
result.contentType = response.getContentType();
|
||||
result.success = (result.statusCode == Poco::Net::HTTPResponse::HTTP_OK);
|
||||
|
||||
Poco::Net::NameValueCollection::ConstIterator it = response.begin();
|
||||
while (it != response.end())
|
||||
{
|
||||
result.headers[it->first] = it->second;
|
||||
++it;
|
||||
}
|
||||
|
||||
Poco::StreamCopier::copyToString(responseStream, result.content);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
std::cerr << "POST form exception: " << e.displayText() << std::endl;
|
||||
HttpResponse result;
|
||||
result.success = false;
|
||||
result.statusMessage = e.displayText();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static HttpResponse post(const std::string& url, const std::string& data,
|
||||
const std::string& contentType = "text/plain",
|
||||
const RequestConfig& config = RequestConfig())
|
||||
{
|
||||
RequestConfig postConfig = config;
|
||||
postConfig.headers["Content-Type"] = contentType;
|
||||
return executeRequest("POST", url, data, postConfig);
|
||||
}
|
||||
|
||||
static HttpResponse put(const std::string& url, const std::string& data = "",
|
||||
const RequestConfig& config = RequestConfig())
|
||||
{
|
||||
return executeRequest("PUT", url, data, config);
|
||||
}
|
||||
|
||||
static HttpResponse deleteRequest(const std::string& url, const RequestConfig& config = RequestConfig())
|
||||
{
|
||||
return executeRequest("DELETE", url, "", config);
|
||||
}
|
||||
|
||||
static RequestConfig createProxyConfig(const std::string& proxyHost, int proxyPort,
|
||||
const RequestConfig& baseConfig = RequestConfig())
|
||||
{
|
||||
RequestConfig config = baseConfig;
|
||||
config.proxy = ProxyConfig(proxyHost, proxyPort);
|
||||
return config;
|
||||
}
|
||||
|
||||
static HttpResponse executeRequest(const std::string& method, const std::string& url, const std::string& data,
|
||||
const RequestConfig& config)
|
||||
{
|
||||
HttpResponse result;
|
||||
|
||||
try
|
||||
{
|
||||
Poco::URI uri(url);
|
||||
auto session = createSession(uri, config.proxy);
|
||||
session->setTimeout(Poco::Timespan(config.timeout, 0));
|
||||
|
||||
std::string path = getPathAndQuery(uri);
|
||||
Poco::Net::HTTPRequest request(method, path);
|
||||
setupRequest(request, config);
|
||||
|
||||
if (!data.empty())
|
||||
{
|
||||
request.setContentLength(data.length());
|
||||
std::ostream& requestStream = session->sendRequest(request);
|
||||
requestStream << data;
|
||||
}
|
||||
else
|
||||
{
|
||||
session->sendRequest(request);
|
||||
}
|
||||
|
||||
Poco::Net::HTTPResponse response;
|
||||
std::istream& responseStream = session->receiveResponse(response);
|
||||
|
||||
result.statusCode = response.getStatus();
|
||||
result.statusMessage = response.getReason();
|
||||
result.contentType = response.getContentType();
|
||||
result.success = (result.statusCode == Poco::Net::HTTPResponse::HTTP_OK);
|
||||
|
||||
Poco::Net::NameValueCollection::ConstIterator it = response.begin();
|
||||
while (it != response.end())
|
||||
{
|
||||
result.headers[it->first] = it->second;
|
||||
++it;
|
||||
}
|
||||
|
||||
Poco::StreamCopier::copyToString(responseStream, result.content);
|
||||
|
||||
if (config.followRedirects && (result.statusCode == Poco::Net::HTTPResponse::HTTP_MOVED_PERMANENTLY ||
|
||||
result.statusCode == Poco::Net::HTTPResponse::HTTP_FOUND ||
|
||||
result.statusCode == Poco::Net::HTTPResponse::HTTP_SEE_OTHER))
|
||||
{
|
||||
auto locationIt = result.headers.find("Location");
|
||||
if (locationIt != result.headers.end())
|
||||
{
|
||||
std::cout << "Redirecting to: " << locationIt->second << std::endl;
|
||||
return executeRequest(method, locationIt->second, data, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Poco::TimeoutException& e)
|
||||
{
|
||||
std::cerr << "Request timeout: " << e.displayText() << std::endl;
|
||||
result.success = false;
|
||||
result.statusMessage = "Timeout";
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
std::cerr << "HTTP exception: " << e.displayText() << std::endl;
|
||||
result.success = false;
|
||||
result.statusMessage = e.displayText();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "Standard exception: " << e.what() << std::endl;
|
||||
result.success = false;
|
||||
result.statusMessage = e.what();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string urlEncode(const std::string& value)
|
||||
{
|
||||
std::ostringstream escaped;
|
||||
escaped.fill('0');
|
||||
escaped << std::hex;
|
||||
|
||||
for (char c : value)
|
||||
{
|
||||
if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
|
||||
{
|
||||
escaped << c;
|
||||
}
|
||||
else
|
||||
{
|
||||
escaped << '%' << std::setw(2) << int(static_cast<unsigned char>(c));
|
||||
}
|
||||
}
|
||||
|
||||
return escaped.str();
|
||||
}
|
||||
|
||||
static std::string buildFormData(const std::map<std::string, std::string>& formData)
|
||||
{
|
||||
std::ostringstream formStream;
|
||||
bool first = true;
|
||||
|
||||
for (const auto& field : formData)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
formStream << "&";
|
||||
}
|
||||
formStream << urlEncode(field.first) << "=" << urlEncode(field.second);
|
||||
first = false;
|
||||
}
|
||||
|
||||
return formStream.str();
|
||||
}
|
||||
|
||||
static std::unique_ptr<Poco::Net::HTTPClientSession> createSession(const Poco::URI& uri, const ProxyConfig& proxy)
|
||||
{
|
||||
std::unique_ptr<Poco::Net::HTTPClientSession> session;
|
||||
logger().debug("HTTPClient url: %s", uri.toString());
|
||||
if (proxy.enabled)
|
||||
{
|
||||
session = std::make_unique<Poco::Net::HTTPClientSession>(proxy.host, proxy.port);
|
||||
session->setProxy(uri.getHost(), uri.getPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (uri.getScheme() == "https")
|
||||
{
|
||||
logger().warning("HTTPClient 暂时不支持https,自动调整为使用http连接: %s", uri.toString());
|
||||
|
||||
session = std::make_unique<Poco::Net::HTTPClientSession>(uri.getHost(), uri.getPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
session = std::make_unique<Poco::Net::HTTPClientSession>(uri.getHost(), uri.getPort());
|
||||
}
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
static void setupRequest(Poco::Net::HTTPRequest& request, const RequestConfig& config)
|
||||
{
|
||||
request.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
request.set("User-Agent", config.userAgent);
|
||||
request.set("Accept", "*/*");
|
||||
request.set("Connection", "close");
|
||||
|
||||
for (const auto& header : config.headers)
|
||||
{
|
||||
request.set(header.first, header.second);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getPathAndQuery(const Poco::URI& uri)
|
||||
{
|
||||
std::string path = uri.getPathAndQuery();
|
||||
if (path.empty())
|
||||
{
|
||||
path = "/";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
0
util/HandlesManager.cpp
Normal file
0
util/HandlesManager.cpp
Normal file
67
util/HandlesManager.h
Normal file
67
util/HandlesManager.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef F0270054_CDC4_4A91_B09F_73A4C75D9356
|
||||
#define F0270054_CDC4_4A91_B09F_73A4C75D9356
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/Mutex.h>
|
||||
#include <set>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
template <typename T> class HandlesManager
|
||||
{
|
||||
public:
|
||||
using HandleCollection = std::set<T>;
|
||||
|
||||
public:
|
||||
HandlesManager(unsigned count): HandlesManager(0, count)
|
||||
{
|
||||
}
|
||||
|
||||
HandlesManager(unsigned begin, unsigned count)
|
||||
{
|
||||
for (T h = begin; h < (begin + count); h++)
|
||||
_freeHandles.insert(h);
|
||||
}
|
||||
|
||||
HandlesManager(HandleCollection& c)
|
||||
{
|
||||
_freeHandles.insert(c);
|
||||
}
|
||||
|
||||
T allocHandle()
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_lock);
|
||||
|
||||
if (_freeHandles.size() == 0)
|
||||
throw Poco::NotFoundException("Collection is empty", -ENODATA);
|
||||
|
||||
T h = *_freeHandles.begin();
|
||||
_freeHandles.erase(h);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
void freeHandle(T handle)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_lock);
|
||||
|
||||
if (_freeHandles.count(handle) != 0)
|
||||
throw Poco::NotFoundException("Double free", -EINVAL);
|
||||
|
||||
_freeHandles.insert(handle);
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<T> _freeHandles;
|
||||
Poco::FastMutex _lock;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
29
util/HexBinaryCodec.cpp
Executable file
29
util/HexBinaryCodec.cpp
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "HexBinaryCodec.h"
|
||||
#include <sstream>
|
||||
#include <Poco/HexBinaryEncoder.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
std::string HexBinaryCodec::encode(const void* data, unsigned size, bool uppercase)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
Poco::HexBinaryEncoder encoder(ostr);
|
||||
encoder.rdbuf()->setUppercase(uppercase);
|
||||
uint8_t* pBytes = (uint8_t*)data;
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
encoder << pBytes[i];
|
||||
encoder.close();
|
||||
|
||||
return ostr.str();
|
||||
}
|
||||
}
|
||||
23
util/HexBinaryCodec.h
Executable file
23
util/HexBinaryCodec.h
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef E955D6BE_6497_479F_8D49_2A73C17E05E9
|
||||
#define E955D6BE_6497_479F_8D49_2A73C17E05E9
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <string>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class HexBinaryCodec
|
||||
{
|
||||
public:
|
||||
static std::string encode(const void* data, unsigned size, bool uppercase = true);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
257
util/JsonUtil.h
Normal file
257
util/JsonUtil.h
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
#ifndef JSONUTIL_H
|
||||
#define JSONUTIL_H
|
||||
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "util/xpack/json.h"
|
||||
|
||||
#include <Poco/JSON/Array.h>
|
||||
#include <Poco/JSON/Object.h>
|
||||
#include <Poco/JSON/Parser.h>
|
||||
namespace Util
|
||||
{
|
||||
class JsonUtil
|
||||
{
|
||||
private:
|
||||
public:
|
||||
template <class T> static std::string encode(T t)
|
||||
{
|
||||
return xpack::json::encode(t);
|
||||
}
|
||||
|
||||
template <typename T> static T decode(std::string jsonStr)
|
||||
{
|
||||
T t;
|
||||
xpack::json::decode(jsonStr, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
static std::string jsonToString(const Poco::JSON::Object::Ptr& jsonObject)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
Poco::JSON::Stringifier::stringify(jsonObject, oss);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static Poco::JSON::Object::Ptr stringToJson(const std::string& jsonString)
|
||||
{
|
||||
Poco::JSON::Parser parser;
|
||||
Poco::Dynamic::Var result = parser.parse(jsonString);
|
||||
return result.extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
|
||||
static Poco::JSON::Array::Ptr stringToJsonArray(const std::string& jsonArrayString)
|
||||
{
|
||||
Poco::JSON::Parser parser;
|
||||
Poco::Dynamic::Var result = parser.parse(jsonArrayString);
|
||||
return result.extract<Poco::JSON::Array::Ptr>();
|
||||
}
|
||||
|
||||
static Poco::Dynamic::Var getNestedValue(Poco::JSON::Object::Ptr json, const std::string& path)
|
||||
{
|
||||
if (path.empty())
|
||||
return json;
|
||||
|
||||
std::regex arrayRegex(R"((\w+)((?:\[\d+\])+))");
|
||||
std::istringstream pathStream(path);
|
||||
std::string segment;
|
||||
Poco::Dynamic::Var currentVar = json;
|
||||
|
||||
while (std::getline(pathStream, segment, '.'))
|
||||
{
|
||||
std::smatch match;
|
||||
|
||||
if (std::regex_match(segment, match, arrayRegex))
|
||||
{
|
||||
std::string arrayKey = match[1];
|
||||
std::string indicesStr = match[2];
|
||||
|
||||
std::vector<std::size_t> indices;
|
||||
std::regex indexRegex(R"(\[(\d+)\])");
|
||||
std::sregex_iterator it(indicesStr.begin(), indicesStr.end(), indexRegex);
|
||||
std::sregex_iterator end;
|
||||
|
||||
while (it != end)
|
||||
{
|
||||
indices.push_back(static_cast<std::size_t>(std::stoi((*it)[1])));
|
||||
++it;
|
||||
}
|
||||
|
||||
Poco::JSON::Object::Ptr obj = currentVar.extract<Poco::JSON::Object::Ptr>();
|
||||
if (!obj->has(arrayKey))
|
||||
{
|
||||
throw std::runtime_error("getNestedValue Key not found: " + arrayKey);
|
||||
}
|
||||
|
||||
Poco::JSON::Array::Ptr array = obj->getArray(arrayKey);
|
||||
if (!array)
|
||||
{
|
||||
throw std::runtime_error("getNestedValue Expected an array at key: " + arrayKey);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < indices.size(); i++)
|
||||
{
|
||||
std::size_t index = indices[i];
|
||||
|
||||
if (index >= array->size())
|
||||
{
|
||||
throw std::out_of_range("getNestedValue Array index out of bounds: " + std::to_string(index));
|
||||
}
|
||||
|
||||
currentVar = array->get(index);
|
||||
|
||||
if (i < indices.size() - 1)
|
||||
{
|
||||
array = currentVar.extract<Poco::JSON::Array::Ptr>();
|
||||
if (!array)
|
||||
{
|
||||
throw std::runtime_error("getNestedValue Expected an array at index: " +
|
||||
std::to_string(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Poco::JSON::Object::Ptr obj = currentVar.extract<Poco::JSON::Object::Ptr>();
|
||||
if (!obj->has(segment))
|
||||
{
|
||||
throw std::runtime_error("getNestedValue Key not found: " + segment);
|
||||
}
|
||||
currentVar = obj->get(segment);
|
||||
}
|
||||
}
|
||||
return currentVar;
|
||||
}
|
||||
|
||||
static Poco::JSON::Object::Ptr getNestedValue(Poco::JSON::Object::Ptr json, const std::vector<std::string>& paths)
|
||||
{
|
||||
Poco::JSON::Object::Ptr results = new Poco::JSON::Object();
|
||||
for (const auto& path : paths)
|
||||
{
|
||||
results->set(path, getNestedValue(json, path));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
static void setNestedValue(Poco::JSON::Object::Ptr jsonObject, const std::string& path,
|
||||
const Poco::Dynamic::Var& value)
|
||||
{
|
||||
if (!jsonObject)
|
||||
{
|
||||
throw std::invalid_argument("setNestedValue JSON object is null.");
|
||||
}
|
||||
|
||||
std::regex arrayRegex(R"((\w+)((?:\[\d+\])+))");
|
||||
std::istringstream pathStream(path);
|
||||
std::string segment;
|
||||
Poco::JSON::Object::Ptr currentObject = jsonObject;
|
||||
|
||||
while (std::getline(pathStream, segment, '.'))
|
||||
{
|
||||
std::smatch match;
|
||||
|
||||
if (std::regex_match(segment, match, arrayRegex))
|
||||
{
|
||||
std::string arrayKey = match[1];
|
||||
std::string indicesStr = match[2];
|
||||
|
||||
std::vector<std::size_t> indices;
|
||||
std::regex indexRegex(R"(\[(\d+)\])");
|
||||
std::sregex_iterator it(indicesStr.begin(), indicesStr.end(), indexRegex);
|
||||
std::sregex_iterator end;
|
||||
|
||||
while (it != end)
|
||||
{
|
||||
indices.push_back(static_cast<std::size_t>(std::stoi((*it)[1])));
|
||||
++it;
|
||||
}
|
||||
|
||||
Poco::JSON::Array::Ptr array;
|
||||
if (!currentObject->has(arrayKey))
|
||||
{
|
||||
array = new Poco::JSON::Array();
|
||||
currentObject->set(arrayKey, array);
|
||||
}
|
||||
else
|
||||
{
|
||||
array = currentObject->getArray(arrayKey);
|
||||
if (!array)
|
||||
{
|
||||
throw std::runtime_error("setNestedValue Expected an array at key: " + arrayKey);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < indices.size() - 1; i++)
|
||||
{
|
||||
while (array->size() <= indices[i])
|
||||
{
|
||||
Poco::JSON::Array::Ptr nestedArray = new Poco::JSON::Array();
|
||||
array->add(nestedArray);
|
||||
}
|
||||
|
||||
Poco::JSON::Array::Ptr nextArray = array->getArray(indices[i]);
|
||||
if (!nextArray)
|
||||
{
|
||||
throw std::runtime_error("setNestedValue Expected an array at index: " +
|
||||
std::to_string(indices[i]));
|
||||
}
|
||||
array = nextArray;
|
||||
}
|
||||
|
||||
std::size_t lastIndex = indices.back();
|
||||
while (array->size() <= lastIndex)
|
||||
{
|
||||
Poco::JSON::Object::Ptr nestedObject = new Poco::JSON::Object();
|
||||
array->add(nestedObject);
|
||||
}
|
||||
|
||||
if (pathStream.peek() == EOF)
|
||||
{
|
||||
array->set(lastIndex, value);
|
||||
return;
|
||||
}
|
||||
|
||||
currentObject = array->getObject(lastIndex);
|
||||
if (!currentObject)
|
||||
{
|
||||
throw std::runtime_error("setNestedValue Expected an object at index: " +
|
||||
std::to_string(lastIndex));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pathStream.peek() == EOF)
|
||||
{
|
||||
currentObject->set(segment, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentObject->has(segment))
|
||||
{
|
||||
Poco::JSON::Object::Ptr nestedObject = new Poco::JSON::Object();
|
||||
currentObject->set(segment, nestedObject);
|
||||
}
|
||||
|
||||
currentObject = currentObject->getObject(segment);
|
||||
if (!currentObject)
|
||||
{
|
||||
throw std::runtime_error("setNestedValue Expected an object at key: " + segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setNestedValue(Poco::JSON::Object::Ptr jsonObject,
|
||||
const std::map<std::string, Poco::Dynamic::Var>& pathValues)
|
||||
{
|
||||
for (const auto& kv : pathValues)
|
||||
{
|
||||
setNestedValue(jsonObject, kv.first, kv.second);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
25
util/Math.cpp
Normal file
25
util/Math.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Math.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
unsigned Math::alignup(unsigned num, unsigned align)
|
||||
{
|
||||
return (((num) + (align)-1) & ~((align)-1));
|
||||
}
|
||||
|
||||
unsigned Math::aligndown(unsigned num, unsigned align)
|
||||
{
|
||||
return ((num) & ~((align)-1));
|
||||
}
|
||||
|
||||
}
|
||||
37
util/Math.h
Normal file
37
util/Math.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef D6937363_A08A_40BF_B387_36E8AC570ECF
|
||||
#define D6937363_A08A_40BF_B387_36E8AC570ECF
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Math
|
||||
{
|
||||
public:
|
||||
static unsigned alignup(unsigned num, unsigned align);
|
||||
static unsigned aligndown(unsigned num, unsigned align);
|
||||
|
||||
template <typename T> static T max(T a, T b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
template <typename T> static T min(T a, T b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T> static T clamp(T value, T minVal, T maxVal)
|
||||
{
|
||||
return max(minVal, min(maxVal, value));
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
37
util/Md5Util.h
Normal file
37
util/Md5Util.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef B6E698FD_68E6_4CB8_9BBA_BFE96C7501B0
|
||||
#define B6E698FD_68E6_4CB8_9BBA_BFE96C7501B0
|
||||
#include <Poco/DigestStream.h>
|
||||
#include <Poco/MD5Engine.h>
|
||||
#include <Poco/UUID.h>
|
||||
#include <Poco/UUIDGenerator.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
class Md5Util
|
||||
{
|
||||
public:
|
||||
static std::string md5(const std::string& data)
|
||||
{
|
||||
Poco::MD5Engine md5Engine;
|
||||
|
||||
Poco::DigestOutputStream dos(md5Engine);
|
||||
dos << data;
|
||||
dos.close();
|
||||
|
||||
const Poco::DigestEngine::Digest& digest = md5Engine.digest();
|
||||
|
||||
return Poco::DigestEngine::digestToHex(digest);
|
||||
}
|
||||
|
||||
static std::string uuid()
|
||||
{
|
||||
Poco::UUIDGenerator& generator = Poco::UUIDGenerator::defaultGenerator();
|
||||
|
||||
Poco::UUID uuid = generator.createRandom();
|
||||
|
||||
return uuid.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
20
util/ParallelRunner.cpp
Normal file
20
util/ParallelRunner.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "ParallelRunner.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
void ParallelRunner::join()
|
||||
{
|
||||
for (auto& t : _threads)
|
||||
t->join();
|
||||
}
|
||||
}
|
||||
35
util/ParallelRunner.h
Normal file
35
util/ParallelRunner.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef DE82057F_5520_4849_8108_E9A31AAC1878
|
||||
#define DE82057F_5520_4849_8108_E9A31AAC1878
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <functional>
|
||||
#include <Poco/Thread.h>
|
||||
#include <Poco/SharedPtr.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class ParallelRunner
|
||||
{
|
||||
public:
|
||||
template <class Func, class... Args> void run(Func func, Args... args)
|
||||
{
|
||||
Poco::Thread* pThread = new Poco::Thread();
|
||||
pThread->startFunc([=]() -> void { func(args...); });
|
||||
_threads.push_back(pThread);
|
||||
}
|
||||
|
||||
void join();
|
||||
|
||||
private:
|
||||
std::vector<Poco::SharedPtr<Poco::Thread>> _threads;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
44
util/PocoConfigurationCopier.cpp
Normal file
44
util/PocoConfigurationCopier.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "PocoConfigurationCopier.h"
|
||||
#include <Poco/Util/JSONConfiguration.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
void PocoConfigurationCopier::copy(Poco::Util::AbstractConfiguration::Ptr& from,
|
||||
Poco::Util::AbstractConfiguration::Ptr& to)
|
||||
{
|
||||
bool usingJSON = false;
|
||||
|
||||
if (to.isNull())
|
||||
{
|
||||
to = new Poco::Util::JSONConfiguration();
|
||||
usingJSON = true;
|
||||
}
|
||||
else
|
||||
usingJSON = !to.cast<Poco::Util::JSONConfiguration>().isNull();
|
||||
|
||||
Poco::AutoPtr<Poco::Util::JSONConfiguration> pJConfig = from.cast<Poco::Util::JSONConfiguration>();
|
||||
if (pJConfig && usingJSON)
|
||||
{
|
||||
std::stringstream ss;
|
||||
pJConfig->save(ss);
|
||||
to.cast<Poco::Util::JSONConfiguration>()->load(ss);
|
||||
}
|
||||
else
|
||||
{
|
||||
Poco::Util::AbstractConfiguration::Keys keys;
|
||||
from->keys(keys);
|
||||
for (const auto& key : keys)
|
||||
to->setString(key, from->getString(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
23
util/PocoConfigurationCopier.h
Normal file
23
util/PocoConfigurationCopier.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef B2336806_10E0_4BFA_9CC6_0995436A32EB
|
||||
#define B2336806_10E0_4BFA_9CC6_0995436A32EB
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class PocoConfigurationCopier
|
||||
{
|
||||
public:
|
||||
static void copy(Poco::Util::AbstractConfiguration::Ptr& from, Poco::Util::AbstractConfiguration::Ptr& to);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
54
util/Service.cpp
Normal file
54
util/Service.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Service.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
namespace Util
|
||||
{
|
||||
|
||||
void Service::start()
|
||||
{
|
||||
if (isRunning())
|
||||
return;
|
||||
|
||||
_pThread = new Poco::Thread();
|
||||
try
|
||||
{
|
||||
_pThread->start(*this);
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
std::cout << " --> Service: Poco::Exception: " << e.displayText() << "(" << e.what() << ")" << std::endl;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << " --> Service: std::exception: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Service::stop()
|
||||
{
|
||||
if (isRunning())
|
||||
{
|
||||
cancel();
|
||||
_pThread->join();
|
||||
_pThread.reset();
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool Service::isRunning() const
|
||||
{
|
||||
return !_pThread.isNull() && _pThread->isRunning();
|
||||
}
|
||||
|
||||
}
|
||||
31
util/Service.h
Normal file
31
util/Service.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef F3A063B4_C5E0_40B0_AFDA_B9DC936E9E82
|
||||
#define F3A063B4_C5E0_40B0_AFDA_B9DC936E9E82
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/Task.h>
|
||||
#include <Poco/Thread.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Service: public Poco::Task
|
||||
{
|
||||
public:
|
||||
using Poco::Task::Task;
|
||||
|
||||
virtual void start();
|
||||
virtual void stop();
|
||||
bool isRunning() const;
|
||||
|
||||
private:
|
||||
Poco::SharedPtr<Poco::Thread> _pThread;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
15
util/SimpleFactory.cpp
Normal file
15
util/SimpleFactory.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "SimpleFactory.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
}
|
||||
20
util/SimpleFactory.h
Normal file
20
util/SimpleFactory.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef FF4EF0DA_D455_437D_A5ED_BA7A7994B9CB
|
||||
#define FF4EF0DA_D455_437D_A5ED_BA7A7994B9CB
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
template <class T, class... TArgs> class SimpleFactory
|
||||
{
|
||||
public:
|
||||
static T* create(TArgs... args)
|
||||
{
|
||||
return new T(args...);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
35
util/Subsystem.cpp
Normal file
35
util/Subsystem.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDES
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Subsystem.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Subsystem::Subsystem(int maxCapacity): _threadPool(2, 16, 60, 0), _taskManager(_threadPool)
|
||||
{
|
||||
}
|
||||
|
||||
void Subsystem::run(Service* pService)
|
||||
{
|
||||
_taskManager.start(pService);
|
||||
}
|
||||
|
||||
void Subsystem::stopAll()
|
||||
{
|
||||
_taskManager.cancelAll();
|
||||
_taskManager.joinAll();
|
||||
}
|
||||
|
||||
void Subsystem::uninitialize()
|
||||
{
|
||||
stopAll();
|
||||
}
|
||||
|
||||
}
|
||||
39
util/Subsystem.h
Normal file
39
util/Subsystem.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef DC436124_02CE_49A1_88B1_1A95453FA546
|
||||
#define DC436124_02CE_49A1_88B1_1A95453FA546
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Service.h"
|
||||
#include <Poco/Task.h>
|
||||
#include <Poco/TaskManager.h>
|
||||
#include <Poco/Thread.h>
|
||||
#include <Poco/ThreadPool.h>
|
||||
#include <Poco/Util/Subsystem.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Subsystem: public Poco::Util::Subsystem
|
||||
{
|
||||
public:
|
||||
Subsystem(int maxCapacity = 16);
|
||||
|
||||
protected:
|
||||
void run(Service* pService);
|
||||
|
||||
void stopAll();
|
||||
|
||||
virtual void uninitialize() override;
|
||||
|
||||
private:
|
||||
Poco::ThreadPool _threadPool;
|
||||
Poco::TaskManager _taskManager;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
829
util/SystemInfo.cpp
Normal file
829
util/SystemInfo.cpp
Normal file
|
|
@ -0,0 +1,829 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "SystemInfo.h"
|
||||
#include <Poco/DirectoryIterator.h>
|
||||
#include <Poco/Path.h>
|
||||
#include <Poco/Pipe.h>
|
||||
#include <Poco/PipeStream.h>
|
||||
#include <Poco/Process.h>
|
||||
#include <Poco/StreamCopier.h>
|
||||
#include <dirent.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <experimental/filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include "Application.h"
|
||||
#include "Logger.h"
|
||||
#include "Poco/Thread.h"
|
||||
#include "linux-system-usage.hpp"
|
||||
|
||||
using namespace get_system_usage_linux;
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
unsigned SystemInfo::cpuUsage()
|
||||
{
|
||||
CPU_stats t1 = read_cpu_data();
|
||||
Poco::Thread::sleep(100);
|
||||
CPU_stats t2 = read_cpu_data();
|
||||
|
||||
return (unsigned)(100.0f * get_cpu_usage(t1, t2));
|
||||
}
|
||||
|
||||
SystemInfo::MemoryInfo SystemInfo::readMemoryInfo()
|
||||
{
|
||||
auto memory_data = read_memory_data();
|
||||
|
||||
MemoryInfo info;
|
||||
info.total = memory_data.total_memory;
|
||||
info.free = memory_data.free_memory;
|
||||
info.usage = 100.0f * memory_data.get_memory_usage();
|
||||
info.available = memory_data.available_memory;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
std::map<std::string, Util::SystemInfo::StorageInfo> SystemInfo::getStorageInfo(bool returnSpace)
|
||||
{
|
||||
std::ifstream mounts("/proc/mounts");
|
||||
std::string line;
|
||||
std::map<std::string, StorageInfo> storageMap;
|
||||
|
||||
if (!mounts.is_open())
|
||||
{
|
||||
logger().error("Failed to open /proc/mounts");
|
||||
return storageMap;
|
||||
}
|
||||
while (std::getline(mounts, line))
|
||||
{
|
||||
std::istringstream iss(line);
|
||||
std::string device, path;
|
||||
iss >> device >> path;
|
||||
std::string deviceType = device.find("/dev/sd") == 0 ? "disk" : "";
|
||||
deviceType = !deviceType.empty() ? deviceType : (device.find("/dev/mmcblk") == 0 ? "mmcblk" : "");
|
||||
deviceType = !deviceType.empty() ? deviceType : (path.find("/mnt/storages/nfs") == 0 ? "nfs" : "");
|
||||
deviceType = !deviceType.empty() ? deviceType : (path.find("/mnt/storages/cifs") == 0 ? "cifs" : "");
|
||||
if (!deviceType.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!mountPointEnable(path))
|
||||
{
|
||||
logger().error("%s Mount point is not available", path);
|
||||
continue;
|
||||
}
|
||||
StorageInfo storageInfo;
|
||||
storageInfo.device = device;
|
||||
storageInfo.path = path;
|
||||
storageInfo.status = 1;
|
||||
storageInfo.type = deviceType;
|
||||
|
||||
if (returnSpace)
|
||||
{
|
||||
struct statvfs stat;
|
||||
int ret_code = statvfs(path.c_str(), &stat);
|
||||
if (ret_code != 0)
|
||||
{
|
||||
int err = errno;
|
||||
logger().error("Failed to get disk usage information for: %s", strerror(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long long total = stat.f_blocks * stat.f_frsize;
|
||||
unsigned long long free = stat.f_bfree * stat.f_frsize;
|
||||
unsigned long long available = stat.f_bavail * stat.f_frsize;
|
||||
unsigned long long used = total - free;
|
||||
storageInfo.total = total;
|
||||
storageInfo.used = used;
|
||||
storageInfo.available = available;
|
||||
storageInfo.free = free;
|
||||
}
|
||||
}
|
||||
storageMap[device] = storageInfo;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
logger().error("SystemInfo::getStorageInfo erorr: %s", std::string(e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto blocks = getBlockDevices();
|
||||
for (const auto& block : blocks)
|
||||
{
|
||||
if (block.empty() || block.back() != '1')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = storageMap.find(block);
|
||||
if (it == storageMap.end())
|
||||
{
|
||||
StorageInfo storageInfo;
|
||||
storageInfo.status = 2;
|
||||
storageInfo.device = block;
|
||||
storageMap[block] = storageInfo;
|
||||
}
|
||||
}
|
||||
return storageMap;
|
||||
}
|
||||
|
||||
bool isBlockDevice(const std::string& path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
if (stat(path.c_str(), &statbuf) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return S_ISBLK(statbuf.st_mode);
|
||||
}
|
||||
|
||||
std::vector<std::string> SystemInfo::getBlockDevices()
|
||||
{
|
||||
std::vector<std::string> blockDevices;
|
||||
std::ifstream file("/proc/partitions");
|
||||
std::string line;
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
std::istringstream iss(line);
|
||||
std::string major, minor, blocks, name;
|
||||
if (!(iss >> major >> minor >> blocks >> name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string devicePath = "/dev/" + name;
|
||||
if (devicePath.find("/dev/sd") == 0 && isBlockDevice(devicePath))
|
||||
{
|
||||
blockDevices.push_back(devicePath);
|
||||
}
|
||||
}
|
||||
|
||||
return blockDevices;
|
||||
}
|
||||
|
||||
std::vector<Util::SystemInfo::FileInfo> SystemInfo::getFileInfoList(std::string parentPath)
|
||||
{
|
||||
std::vector<Util::SystemInfo::FileInfo> fileInfoList;
|
||||
Poco::Path path(parentPath);
|
||||
if (!path.isDirectory())
|
||||
{
|
||||
logger().error("Error: %s is not a directory.", parentPath);
|
||||
return fileInfoList;
|
||||
}
|
||||
try
|
||||
{
|
||||
Poco::DirectoryIterator it(parentPath);
|
||||
Poco::DirectoryIterator end;
|
||||
|
||||
while (it != end)
|
||||
{
|
||||
const Poco::Path& p = it.path();
|
||||
Util::SystemInfo::FileInfo fileInfo;
|
||||
fileInfo.name = p.getFileName();
|
||||
fileInfo.parentPath = parentPath;
|
||||
fileInfo.type = it->isDirectory() ? 2 : (it->isFile() ? 1 : 0);
|
||||
if (it->isDirectory())
|
||||
{
|
||||
}
|
||||
else if (it->isFile())
|
||||
{
|
||||
Poco::File file(p.toString());
|
||||
fileInfo.size = file.getSize();
|
||||
fileInfo.lastModifyTime = file.getLastModified().epochTime();
|
||||
}
|
||||
++it;
|
||||
fileInfoList.push_back(fileInfo);
|
||||
}
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
logger().error("An error occurred: %s", e.displayText());
|
||||
}
|
||||
return fileInfoList;
|
||||
}
|
||||
|
||||
unsigned long long Util::SystemInfo::getPathFreeSpace(const std::string& path)
|
||||
{
|
||||
struct statvfs stat;
|
||||
if (statvfs(path.c_str(), &stat) != 0)
|
||||
{
|
||||
logger().error("Failed to get filesystem stats for %s", path);
|
||||
return 0;
|
||||
}
|
||||
unsigned long long free = stat.f_bfree * stat.f_frsize;
|
||||
|
||||
return free;
|
||||
}
|
||||
|
||||
unsigned long long Util::SystemInfo::checkSizeAndDelEarliestFile(const std::string& basePath,
|
||||
const unsigned int limitMB,
|
||||
const std::string deletePath,
|
||||
const std::string& deleteExtName,
|
||||
const std::set<std::string> exculdePathOrFiles)
|
||||
{
|
||||
int i = 10;
|
||||
unsigned long long freeBytes = 0;
|
||||
while (i-- > 0)
|
||||
{
|
||||
freeBytes = getPathFreeSpace(basePath);
|
||||
unsigned long long limitBytes = static_cast<unsigned long long>(limitMB) * 1024 * 1024;
|
||||
logger().information(" freeBytes=%s, limitBytes=%s", std::to_string(freeBytes), std::to_string(limitBytes));
|
||||
|
||||
if (freeBytes < limitBytes)
|
||||
{
|
||||
logger().information(" Space is less than=%s. Deleting earliest file...", std::to_string(limitMB));
|
||||
|
||||
try
|
||||
{
|
||||
std::string findCmd = "find " + deletePath + " -type f -name \"*" + deleteExtName +
|
||||
"\" -exec stat -c '%mY %n' {} + | sort -n | head -n 1 | cut -d' ' -f2-";
|
||||
logger().information("Execute command: %s", findCmd);
|
||||
std::string oldestFile;
|
||||
std::array<char, 128> buffer;
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(findCmd.c_str(), "r"), pclose);
|
||||
if (!pipe)
|
||||
{
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
|
||||
{
|
||||
oldestFile += buffer.data();
|
||||
}
|
||||
|
||||
if (!oldestFile.empty() && oldestFile[oldestFile.size() - 1] == '\n')
|
||||
{
|
||||
oldestFile.erase(oldestFile.size() - 1);
|
||||
}
|
||||
|
||||
if (!oldestFile.empty())
|
||||
{
|
||||
bool isExecuteDelete = true;
|
||||
|
||||
for (std::string name : exculdePathOrFiles)
|
||||
{
|
||||
if (oldestFile.find(name) == 0)
|
||||
{
|
||||
isExecuteDelete = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isExecuteDelete)
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::File file(oldestFile);
|
||||
|
||||
if (file.exists())
|
||||
{
|
||||
file.remove();
|
||||
logger().information("File deleted successfully: %s", oldestFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger().information("File does not exist: %s", oldestFile);
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception& ex)
|
||||
{
|
||||
logger().information("Failed to delete file: : %s, error:", oldestFile, ex.displayText());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger().information("deleted old file -> exculde path or file:%s", oldestFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger().information("deleted old file -> No .mp4 files found");
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
logger().error("deleted old file -> Error: ", e.what());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (freeBytes <= 0)
|
||||
{
|
||||
freeBytes = getPathFreeSpace(basePath);
|
||||
}
|
||||
return freeBytes;
|
||||
}
|
||||
|
||||
bool Util::SystemInfo::mountPointEnable(const std::string& localPath)
|
||||
{
|
||||
return Util::SystemInfo::executeCommand("ls " + localPath, 5);
|
||||
}
|
||||
|
||||
bool Util::SystemInfo::mountCifs(std::string ip, std::string remotePath, std::string localPath, std::string username,
|
||||
std::string password, std::string vers, std::string charset)
|
||||
{
|
||||
Util::SystemInfo::umount(localPath);
|
||||
Util::SystemInfo::executeCommand("rm -rf " + localPath);
|
||||
Util::SystemInfo::executeCommand("mkdir -p " + localPath);
|
||||
|
||||
std::string _charset = charset.empty() ? "" : ",iocharset=" + charset;
|
||||
std::string mountCmd = Poco::format("mount -t cifs -o username=%s,password=%s,vers=%s%s //%s%s %s", username,
|
||||
password, vers, _charset, ip, remotePath, localPath);
|
||||
return Util::SystemInfo::executeCommand(mountCmd);
|
||||
}
|
||||
bool Util::SystemInfo::mountNfs(std::string ip, std::string remotePath, std::string localPath, std::string vers)
|
||||
{
|
||||
Util::SystemInfo::umount(localPath);
|
||||
Util::SystemInfo::executeCommand("rm -rf " + localPath);
|
||||
Util::SystemInfo::executeCommand("mkdir -p " + localPath);
|
||||
|
||||
std::string mountCmd = Poco::format("mount -t nfs -o nolock,vers=%s %s:%s %s", vers, ip, remotePath, localPath);
|
||||
return Util::SystemInfo::executeCommand(mountCmd, 5);
|
||||
}
|
||||
bool Util::SystemInfo::umount(std::string localPath)
|
||||
{
|
||||
return Util::SystemInfo::executeCommand("umount -f " + localPath);
|
||||
}
|
||||
|
||||
int Util::SystemInfo::getProcessPID(const std::string& processName)
|
||||
{
|
||||
try
|
||||
{
|
||||
DIR* dir = opendir("/proc");
|
||||
if (!dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string targetName = processName;
|
||||
size_t lastSlash = targetName.find_last_of('/');
|
||||
if (lastSlash != std::string::npos)
|
||||
{
|
||||
targetName = targetName.substr(lastSlash + 1);
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
int pid = 0;
|
||||
|
||||
while ((entry = readdir(dir)))
|
||||
{
|
||||
if (entry->d_type != DT_DIR || !isdigit(entry->d_name[0]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string commPath = std::string("/proc/") + entry->d_name + "/comm";
|
||||
std::ifstream commFile(commPath);
|
||||
if (commFile)
|
||||
{
|
||||
std::string commName;
|
||||
if (std::getline(commFile, commName))
|
||||
{
|
||||
commName.erase(std::remove(commName.begin(), commName.end(), '\n'), commName.end());
|
||||
if (commName == targetName)
|
||||
{
|
||||
pid = std::stoi(entry->d_name);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
std::string cmdlinePath = std::string("/proc/") + entry->d_name + "/cmdline";
|
||||
std::ifstream cmdlineFile(cmdlinePath);
|
||||
if (cmdlineFile)
|
||||
{
|
||||
std::string cmdline;
|
||||
if (std::getline(cmdlineFile, cmdline))
|
||||
{
|
||||
size_t nullPos = cmdline.find('\0');
|
||||
if (nullPos != std::string::npos)
|
||||
{
|
||||
cmdline.resize(nullPos);
|
||||
}
|
||||
|
||||
lastSlash = cmdline.find_last_of('/');
|
||||
std::string exeName = (lastSlash != std::string::npos) ? cmdline.substr(lastSlash + 1) : cmdline;
|
||||
if (exeName == targetName)
|
||||
{
|
||||
pid = std::stoi(entry->d_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return pid;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
logger().error("getProcessPID Error: %s", std::string(e.what()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> Util::SystemInfo::getNetworkInterfaceNames()
|
||||
{
|
||||
std::vector<std::string> interfaceNames;
|
||||
try
|
||||
{
|
||||
Poco::Net::NetworkInterface::List interfaces = Poco::Net::NetworkInterface::list(false, false);
|
||||
for (const auto& interface : interfaces)
|
||||
{
|
||||
if (!interface.isLoopback()
|
||||
|
||||
&& !interface.name().empty())
|
||||
{
|
||||
interfaceNames.push_back(interface.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception& e)
|
||||
{
|
||||
logger().error("getNetworkInterfaceNames Error: %s", std::string(e.what()));
|
||||
}
|
||||
return interfaceNames;
|
||||
}
|
||||
|
||||
Util::SystemInfo::NetworkInterfaceInfo Util::SystemInfo::getNetWorkInterfaceInfo(const std::string& interfaceName,
|
||||
bool returnGateway)
|
||||
{
|
||||
Util::SystemInfo::NetworkInterfaceInfo info;
|
||||
try
|
||||
{
|
||||
auto interface = Poco::Net::NetworkInterface::forName(interfaceName);
|
||||
if (interface.name() == interfaceName)
|
||||
{
|
||||
info.name = interface.name();
|
||||
info.displayName = interface.displayName();
|
||||
info.ipAddress = interface.address().toString();
|
||||
info.subnetMask = interface.subnetMask().toString();
|
||||
info.broadcastAddress = interface.broadcastAddress().toString();
|
||||
auto macAddress = interface.macAddress();
|
||||
info.macAddress = Poco::format("%02X:%02X:%02X:%02X:%02X:%02X", (unsigned)macAddress[0],
|
||||
(unsigned)macAddress[1], (unsigned)macAddress[2], (unsigned)macAddress[3],
|
||||
(unsigned)macAddress[4], (unsigned)macAddress[5]);
|
||||
info.isUp = interface.isUp();
|
||||
|
||||
if (returnGateway)
|
||||
{
|
||||
info.gateway = gatewayAddress(interfaceName).toString();
|
||||
}
|
||||
info.isInitialized = true;
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception& e)
|
||||
{
|
||||
logger().error("Error getNetWorkInterfaceInfo info: %s", std::string(e.what()));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
Poco::Net::IPAddress Util::SystemInfo::localAddress(const std::string& interfaceName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Poco::Net::NetworkInterface::forName(interfaceName).address();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return Poco::Net::IPAddress("0.0.0.0");
|
||||
}
|
||||
}
|
||||
std::map<std::string, Poco::Net::IPAddress> Util::SystemInfo::localAddresses()
|
||||
{
|
||||
std::map<std::string, Poco::Net::IPAddress> ipMap;
|
||||
try
|
||||
{
|
||||
Poco::Net::NetworkInterface::List interfaces = Poco::Net::NetworkInterface::list();
|
||||
|
||||
for (const auto& interface : interfaces)
|
||||
{
|
||||
if (interface.isUp() && !interface.isLoopback() && !interface.address().isWildcard() &&
|
||||
interface.address().isUnicast() && interface.address().family() == Poco::Net::AddressFamily::IPv4)
|
||||
{
|
||||
ipMap[interface.name()] = interface.address();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception& e)
|
||||
{
|
||||
logger().error("localAddresses Error: %s", std::string(e.what()));
|
||||
}
|
||||
return ipMap;
|
||||
}
|
||||
|
||||
std::vector<std::string> Util::SystemInfo::localAddressesList()
|
||||
{
|
||||
std::vector<std::string> ipList;
|
||||
try
|
||||
{
|
||||
Poco::Net::NetworkInterface::List interfaces = Poco::Net::NetworkInterface::list();
|
||||
|
||||
for (const auto& interface : interfaces)
|
||||
{
|
||||
if (interface.isUp() && !interface.isLoopback())
|
||||
{
|
||||
Poco::Net::NetworkInterface::AddressList addresses = interface.addressList();
|
||||
|
||||
for (const auto& addressInfo : addresses)
|
||||
{
|
||||
const Poco::Net::IPAddress& ip = addressInfo.get<0>();
|
||||
|
||||
if (!ip.isWildcard() && ip.isUnicast() && ip.family() == Poco::Net::AddressFamily::IPv4)
|
||||
{
|
||||
ipList.push_back(ip.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception& e)
|
||||
{
|
||||
logger().error("localAddresses Error: %s", std::string(e.what()));
|
||||
}
|
||||
return ipList;
|
||||
}
|
||||
|
||||
std::string Util::SystemInfo::localAddressOfAvailable()
|
||||
{
|
||||
std::map<std::string, Poco::Net::IPAddress> ipMap = localAddresses();
|
||||
std::string hostIp = "0.0.0.0";
|
||||
if (!ipMap.empty())
|
||||
{
|
||||
hostIp = ipMap.begin()->second.toString();
|
||||
}
|
||||
return hostIp;
|
||||
}
|
||||
|
||||
std::string Util::SystemInfo::getFirstWirelessInterfaceName()
|
||||
{
|
||||
auto interfaces = getNetworkInterfaceNames();
|
||||
for (auto& name : interfaces)
|
||||
{
|
||||
std::vector<std::string> wirelessPatterns = {"wlan", "wi-fi", "wireless", "wifi", "ath", "ra", "wlp", "wlan"};
|
||||
for (const auto& pattern : wirelessPatterns)
|
||||
{
|
||||
if (Poco::toLower(name).find(pattern) != std::string::npos)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Poco::Net::IPAddress Util::SystemInfo::subnetMask(const std::string& interfaceName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Poco::Net::NetworkInterface::forName(interfaceName).subnetMask();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return Poco::Net::IPAddress("0.0.0.0");
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::NetworkInterface::MACAddress Util::SystemInfo::macAddress(const std::string& interfaceName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Poco::Net::NetworkInterface::forName(interfaceName).macAddress();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return Poco::Net::NetworkInterface::MACAddress();
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::NetworkInterface::MACAddress Util::SystemInfo::getFirstMacAddress()
|
||||
{
|
||||
auto interfaces = getNetworkInterfaceNames();
|
||||
try
|
||||
{
|
||||
for (const auto& name : interfaces)
|
||||
{
|
||||
return Poco::Net::NetworkInterface::forName(name).macAddress();
|
||||
}
|
||||
return Poco::Net::NetworkInterface::MACAddress();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return Poco::Net::NetworkInterface::MACAddress();
|
||||
}
|
||||
}
|
||||
|
||||
bool Util::SystemInfo::netInterfaceIsExist(const std::string& interfaceName)
|
||||
{
|
||||
if (interfaceName.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> interfaceNames = Util::SystemInfo::getNetworkInterfaceNames();
|
||||
for (const auto& name : interfaceNames)
|
||||
{
|
||||
if (interfaceName == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Util::SystemInfo::netInterfaceIsAvailable(const std::string& interfaceName)
|
||||
{
|
||||
std::vector<std::string> interfaceNames;
|
||||
try
|
||||
{
|
||||
Poco::Net::NetworkInterface::List interfaces = Poco::Net::NetworkInterface::list(false, false);
|
||||
for (const auto& interface : interfaces)
|
||||
{
|
||||
if (!interface.isLoopback() && interface.isUp() && !interface.name().empty())
|
||||
{
|
||||
if (interfaceName == interface.name())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception& e)
|
||||
{
|
||||
logger().error("netInterfaceIsAvailable Error: %s", std::string(e.what()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Poco::Net::IPAddress Util::SystemInfo::gatewayAddress(const std::string& interfaceName)
|
||||
{
|
||||
#define BUFLEN 20480
|
||||
Poco::Net::IPAddress invalid("0.0.0.0");
|
||||
|
||||
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (fd < 0)
|
||||
{
|
||||
logger().error("NETLINK socket error");
|
||||
return invalid;
|
||||
}
|
||||
|
||||
char req[BUFLEN] = {0};
|
||||
struct nlmsghdr* nh = (struct nlmsghdr*)req;
|
||||
nh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
nh->nlmsg_type = RTM_GETROUTE;
|
||||
nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nh);
|
||||
rtm->rtm_family = AF_INET;
|
||||
rtm->rtm_table = RT_TABLE_MAIN;
|
||||
struct sockaddr_nl nladdr = {0};
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
if (bind(fd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0)
|
||||
{
|
||||
logger().error("NETLINK bind error");
|
||||
close(fd);
|
||||
return invalid;
|
||||
}
|
||||
if (send(fd, req, sizeof(req), 0) < 0)
|
||||
{
|
||||
logger().error("NETLINK send error");
|
||||
close(fd);
|
||||
return invalid;
|
||||
}
|
||||
|
||||
char buf[BUFLEN] = {0};
|
||||
struct iovec iov = {buf, sizeof(buf)};
|
||||
struct sockaddr_nl sa;
|
||||
struct msghdr msg = {&sa, sizeof(sa), &iov, 1, NULL, 0, 0};
|
||||
int len = recvmsg(fd, &msg, 0);
|
||||
if (len < 0)
|
||||
{
|
||||
logger().error("NETLINK recvmsg error");
|
||||
close(fd);
|
||||
return invalid;
|
||||
}
|
||||
|
||||
struct nlmsghdr* nhp;
|
||||
for (nhp = (struct nlmsghdr*)buf; NLMSG_OK(nhp, len); nhp = NLMSG_NEXT(nhp, len))
|
||||
{
|
||||
struct rtmsg* rtp = (struct rtmsg*)NLMSG_DATA(nhp);
|
||||
if (rtp->rtm_table != RT_TABLE_MAIN || rtp->rtm_family != AF_INET)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
struct rtattr* attr = (struct rtattr*)RTM_RTA(rtp);
|
||||
int attrlen = RTM_PAYLOAD(nhp);
|
||||
for (; RTA_OK(attr, attrlen); attr = RTA_NEXT(attr, attrlen))
|
||||
{
|
||||
if (attr->rta_type != RTA_GATEWAY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t gateway = *(uint32_t*)RTA_DATA(attr);
|
||||
char gwstr[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &gateway, gwstr, sizeof(gwstr));
|
||||
close(fd);
|
||||
|
||||
return Poco::Net::IPAddress(std::string(gwstr));
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return invalid;
|
||||
}
|
||||
|
||||
bool Util::SystemInfo::executeCommand(const std::string& command, int timeout_sec, std::string& output)
|
||||
{
|
||||
if (timeout_sec <= 0)
|
||||
{
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
|
||||
if (!pipe)
|
||||
{
|
||||
logger().error("Failed to execute command: %s", command);
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr)
|
||||
{
|
||||
output += buffer;
|
||||
}
|
||||
|
||||
int status = pclose(pipe.release());
|
||||
int ret = WEXITSTATUS(status);
|
||||
if (ret != 0)
|
||||
{
|
||||
logger().error("Command failed: %s, exit code: %d, error: %s", command, ret, output);
|
||||
return false;
|
||||
}
|
||||
logger().information("Command succeeded: %s, exit code: %d", command, ret);
|
||||
return true;
|
||||
}
|
||||
|
||||
output.clear();
|
||||
std::string timeoutCommand = "timeout -s KILL " + std::to_string(timeout_sec) + " " + command;
|
||||
timeoutCommand += " 2>/dev/null || timeout -s KILL -t " + std::to_string(timeout_sec) + " " + command;
|
||||
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(timeoutCommand.c_str(), "r"), pclose);
|
||||
if (!pipe)
|
||||
{
|
||||
logger().error("2Failed to execute command: %s", timeoutCommand);
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr)
|
||||
{
|
||||
output += buffer;
|
||||
}
|
||||
|
||||
int status = pclose(pipe.release());
|
||||
int ret = WEXITSTATUS(status);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
if (ret == 124 || output.find("time") != std::string::npos)
|
||||
{
|
||||
logger().error("2Command timeout: %s", timeoutCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger().error("2Command failed: %s, exit code: %d, error: %s", timeoutCommand, ret, output);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
logger().information("2Command succeeded: %s, exit code: %d", timeoutCommand, ret);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
140
util/SystemInfo.h
Normal file
140
util/SystemInfo.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#ifndef C42159C1_B275_444E_86D0_9A26B781F354
|
||||
#define C42159C1_B275_444E_86D0_9A26B781F354
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/Net/IPAddress.h>
|
||||
#include <Poco/Net/NetworkInterface.h>
|
||||
#include <stdint.h>
|
||||
#include <ctime>
|
||||
#include "util/xpack/json.h"
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class SystemInfo
|
||||
{
|
||||
public:
|
||||
struct MemoryInfo
|
||||
{
|
||||
uint32_t total;
|
||||
uint32_t free;
|
||||
uint32_t usage;
|
||||
uint32_t available;
|
||||
};
|
||||
|
||||
struct StorageInfo
|
||||
{
|
||||
std::string type = "";
|
||||
int status = 0;
|
||||
std::string device = "";
|
||||
std::string path = "";
|
||||
unsigned long long total = 0;
|
||||
unsigned long long used = 0;
|
||||
unsigned long long available = 0;
|
||||
unsigned long long free = 0;
|
||||
StorageInfo() = default;
|
||||
|
||||
XPACK(O(type, status, device, path, total, used, available, free));
|
||||
};
|
||||
|
||||
struct FileInfo
|
||||
{
|
||||
std::string name;
|
||||
std::string parentPath = "";
|
||||
int type;
|
||||
off_t size;
|
||||
time_t lastModifyTime;
|
||||
XPACK(O(name, parentPath, type, size, lastModifyTime));
|
||||
};
|
||||
|
||||
struct NetworkInterfaceInfo
|
||||
{
|
||||
std::string name;
|
||||
std::string displayName;
|
||||
std::string ipAddress = "0.0.0.0";
|
||||
std::string subnetMask = "0.0.0.0";
|
||||
std::string broadcastAddress;
|
||||
std::string gateway = "0.0.0.0";
|
||||
std::string macAddress;
|
||||
bool isUp;
|
||||
|
||||
bool isInitialized;
|
||||
|
||||
NetworkInterfaceInfo() = default;
|
||||
XPACK(O(name, displayName, ipAddress, subnetMask, broadcastAddress, gateway, macAddress, isUp));
|
||||
};
|
||||
|
||||
public:
|
||||
static unsigned cpuUsage();
|
||||
static MemoryInfo readMemoryInfo();
|
||||
|
||||
static std::map<std::string, Util::SystemInfo::StorageInfo> getStorageInfo(bool returnSpace = true);
|
||||
|
||||
static std::vector<std::string> getBlockDevices();
|
||||
|
||||
static std::vector<Util::SystemInfo::FileInfo> getFileInfoList(std::string parentPath);
|
||||
|
||||
static unsigned long long getPathFreeSpace(const std::string& path);
|
||||
|
||||
static unsigned long long checkSizeAndDelEarliestFile(const std::string& basePath, const unsigned int limitMB,
|
||||
const std::string deletePath,
|
||||
const std::string& deleteExtName,
|
||||
const std::set<std::string> exculdePathOrFiles);
|
||||
|
||||
static bool mountPointEnable(const std::string& localPath);
|
||||
|
||||
static bool mountCifs(std::string ip, std::string remotePath, std::string localPath, std::string username,
|
||||
std::string password, std::string vers = "2.0", std::string charset = "");
|
||||
|
||||
static bool mountNfs(std::string ip, std::string remotePath, std::string localPath, std::string vers = "4");
|
||||
static bool umount(std::string localPath);
|
||||
|
||||
static int getProcessPID(const std::string& processName);
|
||||
|
||||
static std::vector<std::string> getNetworkInterfaceNames();
|
||||
|
||||
static NetworkInterfaceInfo getNetWorkInterfaceInfo(const std::string& interfaceName, bool returnGateway = false);
|
||||
|
||||
static bool netInterfaceIsExist(const std::string& interfaceName);
|
||||
|
||||
static bool netInterfaceIsAvailable(const std::string& interfaceName);
|
||||
|
||||
static Poco::Net::IPAddress localAddress(const std::string& interfaceName);
|
||||
|
||||
static std::map<std::string, Poco::Net::IPAddress> localAddresses();
|
||||
|
||||
static std::vector<std::string> localAddressesList();
|
||||
|
||||
static std::string localAddressOfAvailable();
|
||||
|
||||
static std::string getFirstWirelessInterfaceName();
|
||||
|
||||
static Poco::Net::IPAddress subnetMask(const std::string& interfaceName);
|
||||
|
||||
static Poco::Net::NetworkInterface::MACAddress macAddress(const std::string& interfaceName);
|
||||
|
||||
static Poco::Net::NetworkInterface::MACAddress getFirstMacAddress();
|
||||
|
||||
static Poco::Net::IPAddress gatewayAddress(const std::string& interfaceName);
|
||||
|
||||
static bool executeCommand(const std::string& command)
|
||||
{
|
||||
return executeCommand(command, 0);
|
||||
}
|
||||
|
||||
static bool executeCommand(const std::string& command, int timeout_sec)
|
||||
{
|
||||
std::string output;
|
||||
return executeCommand(command, timeout_sec, output);
|
||||
}
|
||||
|
||||
static bool executeCommand(const std::string& command, int timeout_sec, std::string& output);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
62
util/Task.cpp
Normal file
62
util/Task.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Task.h"
|
||||
#include "Logger.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Task::Task(const std::string& name): _name(name)
|
||||
{
|
||||
}
|
||||
|
||||
void Task::run(std::function<void(std::atomic<bool>& isCancelled)> func)
|
||||
{
|
||||
cancel();
|
||||
|
||||
Poco::FastMutex::ScopedLock lock(_lock);
|
||||
_pThread = new Poco::Thread();
|
||||
_isCancelled = false;
|
||||
|
||||
_pThread->startFunc(
|
||||
[this, func]() -> void
|
||||
{
|
||||
try
|
||||
{
|
||||
func(_isCancelled);
|
||||
}
|
||||
catch (Poco::Exception& e)
|
||||
{
|
||||
logger().error("Task(%s): %s", name(), e.displayText());
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
logger().error("Task(%s): %s", name(), std::string(e.what()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Task::cancel()
|
||||
{
|
||||
if (isRunning())
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_lock);
|
||||
_isCancelled = true;
|
||||
_pThread->join();
|
||||
_pThread.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool Task::isRunning()
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_lock);
|
||||
return !_pThread.isNull() && _pThread->isRunning();
|
||||
}
|
||||
}
|
||||
93
util/Task.h
Normal file
93
util/Task.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#ifndef EBDC071F_8F58_4C5D_ACB9_7C534616BEC5
|
||||
#define EBDC071F_8F58_4C5D_ACB9_7C534616BEC5
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include <Poco/Thread.h>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Task
|
||||
{
|
||||
public:
|
||||
Task(const std::string& name = "Anonymous");
|
||||
|
||||
public:
|
||||
void run(std::function<void(std::atomic<bool>& isCancelled)> func);
|
||||
|
||||
template <typename Func, typename... Args> static void run2(Func&& func, Args&&... args)
|
||||
{
|
||||
run2WithError(std::forward<Func>(func), nullptr, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Func, typename... Args>
|
||||
static void run2WithError(Func&& func, std::function<void(std::exception_ptr)> onError, Args&&... args)
|
||||
{
|
||||
auto boundFunc = std::bind(std::forward<Func>(func), std::forward<Args>(args)...);
|
||||
|
||||
std::thread(
|
||||
[boundFunc, onError]() mutable
|
||||
{
|
||||
try
|
||||
{
|
||||
boundFunc();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
if (onError)
|
||||
{
|
||||
onError(std::current_exception());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Util::Task::run2 exception: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (onError)
|
||||
{
|
||||
onError(std::current_exception());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Util::Task::run2 exception!" << std::endl;
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
void cancel();
|
||||
|
||||
bool isRunning();
|
||||
|
||||
const std::string& name() const;
|
||||
|
||||
private:
|
||||
const std::string _name;
|
||||
std::atomic<bool> _isCancelled;
|
||||
Poco::FastMutex _lock;
|
||||
Poco::SharedPtr<Poco::Thread> _pThread;
|
||||
};
|
||||
|
||||
inline const std::string& Task::name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
38
util/Temperature.cpp
Normal file
38
util/Temperature.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Temperature.h"
|
||||
#include "Device.h"
|
||||
#include "Application.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
float Temperature::read()
|
||||
{
|
||||
Device device("/sys/devices/virtual/mstar/msys/TEMP_R");
|
||||
|
||||
try
|
||||
{
|
||||
device.open();
|
||||
char str[64];
|
||||
device.read((uint8_t*)str, sizeof(str));
|
||||
int temp;
|
||||
sscanf(str, "Temperature %d", &temp);
|
||||
device.close();
|
||||
return temp;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
22
util/Temperature.h
Normal file
22
util/Temperature.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef AE8A4A92_D487_4675_9A6A_0B266E47C520
|
||||
#define AE8A4A92_D487_4675_9A6A_0B266E47C520
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
namespace Util
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Temperature
|
||||
{
|
||||
public:
|
||||
static float read();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
169
util/WifiUtil.h
Normal file
169
util/WifiUtil.h
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
#ifndef WIFI_UTIL_H
|
||||
#define WIFI_UTIL_H
|
||||
|
||||
#include <Poco/JSON/Array.h>
|
||||
#include <Poco/JSON/Object.h>
|
||||
#include <Poco/StringTokenizer.h>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "Application.h"
|
||||
#include "util/SystemInfo.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
class WifiUtil
|
||||
{
|
||||
private:
|
||||
public:
|
||||
static constexpr const char* frpcConfigPathName = "/customer/frp/frpc.toml";
|
||||
static constexpr const char* frpcPathName = "/customer/frp/frpc";
|
||||
|
||||
public:
|
||||
static Poco::JSON::Object::Ptr wifiStaStatus(const std::string& interfaceName)
|
||||
{
|
||||
Poco::JSON::Object::Ptr statusMap = new Poco::JSON::Object;
|
||||
try
|
||||
{
|
||||
std::string retStr;
|
||||
bool retFlag = Util::SystemInfo::executeCommand("wpa_cli -i " + interfaceName + " status", 10, retStr);
|
||||
if (retFlag)
|
||||
{
|
||||
Poco::StringTokenizer lines(retStr, "\n", Poco::StringTokenizer::TOK_TRIM);
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
size_t eqPos = line.find('=');
|
||||
if (eqPos != std::string::npos)
|
||||
{
|
||||
std::string key = line.substr(0, eqPos);
|
||||
std::string value = line.substr(eqPos + 1);
|
||||
statusMap->set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
logger().error("wifiStaStatus failed: %s", std::string(e.what()));
|
||||
}
|
||||
return statusMap;
|
||||
}
|
||||
|
||||
static bool wifiStaScan(const std::string& interfaceName, bool wifiEnable = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Util::SystemInfo::executeCommand("/customer/customer-network.sh " + interfaceName + " scan");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
logger().error("wifiStaScan failed: %s", std::string(e.what()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Poco::JSON::Array::Ptr wifiStaScanResults(const std::string& interfaceName)
|
||||
{
|
||||
Poco::JSON::Array::Ptr jsonArray = new Poco::JSON::Array;
|
||||
std::string retStr;
|
||||
bool retFlag = Util::SystemInfo::executeCommand("wpa_cli -i " + interfaceName + " scan_results", 10, retStr);
|
||||
if (!retFlag)
|
||||
{
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
Poco::StringTokenizer lines(retStr, "\n", Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
for (size_t i = 1; i < lines.count(); ++i)
|
||||
{
|
||||
Poco::StringTokenizer tokens(lines[i], "\t", Poco::StringTokenizer::TOK_TRIM);
|
||||
if (tokens.count() < 4)
|
||||
continue;
|
||||
|
||||
Poco::JSON::Object::Ptr netObj = new Poco::JSON::Object;
|
||||
netObj->set("bssid", tokens[0]);
|
||||
netObj->set("frequency", std::stoi(tokens[1]));
|
||||
netObj->set("signal_level", std::stoi(tokens[2]));
|
||||
|
||||
if (tokens.count() == 4 && tokens[3].find('[') == std::string::npos)
|
||||
{
|
||||
netObj->set("flags", "OPEN");
|
||||
netObj->set("ssid", convertHexEscape(tokens[3]));
|
||||
}
|
||||
else
|
||||
{
|
||||
netObj->set("flags", tokens[3]);
|
||||
netObj->set("ssid", tokens.count() > 4 ? convertHexEscape(tokens[4]) : "");
|
||||
}
|
||||
|
||||
jsonArray->add(netObj);
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
static bool wifiStaConnect(const std::string& interfaceName, int status)
|
||||
{
|
||||
if (status == 1)
|
||||
{
|
||||
return Util::SystemInfo::executeCommand("/customer/customer-network.sh " + interfaceName + " up");
|
||||
}
|
||||
else if (status == 0)
|
||||
{
|
||||
return Util::SystemInfo::executeCommand("/customer/customer-network.sh " + interfaceName + " down");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Poco::JSON::Array::Ptr wifiGetApClients(const std::string& interfaceName)
|
||||
{
|
||||
Poco::JSON::Array::Ptr jsonArray = new Poco::JSON::Array;
|
||||
std::string retStr;
|
||||
|
||||
bool retFlag = Util::SystemInfo::executeCommand(
|
||||
"ip neigh show dev " + interfaceName + " nud reachable | awk '{print $1, $3}'", 10, retStr);
|
||||
if (!retFlag)
|
||||
{
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
Poco::StringTokenizer lines(retStr, "\n", Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
for (size_t i = 0; i < lines.count(); ++i)
|
||||
{
|
||||
if (lines[i].empty())
|
||||
continue;
|
||||
Poco::StringTokenizer tokens(lines[i], " ", Poco::StringTokenizer::TOK_TRIM);
|
||||
if (tokens.count() < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
std::string ip = tokens[0], mac = tokens[1];
|
||||
|
||||
Poco::JSON::Object::Ptr netObj = new Poco::JSON::Object;
|
||||
netObj->set("ip", ip);
|
||||
netObj->set("mac", mac);
|
||||
jsonArray->add(netObj);
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
static std::string convertHexEscape(const std::string& input)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for (size_t i = 0; i < input.length();)
|
||||
{
|
||||
if (input.substr(i, 2) == "\\x" && i + 3 < input.length())
|
||||
{
|
||||
ss << static_cast<char>(std::stoi(input.substr(i + 2, 2), nullptr, 16));
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << input[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
203
util/linux-system-usage.hpp
Normal file
203
util/linux-system-usage.hpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/* ---------------------------------------------------------------------
|
||||
* Luiz Carlos doleron @ 2021
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero Public License version 3 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero Public License for more details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _GET_CPU_USAGE_LINUX_
|
||||
#define _GET_CPU_USAGE_LINUX_
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
namespace get_system_usage_linux
|
||||
{
|
||||
|
||||
struct CPU_stats
|
||||
{
|
||||
// see http://www.linuxhowtos.org/manpages/5/proc.htm
|
||||
int user;
|
||||
int nice;
|
||||
int system;
|
||||
int idle;
|
||||
int iowait;
|
||||
int irq;
|
||||
int softirq;
|
||||
int steal;
|
||||
int guest;
|
||||
int guest_nice;
|
||||
|
||||
int get_total_idle()
|
||||
const {
|
||||
return idle + iowait;
|
||||
}
|
||||
|
||||
int get_total_active()
|
||||
const {
|
||||
return user + nice + system + irq + softirq + steal + guest + guest_nice;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Memory_stats
|
||||
{
|
||||
int total_memory;
|
||||
int available_memory;
|
||||
int free_memory;
|
||||
int total_swap;
|
||||
int free_swap;
|
||||
|
||||
float get_memory_usage() {
|
||||
const float result = static_cast<float>(total_memory - available_memory) / total_memory;
|
||||
return result;
|
||||
}
|
||||
|
||||
float get_swap_usage() {
|
||||
const float result = static_cast<float>(total_swap - free_swap) / total_swap;
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline CPU_stats read_cpu_data()
|
||||
{
|
||||
CPU_stats result;
|
||||
std::ifstream proc_stat("/proc/stat");
|
||||
|
||||
if (proc_stat.good())
|
||||
{
|
||||
std::string line;
|
||||
getline(proc_stat, line);
|
||||
|
||||
unsigned int *stats_p = (unsigned int *)&result;
|
||||
std::stringstream iss(line);
|
||||
std::string cpu;
|
||||
iss >> cpu;
|
||||
while (iss >> *stats_p)
|
||||
{
|
||||
stats_p++;
|
||||
};
|
||||
}
|
||||
|
||||
proc_stat.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline int get_val(const std::string &target, const std::string &content) {
|
||||
int result = -1;
|
||||
std::size_t start = content.find(target);
|
||||
if (start != std::string::npos) {
|
||||
int begin = start + target.length();
|
||||
std::size_t end = content.find("kB", start);
|
||||
std::string substr = content.substr(begin, end - begin);
|
||||
result = std::stoi(substr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Memory_stats read_memory_data()
|
||||
{
|
||||
Memory_stats result;
|
||||
std::ifstream proc_meminfo("/proc/meminfo");
|
||||
|
||||
if (proc_meminfo.good())
|
||||
{
|
||||
std::string content((std::istreambuf_iterator<char>(proc_meminfo)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
result.total_memory = get_val("MemTotal:", content);
|
||||
result.free_memory = get_val("MemFree:", content);
|
||||
result.total_swap = get_val("SwapTotal:", content);
|
||||
result.free_swap = get_val("SwapFree:", content);
|
||||
result.available_memory = get_val("MemAvailable:", content);
|
||||
|
||||
}
|
||||
|
||||
proc_meminfo.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline float get_cpu_usage(const CPU_stats &first, const CPU_stats &second) {
|
||||
const float active_time = static_cast<float>(second.get_total_active() - first.get_total_active());
|
||||
const float idle_time = static_cast<float>(second.get_total_idle() - first.get_total_idle());
|
||||
const float total_time = active_time + idle_time;
|
||||
return active_time / total_time;
|
||||
}
|
||||
|
||||
inline float get_disk_usage(const std::string & disk) {
|
||||
struct statvfs diskData;
|
||||
|
||||
statvfs(disk.c_str(), &diskData);
|
||||
|
||||
auto total = diskData.f_blocks;
|
||||
auto free = diskData.f_bfree;
|
||||
auto diff = total - free;
|
||||
|
||||
float result = static_cast<float>(diff) / total;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//see https://unix.stackexchange.com/questions/304845/discrepancy-between-number-of-cores-and-thermal-zones-in-sys-class-thermal/342023
|
||||
|
||||
inline int find_thermalzone_index() {
|
||||
int result = 0;
|
||||
bool stop = false;
|
||||
// 20 must stop anyway
|
||||
for (int i = 0; !stop && i < 20; ++i) {
|
||||
std::ifstream thermal_file("/sys/class/thermal/thermal_zone" + std::to_string(i) + "/type");
|
||||
|
||||
if (thermal_file.good())
|
||||
{
|
||||
std::string line;
|
||||
getline(thermal_file, line);
|
||||
|
||||
if (line.compare("x86_pkg_temp") == 0) {
|
||||
result = i;
|
||||
stop = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
|
||||
thermal_file.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline int get_thermalzone_temperature(int thermal_index) {
|
||||
int result = -1;
|
||||
std::ifstream thermal_file("/sys/class/thermal/thermal_zone" + std::to_string(thermal_index) + "/temp");
|
||||
|
||||
if (thermal_file.good())
|
||||
{
|
||||
std::string line;
|
||||
getline(thermal_file, line);
|
||||
|
||||
std::stringstream iss(line);
|
||||
iss >> result;
|
||||
} else {
|
||||
throw std::invalid_argument(std::to_string(thermal_index) + " doesn't refer to a valid thermal zone.");
|
||||
}
|
||||
|
||||
thermal_file.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
711
util/structs/ParamStruct.h
Normal file
711
util/structs/ParamStruct.h
Normal file
|
|
@ -0,0 +1,711 @@
|
|||
#ifndef PARAMSTRUCT_H
|
||||
#define PARAMSTRUCT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Application.h"
|
||||
#include "util/xpack/json.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
namespace Structs
|
||||
{
|
||||
struct Channel_stream
|
||||
{
|
||||
std::string sn;
|
||||
int enable = 0;
|
||||
std::string name;
|
||||
std::string appname;
|
||||
std::string streamid;
|
||||
int bitrate = 8192;
|
||||
std::string bitrate_ctl;
|
||||
std::string codec;
|
||||
int encoded_size_mode = 0;
|
||||
std::string encoded_size;
|
||||
int fps = 30;
|
||||
int gopmode = 0;
|
||||
int goptxt = 30;
|
||||
int video_flip_mirror_enable = 0;
|
||||
int video_clipping_enable = 0;
|
||||
int video_clipping_left = 0;
|
||||
int video_clipping_right = 0;
|
||||
int video_clipping_width = 100;
|
||||
int video_clipping_height = 100;
|
||||
int video_rotate = 0;
|
||||
std::string pkey;
|
||||
std::string rtmp_url;
|
||||
std::string rtsp_url;
|
||||
std::string flv_url;
|
||||
std::string hls_url;
|
||||
std::string webrtc_url;
|
||||
std::string ts_url;
|
||||
std::string srt_url;
|
||||
std::string h5_url;
|
||||
int multicast_enable = 1;
|
||||
std::string multicast_ip_port;
|
||||
int push_enable = 1;
|
||||
std::string push_url;
|
||||
int push_connected = 0;
|
||||
Channel_stream() = default;
|
||||
|
||||
XPACK(O(enable, sn, name, appname, streamid, bitrate, bitrate_ctl, codec, encoded_size_mode, encoded_size, fps,
|
||||
gopmode, goptxt, video_flip_mirror_enable, video_clipping_enable, video_clipping_left, video_clipping_right,
|
||||
video_clipping_width, video_clipping_height, video_rotate, pkey, rtmp_url, rtsp_url, flv_url, hls_url,
|
||||
webrtc_url, ts_url, srt_url, multicast_enable, multicast_ip_port, push_enable, push_url),
|
||||
C(c_push_connected, F(0), push_connected))
|
||||
|
||||
template <class Decoder>
|
||||
bool c_push_connected_decode(Decoder& de, Channel_stream& t, const char* name, int& data, const xpack::Extend* ext)
|
||||
{
|
||||
(void)t;
|
||||
bool ret = false;
|
||||
try
|
||||
{
|
||||
std::string raw;
|
||||
ret = de.decode(name, raw, ext);
|
||||
if (ret)
|
||||
{
|
||||
sscanf(raw.c_str(), "%i", &data);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{ // TODO:如果原则本身就是整数,会转换失败,怎么办???
|
||||
ret = de.decode(name, data, ext);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class Encoder>
|
||||
bool c_push_connected_encode(Encoder& en, const Channel_stream& t, const char* name, const int& data,
|
||||
const xpack::Extend* ext)
|
||||
{
|
||||
(void)t;
|
||||
|
||||
bool ret = en.encode(name, data, ext);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct Channel_input_type_mix_layer
|
||||
{
|
||||
int chn_id = 0;
|
||||
int stream_id = 0;
|
||||
int audio_status = 0;
|
||||
float pos_x = 0.0f;
|
||||
float pos_y = 0.0f;
|
||||
float pos_w = 0.3333f;
|
||||
float pos_h = 0.3333f;
|
||||
int z_index = 0;
|
||||
Channel_input_type_mix_layer() = default;
|
||||
XPACK(O(chn_id, stream_id, audio_status, pos_x, pos_y, pos_w, pos_h, z_index))
|
||||
};
|
||||
|
||||
struct Channel_input_type_mix
|
||||
{
|
||||
std::string layout_id;
|
||||
std::vector<Channel_input_type_mix_layer> layers;
|
||||
Channel_input_type_mix() = default;
|
||||
XPACK(O(layout_id, layers))
|
||||
};
|
||||
|
||||
struct Channel_input_type_ndi
|
||||
{
|
||||
std::string ndirecv_name;
|
||||
Channel_input_type_ndi() = default;
|
||||
XPACK(O(ndirecv_name))
|
||||
};
|
||||
|
||||
struct Channel_input_type_net
|
||||
{
|
||||
int stream_mode = 0;
|
||||
int min_delay = 500;
|
||||
std::string path;
|
||||
int rtp_type = 0;
|
||||
std::string appname;
|
||||
std::string streamid;
|
||||
std::string push_remote_ip;
|
||||
std::string pull_path;
|
||||
int proxy_status;
|
||||
|
||||
int ipc_onvif = 0;
|
||||
std::string ipc_ip;
|
||||
int ipc_port = 8000;
|
||||
int ipc_web_port = 80;
|
||||
std::string ipc_username = "admin";
|
||||
std::string ipc_password;
|
||||
std::string ipc_ptz_xaddr;
|
||||
std::string ipc_ptz_profile_token;
|
||||
Channel_input_type_net() = default;
|
||||
XPACK(O(stream_mode, min_delay, path, rtp_type, pull_path, proxy_status, appname, streamid, push_remote_ip,
|
||||
ipc_onvif, ipc_ip, ipc_port, ipc_web_port, ipc_username, ipc_password, ipc_ptz_xaddr,
|
||||
ipc_ptz_profile_token))
|
||||
};
|
||||
|
||||
struct Channel_input_type_usb
|
||||
{
|
||||
std::string alsa;
|
||||
int channel = -1;
|
||||
std::string lnk;
|
||||
Channel_input_type_usb() = default;
|
||||
XPACK(O(alsa, channel, lnk))
|
||||
};
|
||||
|
||||
struct Channel_audio_set
|
||||
{
|
||||
std::vector<int> audio_src = {0};
|
||||
int audio_channel = 0;
|
||||
int digital_volume_gain = 0;
|
||||
int pts_offset = 0;
|
||||
int encoder_bitrate = 128;
|
||||
int encoder_methods = 0;
|
||||
int sampling_rate = -1;
|
||||
int collected_audio_frame = 0;
|
||||
Channel_audio_set() = default;
|
||||
XPACK(O(audio_src, audio_channel, digital_volume_gain, pts_offset, encoder_bitrate, encoder_methods, sampling_rate,
|
||||
collected_audio_frame))
|
||||
};
|
||||
|
||||
struct Channel_input_type_digimage_point
|
||||
{
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
Channel_input_type_digimage_point() = default;
|
||||
XPACK(O(x, y))
|
||||
};
|
||||
|
||||
struct Channel_input_type_digimage
|
||||
{
|
||||
int auto_update = 0;
|
||||
int tolerance = 0;
|
||||
int src_fg_channel = 0;
|
||||
std::string src_bg_type;
|
||||
std::string src_bg_image;
|
||||
int src_bg_channel = 0;
|
||||
std::vector<Channel_input_type_digimage_point> point;
|
||||
Channel_input_type_digimage() = default;
|
||||
XPACK(O(auto_update, tolerance, src_fg_channel, src_bg_type, src_bg_image, src_bg_channel, point))
|
||||
};
|
||||
|
||||
struct Channel_input_type_carousel_file
|
||||
{
|
||||
std::string filename;
|
||||
int video_len = 0;
|
||||
Channel_input_type_carousel_file() = default;
|
||||
XPACK(O(filename, video_len))
|
||||
};
|
||||
|
||||
struct Channel_input_type_carousel
|
||||
{
|
||||
int decodeA = 0;
|
||||
int decodeV = 0;
|
||||
int playing_file_index = -1;
|
||||
long playing_file_position = 0;
|
||||
std::vector<Channel_input_type_carousel_file> files;
|
||||
Channel_input_type_carousel() = default;
|
||||
XPACK(O(decodeA, decodeV, files), C(c_playing_file_index, F(0), playing_file_index))
|
||||
|
||||
template <class Decoder>
|
||||
bool c_playing_file_index_decode(Decoder& de, Channel_input_type_carousel& t, const char* name, int& data,
|
||||
const xpack::Extend* ext)
|
||||
{
|
||||
(void)t;
|
||||
bool ret = false;
|
||||
try
|
||||
{
|
||||
std::string raw;
|
||||
ret = de.decode(name, raw, ext);
|
||||
if (ret)
|
||||
{
|
||||
sscanf(raw.c_str(), "%i", &data);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{ // TODO:如果原则本身就是整数,会转换失败,怎么办???
|
||||
ret = de.decode(name, data, ext);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class Encoder>
|
||||
bool c_playing_file_index_encode(Encoder& en, const Channel_input_type_carousel& t, const char* name,
|
||||
const int& data, const xpack::Extend* ext)
|
||||
{
|
||||
(void)t;
|
||||
|
||||
bool ret = en.encode(name, data, ext);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct Channel_channel
|
||||
{
|
||||
int enable = 0;
|
||||
std::string name = "HDMI";
|
||||
std::string input_type = "HDMI";
|
||||
int input_video_framerate = 0;
|
||||
std::string input_video_size;
|
||||
int input_video_collected_frame = 0;
|
||||
int input_video_lost_frame = 0;
|
||||
Channel_audio_set audio_set;
|
||||
std::vector<Channel_stream> streams;
|
||||
Channel_input_type_digimage input_type_digimage;
|
||||
Channel_input_type_carousel input_type_carousel;
|
||||
Channel_input_type_mix input_type_mix;
|
||||
Channel_input_type_ndi input_type_ndi;
|
||||
Channel_input_type_net input_type_net;
|
||||
Channel_input_type_usb input_type_usb;
|
||||
Channel_channel() = default;
|
||||
XPACK(O(enable, name, input_type, input_video_framerate, input_video_size, input_video_collected_frame,
|
||||
input_video_lost_frame, audio_set, streams, input_type_digimage, input_type_carousel, input_type_mix,
|
||||
input_type_ndi, input_type_net, input_type_usb))
|
||||
};
|
||||
|
||||
struct Channel_params
|
||||
{
|
||||
std::vector<Channel_channel> channels;
|
||||
Channel_params() = default;
|
||||
XPACK(O(channels))
|
||||
};
|
||||
|
||||
struct Record_record
|
||||
{
|
||||
int enable = 0;
|
||||
int flv = 0;
|
||||
int mp4 = 1;
|
||||
int mp4_max_second = 600;
|
||||
int status = 0;
|
||||
|
||||
std::string start_time;
|
||||
|
||||
Record_record() = default;
|
||||
XPACK(O(enable, flv, mp4, mp4_max_second, status, start_time))
|
||||
};
|
||||
|
||||
struct Record_params
|
||||
{
|
||||
std::string base_path;
|
||||
int loop_storage_enable = 0;
|
||||
int loop_storage_min_size = 1024;
|
||||
std::vector<std::vector<Record_record>> records;
|
||||
|
||||
Record_params() = default;
|
||||
XPACK(O(base_path, loop_storage_enable, loop_storage_min_size, records))
|
||||
};
|
||||
|
||||
struct Gb28181_chn
|
||||
{
|
||||
int enable = 0;
|
||||
std::string gb_chn_id;
|
||||
std::string gb_chn_name;
|
||||
int stream_state = 0;
|
||||
Gb28181_chn() = default;
|
||||
XPACK(O(enable, gb_chn_id, gb_chn_name, stream_state))
|
||||
};
|
||||
|
||||
struct Gb28181_params
|
||||
{
|
||||
int enable = 0;
|
||||
std::string spec_model = "H.264/H.265 Encoder";
|
||||
std::string manufacture = "Encoder";
|
||||
int local_sip_port = 5061;
|
||||
int con_state = 0;
|
||||
std::string auth_id;
|
||||
std::string auth_passwd;
|
||||
int heartbeat_cycle = 30;
|
||||
int heartbeat_timeout_cnt = 3;
|
||||
int registration_period = 86400;
|
||||
std::string sip_server_addr;
|
||||
std::string sip_server_domain;
|
||||
std::string sip_server_id;
|
||||
int sip_server_port = 5060;
|
||||
std::vector<std::vector<Gb28181_chn>> gb28181_chns;
|
||||
Gb28181_params() = default;
|
||||
XPACK(O(enable, spec_model, manufacture, local_sip_port, con_state, auth_id, auth_passwd, heartbeat_cycle,
|
||||
heartbeat_timeout_cnt, registration_period, sip_server_addr, sip_server_domain, sip_server_id,
|
||||
sip_server_port, gb28181_chns))
|
||||
};
|
||||
|
||||
struct Loopout_audio
|
||||
{
|
||||
int enable = 1;
|
||||
int chn_id = 0;
|
||||
|
||||
int audio_volume_gain;
|
||||
Loopout_audio() = default;
|
||||
XPACK(O(enable, chn_id, audio_volume_gain))
|
||||
};
|
||||
struct Loopout_video
|
||||
{
|
||||
int enable = 1;
|
||||
int low_latency = 0;
|
||||
std::string encoded_size;
|
||||
int rotate = 0;
|
||||
int mirror = 0;
|
||||
int chn_id = 0;
|
||||
int stream_id = 0;
|
||||
std::string type;
|
||||
int ui = 0;
|
||||
int vid = 0;
|
||||
std::string matrix;
|
||||
int luma = 64;
|
||||
int contrast = 64;
|
||||
int saturation = 64;
|
||||
int hue = 64;
|
||||
int audio_volume_gain;
|
||||
Loopout_video() = default;
|
||||
XPACK(O(enable, low_latency, encoded_size, rotate, mirror, chn_id, stream_id, type, ui, vid, matrix, luma, contrast,
|
||||
saturation, hue, audio_volume_gain))
|
||||
};
|
||||
|
||||
struct Loopout_params
|
||||
{
|
||||
Loopout_audio audio;
|
||||
Loopout_video hdmi;
|
||||
Loopout_video sdi;
|
||||
Loopout_params() = default;
|
||||
XPACK(O(hdmi, sdi))
|
||||
};
|
||||
|
||||
struct Mix_lay_def_layer
|
||||
{
|
||||
int chn_id = -1;
|
||||
int stream_id = 0;
|
||||
int audio_status = 0;
|
||||
int lock = 0;
|
||||
float pos_x = 0.0f;
|
||||
float pos_y = 0.0f;
|
||||
float pos_w = 0.3333f;
|
||||
float pos_h = 0.3333f;
|
||||
int z_index = 0;
|
||||
Mix_lay_def_layer() = default;
|
||||
XPACK(O(chn_id, stream_id, audio_status, lock, pos_x, pos_y, pos_w, pos_h, z_index))
|
||||
};
|
||||
|
||||
struct Mix_lay_def_layout
|
||||
{
|
||||
std::string layout_id;
|
||||
std::string layout_name;
|
||||
int enable = 1;
|
||||
std::vector<Mix_lay_def_layer> layers;
|
||||
Mix_lay_def_layout() = default;
|
||||
XPACK(O(layout_id, layout_name, layers))
|
||||
};
|
||||
|
||||
struct Mix_lay_def
|
||||
{
|
||||
std::vector<Mix_lay_def_layout> layouts;
|
||||
Mix_lay_def() = default;
|
||||
XPACK(O(layouts))
|
||||
};
|
||||
|
||||
struct Osd_osd
|
||||
{
|
||||
int enable = 0;
|
||||
int chn_id = 0;
|
||||
int stream_id = 0;
|
||||
std::string type = "pic";
|
||||
std::string content;
|
||||
std::string font;
|
||||
std::string color;
|
||||
std::string bgcolor;
|
||||
float alpha = 0;
|
||||
float scale = 0;
|
||||
int speed = 0;
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
int z = 0;
|
||||
float w = 0;
|
||||
float h = 0;
|
||||
Osd_osd() = default;
|
||||
XPACK(O(enable, chn_id, stream_id, type, content, font, color, bgcolor, alpha, scale, speed, x, y, z, w, h))
|
||||
};
|
||||
|
||||
struct Osd_resource
|
||||
{
|
||||
std::string path;
|
||||
std::string time;
|
||||
std::string type;
|
||||
Osd_resource() = default;
|
||||
XPACK(O(path, time, type))
|
||||
};
|
||||
|
||||
struct Osd_params
|
||||
{
|
||||
std::vector<std::vector<std::vector<Osd_osd>>> osds;
|
||||
std::vector<Osd_resource> resources;
|
||||
Osd_params() = default;
|
||||
XPACK(O(osds, resources))
|
||||
};
|
||||
|
||||
struct Push_url
|
||||
{
|
||||
int enable = 0;
|
||||
std::string des;
|
||||
std::string url;
|
||||
int stream_state = 0;
|
||||
|
||||
Push_url() = default;
|
||||
XPACK(O(enable, des, url, stream_state))
|
||||
};
|
||||
|
||||
struct Push_params
|
||||
{
|
||||
int srcA = -1;
|
||||
int srcV = 0;
|
||||
int srcV_stream = 0;
|
||||
int autorun = 0;
|
||||
std::string start_day;
|
||||
std::string start_time;
|
||||
std::string stop_day;
|
||||
std::string stop_time;
|
||||
std::vector<Push_url> urls;
|
||||
Push_params() = default;
|
||||
XPACK(O(srcA, srcV, srcV_stream, autorun, start_day, start_time, stop_day, stop_time, urls))
|
||||
};
|
||||
|
||||
struct Status_params
|
||||
{
|
||||
std::string version;
|
||||
std::string image_version;
|
||||
std::string serial_num;
|
||||
float cpu_usage = 0;
|
||||
float cpu_junc_tmp = 0;
|
||||
float memory_free = 0;
|
||||
float memory_total = 0;
|
||||
std::string runtime;
|
||||
std::string device_time;
|
||||
int net_state_up = 0;
|
||||
int net_state_dw = 0;
|
||||
std::string fireware_download_url;
|
||||
std::string fireware_upgrade_last_log;
|
||||
Status_params() = default;
|
||||
XPACK(O(version, serial_num, cpu_usage, cpu_junc_tmp, memory_free, memory_total, runtime, device_time, net_state_up,
|
||||
net_state_dw, fireware_download_url, fireware_upgrade_last_log))
|
||||
};
|
||||
|
||||
struct System_http
|
||||
{
|
||||
std::string user_name;
|
||||
std::string user_password;
|
||||
std::string language = "zh";
|
||||
int api_auth = 0;
|
||||
System_http() = default;
|
||||
XPACK(O(user_name, user_password, language, api_auth))
|
||||
};
|
||||
|
||||
struct System_service_ports
|
||||
{
|
||||
int nat_port_enable = 0;
|
||||
std::string nat_port_host = "";
|
||||
int http_api_port = 22112;
|
||||
int http_api_port_nat_port = 22112;
|
||||
int http_port = 80;
|
||||
int http_port_nat_port = 80;
|
||||
int rtmp_port = 1935;
|
||||
int rtmp_port_nat_port = 1935;
|
||||
int rtsp_port = 554;
|
||||
int rtsp_port_nat_port = 554;
|
||||
int srt_port = 9000;
|
||||
int srt_port_nat_port = 9000;
|
||||
int nat_frp_enable = 0;
|
||||
int nat_frp_pid = 0;
|
||||
System_service_ports() = default;
|
||||
XPACK(O(nat_port_enable, nat_port_host, http_api_port, http_api_port_nat_port, http_port, http_port_nat_port,
|
||||
rtmp_port, rtmp_port_nat_port, rtsp_port, rtsp_port_nat_port, srt_port, srt_port_nat_port, nat_frp_enable,
|
||||
nat_frp_pid))
|
||||
};
|
||||
|
||||
struct System_share_storage_cifs
|
||||
{
|
||||
int enable = 0;
|
||||
std::string ip;
|
||||
std::string path;
|
||||
std::string username;
|
||||
std::string password;
|
||||
std::string local_path = "/mnt/storages/cifs";
|
||||
std::string vers = "2.0";
|
||||
System_share_storage_cifs() = default;
|
||||
XPACK(O(enable, ip, path, username, password, local_path, vers))
|
||||
};
|
||||
|
||||
struct System_share_storage_nfs
|
||||
{
|
||||
int enable = 0;
|
||||
std::string ip;
|
||||
std::string path;
|
||||
std::string local_path = "/mnt/stroages/nfs";
|
||||
std::string vers = "4";
|
||||
System_share_storage_nfs() = default;
|
||||
XPACK(O(enable, ip, path, local_path, vers))
|
||||
};
|
||||
|
||||
struct System_share_storage
|
||||
{
|
||||
System_share_storage_cifs cifs;
|
||||
System_share_storage_nfs nfs;
|
||||
System_share_storage() = default;
|
||||
XPACK(O(cifs, nfs))
|
||||
};
|
||||
|
||||
struct Network_set_config
|
||||
{
|
||||
int enable = 0;
|
||||
int dhcp_enable = 0;
|
||||
std::string host_ip;
|
||||
std::string mac_addr;
|
||||
std::string netmask;
|
||||
std::string gateway;
|
||||
std::string dns1;
|
||||
std::string dns2;
|
||||
std::string ssid;
|
||||
std::string ssid_pwd;
|
||||
std::string ssid_mode = "STA";
|
||||
Network_set_config() = default;
|
||||
XPACK(O(enable, dhcp_enable, host_ip, mac_addr, netmask, gateway, dns1, dns2, ssid, ssid_pwd, ssid_mode))
|
||||
};
|
||||
|
||||
struct Network_set
|
||||
{
|
||||
Network_set_config eth0;
|
||||
Network_set_config wlan0;
|
||||
Network_set() = default;
|
||||
XPACK(O(eth0, wlan0))
|
||||
};
|
||||
|
||||
struct Time_set
|
||||
{
|
||||
int ntp_enable = 1;
|
||||
std::string ntp_server = "ntp.ntsc.ac.cn";
|
||||
int ntp_server_port = 123;
|
||||
int ntp_idle = 60;
|
||||
std::string time_zone = "8";
|
||||
Time_set() = default;
|
||||
XPACK(O(ntp_enable, ntp_server, ntp_server_port, ntp_idle, time_zone))
|
||||
};
|
||||
|
||||
struct Schedule_restart
|
||||
{
|
||||
int restart_enable = 0;
|
||||
std::string restart_time = "06:10";
|
||||
Schedule_restart() = default;
|
||||
XPACK(O(restart_enable, restart_time))
|
||||
};
|
||||
|
||||
struct System_serialtrans
|
||||
{
|
||||
std::string type = "232";
|
||||
int work_mode = 0;
|
||||
int baudrate = 9600;
|
||||
std::string remote_addr;
|
||||
int remote_port = 10000;
|
||||
int listen_port = 10000;
|
||||
System_serialtrans() = default;
|
||||
XPACK(O(type, work_mode, baudrate, remote_addr, remote_port, listen_port))
|
||||
};
|
||||
|
||||
struct System_nattraversal_frp
|
||||
{
|
||||
int enable = 0;
|
||||
std::string remote_addr;
|
||||
int remote_port = 10001;
|
||||
int listen_port = 10001;
|
||||
System_nattraversal_frp() = default;
|
||||
XPACK(O(enable, remote_addr, remote_port, listen_port))
|
||||
};
|
||||
|
||||
struct System_nattraversal_rtty
|
||||
{
|
||||
int enable = 0;
|
||||
std::string name;
|
||||
std::string remote_addr;
|
||||
std::string id = "dfdfdsfdfdsfds";
|
||||
std::string token;
|
||||
System_nattraversal_rtty() = default;
|
||||
XPACK(O(enable, name, remote_addr, id, token))
|
||||
};
|
||||
|
||||
struct System_nattraversal
|
||||
{
|
||||
System_nattraversal_frp frp;
|
||||
System_nattraversal_rtty rtty;
|
||||
XPACK(O(frp, rtty))
|
||||
};
|
||||
|
||||
struct System_moresettings
|
||||
{
|
||||
std::string logo_title = "H.265/H.264 Encoder";
|
||||
std::string logo_image;
|
||||
std::string menu_location = "left";
|
||||
std::string h5play_title = "";
|
||||
int screen_turn_time = 5;
|
||||
System_moresettings() = default;
|
||||
XPACK(O(logo_title, logo_image, menu_location, h5play_title, screen_turn_time))
|
||||
};
|
||||
|
||||
struct System_params
|
||||
{
|
||||
System_http http;
|
||||
Network_set network_set;
|
||||
Time_set time_set;
|
||||
Schedule_restart schedule_restart;
|
||||
std::vector<System_serialtrans> serialtrans;
|
||||
System_nattraversal nattraversal;
|
||||
System_moresettings moresettings;
|
||||
System_service_ports service_ports;
|
||||
System_share_storage share_storage;
|
||||
System_params() = default;
|
||||
XPACK(O(http, network_set, time_set, schedule_restart, serialtrans, nattraversal, moresettings, service_ports,
|
||||
share_storage))
|
||||
};
|
||||
|
||||
struct Onvif_chn
|
||||
{
|
||||
uint32_t enable = 1;
|
||||
|
||||
Onvif_chn() = default;
|
||||
XPACK(O(enable))
|
||||
};
|
||||
|
||||
struct Onvif_params
|
||||
{
|
||||
int auth_enable = 0;
|
||||
std::string auth_username = "admin";
|
||||
std::string auth_password = "admin";
|
||||
int time_sync_enable = 0;
|
||||
uint32_t enable = 1;
|
||||
std::string device_name = "H.264/H.265 Encoder";
|
||||
std::string spec_model = "H.264/H.265 Encoder";
|
||||
std::string manufacture = "DaweiVision";
|
||||
std::string firmware_version;
|
||||
std::string serial_number;
|
||||
std::string hardware_id = "1.0";
|
||||
std::string device_type = "Encoder";
|
||||
std::string ip;
|
||||
std::string mac;
|
||||
uint web_service_bind_port = 8000;
|
||||
std::string location_country = "China";
|
||||
std::string location_city = "Chengdu";
|
||||
std::vector<std::vector<Onvif_chn>> chns;
|
||||
|
||||
Onvif_params() = default;
|
||||
XPACK(O(auth_enable, auth_username, auth_password, time_sync_enable, enable, device_name, spec_model, manufacture,
|
||||
firmware_version, serial_number, hardware_id, device_type, ip, mac, web_service_bind_port, location_country,
|
||||
location_city, chns))
|
||||
};
|
||||
|
||||
struct Diskinfo
|
||||
{
|
||||
int status = 0;
|
||||
std::string device = "";
|
||||
std::string path = "";
|
||||
unsigned long long total = 0;
|
||||
unsigned long long used = 0;
|
||||
unsigned long long available = 0;
|
||||
unsigned long long free = 0;
|
||||
|
||||
Diskinfo() = default;
|
||||
XPACK(O(status, device, path, total, used, available, free))
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
3
util/util.cmake
Normal file
3
util/util.cmake
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
add_subdirectory(util)
|
||||
include_directories(util)
|
||||
target_link_libraries(${PROJNAME} PRIVATE util)
|
||||
201
util/xpack/LICENSE
Executable file
201
util/xpack/LICENSE
Executable file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
84
util/xpack/README-bson.md
Executable file
84
util/xpack/README-bson.md
Executable file
|
|
@ -0,0 +1,84 @@
|
|||
* 用于在C++结构体和bson之间互相转换
|
||||
* 这个库可以配合[mongoxclient](https://github.com/xyz347/mongoxclient)使用
|
||||
|
||||
# 目录
|
||||
- [encoder](#encoder)
|
||||
- [decoder](#decoder)
|
||||
- [bson types](#bsontypes)
|
||||
- [builder](#builder)
|
||||
- [重要说明](#重要说明)
|
||||
|
||||
## encoder
|
||||
用于将结构体转成bson格式。范例:
|
||||
```C++
|
||||
struct Test {
|
||||
int64_t id;
|
||||
std::string name;
|
||||
std::string email;
|
||||
XPACK(A(id, "bson:_id"), O(name, email));
|
||||
};
|
||||
|
||||
Test t;
|
||||
std::string data = xpack::bson::encode(t); // data就是t转成bson的数据
|
||||
```
|
||||
|
||||
## decoder
|
||||
用于将bson数据转成结构体
|
||||
用于将结构体转成bson格式。范例:
|
||||
```C++
|
||||
struct Test {
|
||||
int64_t id;
|
||||
std::string name;
|
||||
std::string email;
|
||||
XPACK(A(id, "bson:_id"), O(name, email));
|
||||
};
|
||||
|
||||
std::string data;
|
||||
// data = xxxx; data存储了相应的bson数据
|
||||
Test t;
|
||||
xpack::bson::decode(data, t);
|
||||
// xpack::bson::decode 还有另一个参数方式:static void decode(const uint8_t* data, size_t len, T &val)
|
||||
```
|
||||
|
||||
## bsontypes
|
||||
- date time: `bson_date_time_t`
|
||||
- timestamp: `bson_timestamp_t`
|
||||
- binary: `bson_binary_t`
|
||||
- regex: `bson_regex_t`
|
||||
- oid: `bson_oid_t`
|
||||
- decimal128: `bson_decimal128_t`
|
||||
|
||||
前4种是xbson额外定义的,后面两种是定义在libbson内的,为了统一,前4种也是定义在全局命名空间。
|
||||
|
||||
## builder
|
||||
**需要C++11或以上版本支持**。用json的格式来构造bson数据。查询接口中的query,一般只需要指定很少几个字段,这个场景用结构体表达不是很方便。用builder就会简单很多。基本用法是:
|
||||
1. 定义一个BsonBuilder:
|
||||
- 参数是一个json格式的字符串
|
||||
- 里面的双引号用单引号替代
|
||||
- 变量用问号作为占位符,问号后面可以加一个单词用来作为助记符,比如"?"和"?uid"是等效的
|
||||
- key也可以是变量,key作为变量,问号不用加引号
|
||||
- BsonBuilder是线程安全的,建议定义为static变量,这样json字符串只需解析一次
|
||||
范例:
|
||||
```C++
|
||||
static xpack::BsonBuilder bd("{'_id':?, ?:?}"); // 带占位符的builder
|
||||
static xpack::BsonBuilder empty("{}"); // 空bson
|
||||
static xpack::BsonBuilder student("{'type':'student'}"); // 不带占位符的builder
|
||||
```
|
||||
|
||||
2. 调用Encode函数来构造bson数据,Encode的参数对应的是各个占位符,因此参数个数应该和占位符一致
|
||||
比如对于上述的BsonBuilder
|
||||
```C++
|
||||
std::string data1 = bd.Encode(12345, "type", "master");
|
||||
std::string data2 = empty.Encode();
|
||||
std::string data3 = student.Encode();
|
||||
// 这些bson的数据可以用在mongoxclient的各个接口中
|
||||
```
|
||||
|
||||
3. 其他的一些API
|
||||
- EncodeAsJson 和Encode类似,但是输出的是json格式的数据,可以用于调试等场景(所以这个其实也是个JsonBuilder)
|
||||
- Error 如果构造BsonBuilder的json字符串有误,这个接口可以返回错误信息
|
||||
- static std::string En(const std::string&fmt, Args... args)。这个是把构造BsonBuilder和Encode合在一起了,不是很建议使用,建议用于调试,因为每次都要构造一次BsonBuilder
|
||||
|
||||
|
||||
## 重要说明
|
||||
- 依赖于[libbson](https://github.com/mongodb/libbson/tree/1.0.0),需自行安装
|
||||
407
util/xpack/README-en.md
Executable file
407
util/xpack/README-en.md
Executable file
|
|
@ -0,0 +1,407 @@
|
|||
xpack
|
||||
====
|
||||
* Used to convert between C++ structure and json/xml, bson is supported in [xbson](https://github.com/xyz347/xbson).
|
||||
* Only header files, no need to compile library files, so there is no Makefile.
|
||||
* Support MySQL, depends on `libmysqlclient-dev`, need to install by yourself. **not fully tested**
|
||||
* Support Sqlite, depends on [libsqlite3](https://cppget.org/libsqlite3), need to install it yourself. **not fully tested**
|
||||
* Support yaml, depend on [yaml-cpp](https://github.com/jbeder/yaml-cpp), need to install it yourself. **not fully tested**
|
||||
* For details, please refer to the example
|
||||
|
||||
------
|
||||
* [Quick start](#quick-start)
|
||||
* [Container Support](#container-support)
|
||||
* [FLAG](#flag)
|
||||
* [Alias](#alias)
|
||||
* [Bitfield](#bitfield)
|
||||
* [Inherit](#inherit)
|
||||
* [enum](#enum)
|
||||
* [Custom codec](#custom-codec)
|
||||
* [union](#union)
|
||||
* [Schema indeterminate type](#schema-indeterminate-type)
|
||||
* [Define macro outside the structure](#define-macro-outside-the-structure)
|
||||
* [Array](#array)
|
||||
* [Format indentation](#format-indentation)
|
||||
* [XML array](#xml-array)
|
||||
* [CDATA](#cdata)
|
||||
* [Qt support](#qt-support)
|
||||
* [Important note](#important-note)
|
||||
|
||||
Quick start
|
||||
----
|
||||
- Use macro `XPACK`(or `XPACK_OUT` if you don't want to change the structure) include structure members
|
||||
- Use xpack::json::encode to convert structure to json
|
||||
- Use xpack::json::decode to convert json to structure
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h" // include this header file for json or "xpack/xml.h" for xml
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct User {
|
||||
int id;
|
||||
string name;
|
||||
XPACK(O(id, name)); // Add XPACK at the end of structure, up to 99 'O' can be added, and each 'O' can contain up to 99 members
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
User u;
|
||||
string data = "{\"id\":12345, \"name\":\"xpack\"}";
|
||||
|
||||
xpack::json::decode(data, u); // json to structure
|
||||
cout<<u.id<<';'<<u.name<<endl;
|
||||
|
||||
string json = xpack::json::encode(u); // structure to json
|
||||
cout<<json<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Container Support
|
||||
----
|
||||
The following containers are currently supported (std)
|
||||
- vector
|
||||
- set
|
||||
- list
|
||||
- map<string, T>
|
||||
- map<integer, T> // only for json
|
||||
- unordered_map<string, T> (need C++11)
|
||||
- shared_ptr (need C++11)
|
||||
|
||||
FLAG
|
||||
----
|
||||
In the macro `XPACK`, variables need to be enclosed with letters, such as `XPACK(O(a,b))`, `XPACK` can contain multiple letters, and each letter can contain multiple variables. Currently supported letters are:
|
||||
- X Usage: X(F(flag1, flag2...), member1, member2,...) Multiple flags can be written in 'F', currently supported flags are:
|
||||
- 0 no flag
|
||||
- OE omitempty. When encoding, if the variable is 0 or an empty string or false, the variable is ignored
|
||||
- EN empty as null. When json encoding, encode empty variable as null(OE is ignore the variable)
|
||||
- M mandatory. When decoding, if the key corresponding to the variable does not exist, an exception is thrown
|
||||
- ATTR attribute. When xml encode, put the value in attribute
|
||||
- SL single line, When json encoding, put vector in single line
|
||||
- C Usage: C(customcodec, F(flag1,flags...), member1, member2,...) For custom codec function, please refer to [Custom codec](#custom-codec) for details
|
||||
- O Usage: O(member1, member2, ...) Same as X(F(0), member1, member2, ...) no flags
|
||||
- M Usage: M(member1, member2, ...) Same as X(F(M), member1, member2, ...) mandatory
|
||||
- A Usage: A(member1, alias1, member2, alias2...) Used when the key and the variable name are different, please refer to [Alias](#alias) for details
|
||||
- AF Usage: AF(F(flag1, flag2,...), member1, alias1, member2, alias2...) Alias with flags
|
||||
- B Usage: B(F(flag1, flag2, ...), member1, member2, ...) For bitfield, please refer to [Bitfield](#bitfield) for details. **bitfield not support alias**
|
||||
- I Usage: I(baseclass1, baseclass2....), baseclassx is parent class, please refer to [Inherit](#inherit) for details
|
||||
- E Usage: E(member1, member2) For enumeration variables that do not support C++11. **E not support alias**
|
||||
|
||||
Alias
|
||||
----
|
||||
- Used when the key and the variable name are different
|
||||
- Usage: A(member1, alias1, member2, alias2...) or AF(F(flag1, flag2,...), member1, alias1, member2, alias2...), alias's format is "x t:n"
|
||||
- x stands for global alias, not required
|
||||
- t stands for type(currently support json/xml/bson), n stands for type alias, type alias is not required
|
||||
- The order of precedence is: type alias, global alias, variable name
|
||||
- For example, `id bson:_id`, in bson will use `_id` and json/xml will use `id`
|
||||
- Type alias can take some type flags, format is "t:n,flag1,flag2,...", currently supported flags are:
|
||||
- cdata. For xml, indicates that it is cdata
|
||||
- sbs. For xml vector, In normal, `vector<int> nums` will be encoded into `<nums><nums>1</nums><nums>2</nums><nums>`, in sbs is `<nums>1</nums><nums>2</nums>`
|
||||
|
||||
``` C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(A(uid, "id"), O(name)); // "uid" use alias "id"
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.uid<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Bitfield
|
||||
----
|
||||
- Use 'B' include bitfield members. **bitfield not support alias**
|
||||
|
||||
``` C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
short ver:8;
|
||||
short len:8;
|
||||
string name;
|
||||
XPACK(B(F(0), ver, len), O(name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"ver\":4, \"len\":20, \"name\":\"IPv4\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.ver<<endl;
|
||||
cout<<t.len<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Inherit
|
||||
----
|
||||
- Use 'I' include parent classes. If you don't need variables from the parent class, you don't need use 'I'
|
||||
- Parent class need add macro XPACK/XPACK_OUT
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct P1 {
|
||||
string mail;
|
||||
XPACK(O(mail));
|
||||
};
|
||||
|
||||
struct P2 {
|
||||
long version;
|
||||
XPACK(O(version));
|
||||
};
|
||||
|
||||
struct Test:public P1, public P2 {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(I(P1, P2), O(uid, name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"mail\":\"pony@xpack.com\", \"version\":2019, \"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.mail<<endl;
|
||||
cout<<t.version<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
enum
|
||||
----
|
||||
- If support C++11, enum is same as other type, use X/O/M/A is ok
|
||||
- Otherwise need to use 'E', usage: E(F(...), member1, member2, ...)
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum Enum {
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2,
|
||||
};
|
||||
|
||||
struct Test {
|
||||
string name;
|
||||
Enum e;
|
||||
XPACK(O(name), E(F(0), e));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"name\":\"IPv4\", \"e\":1}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.e<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Custom codec
|
||||
----
|
||||
Used in scenarios where you want to define your own codec method, such as:
|
||||
- Wish to encode numeric types in string or hexadecimal
|
||||
- Don't want to encode the struct variable by variable:
|
||||
```C++
|
||||
struct Time {
|
||||
long ts; //unix timestamp
|
||||
};
|
||||
```
|
||||
Don't want to encode to {"ts":1218196800} but "2008-08-08 20:00:00"
|
||||
|
||||
There are two ways to achieve:
|
||||
- Use xtype. You can refer to this [example](example/xtype.cpp)
|
||||
- Use 'C' include members need to custome codec(Hereinafter referred to as the `C method`), You can refer to this [example](example/custom.cpp)
|
||||
|
||||
Both methods need to implement custom codec, but there are some differences:
|
||||
- xtype is at the type level, that is, once a certain type is encapsulated with xtype, the custom encode/decode will take effect for this type. xtype cannot be used for basic types (int/string, etc.)
|
||||
- The C method can support basic types (int/string, etc.) and non-basic types, but only works on variables contained in C, such as
|
||||
```C++
|
||||
int a;
|
||||
int b;
|
||||
XPACK(O(a), C(custome_int, F(0), b ))
|
||||
```
|
||||
Then "a" still uses the default codec, and "b" uses the custom codec.
|
||||
|
||||
1. xtype takes precedence over the XPACK macro, that is, if xtype is defined, the encode/decode of xtype will be used first
|
||||
2. The C method takes precedence over xtype, that is, the variables contained in C must use the codec method specified in C
|
||||
|
||||
With these two features, some more flexible codec control can be realized. For example, this [example](example/xtype_advance.cpp) realizes a function of encoding according to the variable situation. If Sub.type==1, then encode seq1, Otherwise encode seq2. `__x_pack_decode` and `__x_pack_encode` are the decode/encode functions added to the structure by the XPACK macro, and the custom codec function can call the default codec function of xpack through these functions.
|
||||
|
||||
union
|
||||
----
|
||||
Unions can be handled using [Custom codec](#custom-codec). You can refer to this [example](example/union1.cpp)
|
||||
|
||||
Array
|
||||
----
|
||||
- When decoding, if the number of elements exceeds the length of the array, it will be truncated
|
||||
- The char array needs to have a '\0' terminator
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Test {
|
||||
char name[64];
|
||||
char email[64];
|
||||
XPACK(O(name, email));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"name\":\"Pony\", \"email\":\"pony@xpack.com\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.email<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Schema indeterminate type
|
||||
----
|
||||
- Json only
|
||||
- Use [xpack::JsonData](json_data.h) for this kind of content
|
||||
- You can refer to this [example](example/json-data.cpp)
|
||||
- The main APIs for xpack::JsonData are:
|
||||
- Type. To get the field type
|
||||
- IsXXX. To check is the field type is xxx, same as `return Type()==xxxx;`
|
||||
- GetXXX. To get the field value
|
||||
- operator bool. To check is't a valid xpack::JsonData
|
||||
- Size. To get the array's elements number
|
||||
- `operator [](size_t index)`. Used to get the index element in array
|
||||
- `operator [](const char *key)`. Used to get the element by key in object
|
||||
- Iterator:
|
||||
- Begin. Get the first element's iterator
|
||||
- Next. Get the next iterator
|
||||
- Key. Get the key of iterator
|
||||
- Val. Get the value of iterator
|
||||
|
||||
Define macro outside the structure
|
||||
----
|
||||
- Use `XPACK_OUT` instead of `XPACK` to include structure members
|
||||
- `XPACK_OUT` must define in global namespace
|
||||
|
||||
```c++
|
||||
#include <sys/time.h>
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
struct timeval {
|
||||
time_t tv_sec;
|
||||
suseconds_t tv_usec;
|
||||
};
|
||||
*/
|
||||
|
||||
// timeval is thirdparty struct
|
||||
XPACK_OUT(timeval, O(tv_sec, tv_usec));
|
||||
|
||||
struct T {
|
||||
int a;
|
||||
string b;
|
||||
timeval t;
|
||||
XPACK(O(a, b, t));
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
T t;
|
||||
T r;
|
||||
t.a = 123;
|
||||
t.b = "xpack";
|
||||
t.t.tv_sec = 888;
|
||||
t.t.tv_usec = 999;
|
||||
string s = xpack::json::encode(t);
|
||||
cout<<s<<endl;
|
||||
xpack::json::decode(s, r);
|
||||
cout<<r.a<<','<<r.b<<','<<r.t.tv_sec<<','<<r.t.tv_usec<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Format indentation
|
||||
----
|
||||
- The default encode is not indented, and the readability is not good
|
||||
- If indentation is required, it can be controlled by the last two parameters of encode:
|
||||
- indentCount Indicates the number of characters for indentation, <0 means no indentation, 0 means newline but no indentation
|
||||
- indentChar Characters that represent indentation, use spaces or tabs
|
||||
|
||||
XML array
|
||||
----
|
||||
- Arrays use variable names as element labels by default, such as "ids":[1,2,3] will be encoded as:
|
||||
``` xml
|
||||
<ids>
|
||||
<ids>1</ids>
|
||||
<ids>2</ids>
|
||||
<ids>3</ids>
|
||||
</ids>
|
||||
```
|
||||
- You can use alias to change the label name. For example: A(ids,"xml:ids,vl@id"), vl@id means to use id as label:
|
||||
``` xml
|
||||
<ids>
|
||||
<id>1</id>
|
||||
<id>2</id>
|
||||
<id>3</id>
|
||||
</ids>
|
||||
```
|
||||
- If want to encode array element side by side, can use `sbs` flag. For example: `A(ids, "xml:ids,sbs")`. **Note that the sbs tag can only be used for arrays(vector), and it may crash if used elsewhere**
|
||||
``` xml
|
||||
<ids>1</ids>
|
||||
<ids>2</ids>
|
||||
<ids>3</ids>
|
||||
```
|
||||
|
||||
CDATA
|
||||
----
|
||||
- For xml CDATA, need to use `cdata` flag. For example: A(data, "xml:data,cdata")
|
||||
- variable type must be std::string
|
||||
- Non-cdata types can also add cdata flag, which will be processed as ordinary strings
|
||||
|
||||
Qt support
|
||||
----
|
||||
- Modify [config.h](config.h) to enable XPACK_SUPPORT_QT(or enable it in compile flags)
|
||||
- Currently supports: QString/QMap/QList/QVector
|
||||
|
||||
|
||||
Important note
|
||||
----
|
||||
- Try not to start the variable name with __x_pack, otherwise it may conflict with the library.
|
||||
- vc6 is not supported
|
||||
- msvc has only been tested on vs2019
|
||||
- The serialization and deserialization of json uses [rapidjson](https://github.com/Tencent/rapidjson) (November 2018 edition)
|
||||
- The deserialization of xml uses [rapidxml](http://rapidxml.sourceforge.net)
|
||||
- The serialization of xml is written by myself, without reference to RFC, there may be some differences from the standard.
|
||||
418
util/xpack/README.md
Executable file
418
util/xpack/README.md
Executable file
|
|
@ -0,0 +1,418 @@
|
|||
xpack
|
||||
====
|
||||
[English](README-en.md)
|
||||
* 用于在C++结构体和json/xml/yaml/bson/mysql/sqlite之间互相转换
|
||||
* 只有头文件, 无需编译库文件,所以也没有Makefile。
|
||||
* 支持bson,依赖于`libbson-1.0`,需自行安装。**未经充分测试**,具体请参考[README](README-bson.md)
|
||||
* 支持MySQL,依赖于`libmysqlclient-dev`,需自行安装。**未经充分测试**
|
||||
* 支持Sqlite,依赖于[libsqlite3](https://cppget.org/libsqlite3),需自行安装。**未经充分测试**
|
||||
* 支持yaml,依赖于[yaml-cpp](https://github.com/jbeder/yaml-cpp),需自行安装。**未经充分测试**
|
||||
* 具体可以参考example的例子
|
||||
|
||||
------
|
||||
* [基本用法](#基本用法)
|
||||
* [容器支持](#容器支持)
|
||||
* [FLAG](#flag)
|
||||
* [别名](#别名)
|
||||
* [位域](#位域)
|
||||
* [继承](#继承)
|
||||
* [枚举](#枚举)
|
||||
* [自定义编解码](#自定义编解码)
|
||||
* [union](#union)
|
||||
* [不定类型](#不定类型)
|
||||
* [数组](#数组)
|
||||
* [第三方类和结构体](#第三方类和结构体)
|
||||
* [格式化缩进](#格式化缩进)
|
||||
* [XML数组](#xml数组)
|
||||
* [CDATA](#cdata)
|
||||
* [Qt支持](#qt支持)
|
||||
* [MySQL](#mysql)
|
||||
* [重要说明](#重要说明)
|
||||
|
||||
基本用法
|
||||
----
|
||||
- 结构体后面用XPACK宏包含各个变量,XPACK内还需要一个字母,不同字母的意义请参考[FLAG](#flag)
|
||||
- 用xpack::json::encode把结构体转json
|
||||
- 用xpack::json::decode把json转结构体
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h" // Json包含这个头文件,xml则包含xpack/xml.h
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct User {
|
||||
int id;
|
||||
string name;
|
||||
XPACK(O(id, name)); // 添加宏定义XPACK在结构体定义结尾
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
User u;
|
||||
string data = "{\"id\":12345, \"name\":\"xpack\"}";
|
||||
|
||||
xpack::json::decode(data, u); // json转结构体
|
||||
cout<<u.id<<';'<<u.name<<endl;
|
||||
|
||||
string json = xpack::json::encode(u); // 结构体转json
|
||||
cout<<json<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
容器支持
|
||||
----
|
||||
目前支持下列容器(std)
|
||||
- vector
|
||||
- set
|
||||
- list
|
||||
- map<string, T>
|
||||
- map<integer, T> // 仅JSON,XML不支持
|
||||
- unordered_map<string, T> (需要C++11支持)
|
||||
- shared_ptr (需要C++11支持)
|
||||
|
||||
FLAG
|
||||
----
|
||||
宏XPACK里面,需要用字母将变量包含起来,比如XPACK(O(a,b)),XPACK可以包含多个字母,每个字母可以包含多个变量。目前支持的字母有:
|
||||
- X。格式是X(F(flag1, flag2...), member1, member2,...) F里面包含各种FLAG,目前支持的有:
|
||||
- 0 没有任何FLAG
|
||||
- OE omitempty,encode的时候,如果变量是0或者空字符串或者false,则不生成对应的key信息
|
||||
- EN empty as null, 用于json的encode,OE是直接不生成empty的字段,EN则是生成一个null
|
||||
- M mandatory,decode的时候,如果这个字段不存在,则抛出异常,用于一些id字段。
|
||||
- ATTR attribute,xml encode的时候,把值放到attribute里面。
|
||||
- SL single line, json encode的时候,对于数组,放在一行里面
|
||||
- C。格式是C(customcodec, F(flag1,flags...), member1, member2,...)用于自定义编解码函数,详情请参考[自定义编解码](#自定义编解码)
|
||||
- O。等价于X(F(0), ...) 没有任何FLAG。
|
||||
- M。等价于X(F(M),...) 表示这些字段是必须存在的。
|
||||
- A。[别名](#别名),A(member1, alias1, member2, alias2...),用于变量和key名不一样的情况
|
||||
- AF。带FLAG的[别名](#别名),AF(F(flag1, flag2,...), member1, alias1, member2, alias2...)
|
||||
- B。[位域](#位域),B(F(flag1, flag2, ...), member1, member2, ...) **位域不支持别名**
|
||||
- I。[继承](#继承),I(baseclass1, baseclass2....),里面放父类
|
||||
- E。[枚举](#枚举):
|
||||
- 如果编译器支持C++11,不需要用E,枚举可以放X/O/M/A里面。
|
||||
- 否则枚举只能放E里面,不支持别名
|
||||
|
||||
别名
|
||||
----
|
||||
- 用于变量名和key名不一致的场景
|
||||
- 格式是A(变量,别名....)或者AF(F(flags), 变量,别名....),别名的格式是"x t:n"的格式
|
||||
- x表示全局别名,t表示类型(目前支持json、xml、bson),n表示类型下的别名
|
||||
- 全局别名可以没有,比如`json:_id`是合法的
|
||||
- 类型别名可以没有,比如`_id`是合法的
|
||||
- 有类型别名优先用类型别名,否则用全局别名,都没有,则用变量名
|
||||
|
||||
``` C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(A(uid, "id"), O(name)); // "uid"的别名是"id"
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.uid<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
位域
|
||||
----
|
||||
- 使用"B"来包含位域变量,**位域不支持别名**
|
||||
|
||||
``` C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
short ver:8;
|
||||
short len:8;
|
||||
string name;
|
||||
XPACK(B(F(0), ver, len), O(name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"ver\":4, \"len\":20, \"name\":\"IPv4\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.ver<<endl;
|
||||
cout<<t.len<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
继承
|
||||
----
|
||||
- 使用"I"来包含父类。需要用到父类的变量就包含,用不到可以不包含。
|
||||
- 父类的父类也需要包含,比如class Base; class Base1:public Base; class Base2:public Base1;那么在Base2中需要I(Base1, Base)
|
||||
- 父类也需要定义XPACK/XPACK_OUT宏。
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct P1 {
|
||||
string mail;
|
||||
XPACK(O(mail));
|
||||
};
|
||||
|
||||
struct P2 {
|
||||
long version;
|
||||
XPACK(O(version));
|
||||
};
|
||||
|
||||
struct Test:public P1, public P2 {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(I(P1, P2), O(uid, name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"mail\":\"pony@xpack.com\", \"version\":2019, \"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.mail<<endl;
|
||||
cout<<t.version<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
枚举
|
||||
----
|
||||
- 如果编译器支持C++11,则枚举和普通变量名一样,放X/O/M/A里面皆可。
|
||||
- 否则需要放到E里面,格式是E(F(...), member1, member2, ...)
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum Enum {
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2,
|
||||
};
|
||||
|
||||
struct Test {
|
||||
string name;
|
||||
Enum e;
|
||||
XPACK(O(name), E(F(0), e));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"name\":\"IPv4\", \"e\":1}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.e<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
自定义编解码
|
||||
----
|
||||
应用场景
|
||||
- 有些基础类型想用自定义方式编码,比如用字符串的方式来编码整数/浮点数
|
||||
- 部分类型可能不想按结构体变量逐个编码,比如定义了一个时间结构体:
|
||||
```C++
|
||||
struct Time {
|
||||
long ts; //unix timestamp
|
||||
};
|
||||
```
|
||||
并不希望编码成{"ts":1218196800} 这种格式,而是希望编码成"2008-08-08 20:00:00"这种格式。
|
||||
|
||||
这里有两种方式:
|
||||
- 使用xtype,可以参考[例子](example/xtype.cpp)
|
||||
- 用C来包含需要自定义编解码的变量(下面简称C方法),可以参考[例子](example/custom.cpp)
|
||||
|
||||
两种方法本质上都是自己去实现encode/decode,但是有以下区别:
|
||||
- xtype是类型级别的,也就是一旦某个类型用xtype封装之后,那么自定义的encode/decode就对这个类型生效。xtype无法作用于基本类型(int/string等)
|
||||
- C方法能支持基本类型(int/string等)和非基本类型,但是仅作用于用C包含的变量,比如int a;int b; O(a), C(custome_int, F(0), b);那么a还是用默认的编解码,b才是用自定义的编解码。
|
||||
|
||||
1. xtype优先于XPACK宏,也就是定义了xtype的,会优先使用xtype的encode/decode
|
||||
2. C方法优先于xtype,也就是用C包含的变量,一定会用C里面指定的编解码方法。
|
||||
|
||||
用这两个特性,可以实现一些比较灵活的编解码控制,比如这个[例子](example/xtype_advance.cpp)实现了一个根据变量情况来编码的功能,如果Sub.type==1则encode seq1,否则encode seq2. `__x_pack_decode`和`__x_pack_encode`是XPACK宏给结构体添加的decode/encode函数,自定义编解码函数可以通过这些函数调用xpack默认的编解码功能。
|
||||
|
||||
union
|
||||
----
|
||||
可以使用[自定义编解码](#自定义编解码)来处理联合体,可以参考[范例](example/union1.cpp)
|
||||
|
||||
数组
|
||||
----
|
||||
- decode的时候如果元素个数超过数组的长度,会截断
|
||||
- char数组按有\0结束符处理
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Test {
|
||||
char name[64];
|
||||
char email[64];
|
||||
XPACK(O(name, email));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"name\":\"Pony\", \"email\":\"pony@xpack.com\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.email<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
不定类型
|
||||
----
|
||||
- 用于json的schema不确定的场景
|
||||
- 用[xpack::JsonData](json_data.h)来接收这些信息
|
||||
- 可以参考[例子](example/json-data.cpp)
|
||||
- xpack::JsonData主要的方法有:
|
||||
- Type。用于获取类型
|
||||
- IsXXX系列函数。用于判断是否是某种类型,基本等价于return Type()==xxxx;
|
||||
- GetXXX系列函数。用来提取值。
|
||||
- 重载bool。用来判断是否是一个合法的JsonData。
|
||||
- Size。用于数组类型判断元素的个数
|
||||
- `operator [](size_t index)` 用来取数组的第index个元素(从0开始)
|
||||
- `operator [](const char *key)` 用来根据key取Object类型的元素
|
||||
- Begin。用来遍历Object的元素,取第一个。
|
||||
- Next。配合Begin使用,获取下一个元素。
|
||||
- Key。配置Begin和Next使用,遍历的时候获取Key
|
||||
|
||||
第三方类和结构体
|
||||
----
|
||||
- 用XPACK_OUT而非XPACK来包含变量
|
||||
- XPACK_OUT必须定义在全局命名空间
|
||||
|
||||
```c++
|
||||
#include <sys/time.h>
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
struct timeval {
|
||||
time_t tv_sec;
|
||||
suseconds_t tv_usec;
|
||||
};
|
||||
*/
|
||||
|
||||
// timeval is thirdparty struct
|
||||
XPACK_OUT(timeval, O(tv_sec, tv_usec));
|
||||
|
||||
struct T {
|
||||
int a;
|
||||
string b;
|
||||
timeval t;
|
||||
XPACK(O(a, b, t));
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
T t;
|
||||
T r;
|
||||
t.a = 123;
|
||||
t.b = "xpack";
|
||||
t.t.tv_sec = 888;
|
||||
t.t.tv_usec = 999;
|
||||
string s = xpack::json::encode(t);
|
||||
cout<<s<<endl;
|
||||
xpack::json::decode(s, r);
|
||||
cout<<r.a<<','<<r.b<<','<<r.t.tv_sec<<','<<r.t.tv_usec<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
格式化缩进
|
||||
----
|
||||
- encode缺省生成的json/xml是没有缩进的,适合程序使用,如果让人读,可以进行缩进。
|
||||
- encode的最后两个参数控制
|
||||
- indentCount 表示缩进的字符数,<0表示不缩进,0则是换行但是不缩进
|
||||
- indentChar 表示缩进的字符,用空格或者制表符
|
||||
|
||||
XML数组
|
||||
----
|
||||
- 数组默认会用变量名作为元素的标签,比如"ids":[1,2,3],对应的xml是:
|
||||
``` xml
|
||||
<ids>
|
||||
<ids>1</ids>
|
||||
<ids>2</ids>
|
||||
<ids>3</ids>
|
||||
</ids>
|
||||
```
|
||||
- 可以用别名的方式来控制数组的元素的标签,比如A(ids,"xml:ids,vl@id"),vl后面跟着一个@xx,xx就是数组的标签,生成的结果就是:
|
||||
``` xml
|
||||
<ids>
|
||||
<id>1</id>
|
||||
<id>2</id>
|
||||
<id>3</id>
|
||||
</ids>
|
||||
```
|
||||
- 如果希望数组直接展开,而不是在外面包一层,可以用别名加"sbs"的flag来实现,比如A(ids, "xml:ids,sbs"),**注意,sbs标签仅能用于数组,其他地方使用可能会崩溃**
|
||||
``` xml
|
||||
<ids>1</ids>
|
||||
<ids>2</ids>
|
||||
<ids>3</ids>
|
||||
```
|
||||
|
||||
CDATA
|
||||
----
|
||||
- 对于CDATA类型,需要用"cdata"的flag来实现,比如A(data, "xml:data,cdata")
|
||||
- cdata只能用std::string来接收
|
||||
- 如果变量对应的xml不是CDATA结构,会按普通字符串来处理比如`<data>hello</data>`也可以解析成功
|
||||
|
||||
Qt支持
|
||||
----
|
||||
- 修改config.h,开启XPACK_SUPPORT_QT这个宏(或者在编译选项开启)
|
||||
- 当前支持 QString/QMap/QList/QVector
|
||||
|
||||
MySQL
|
||||
----
|
||||
- 目前仅支持decode,还不支持encode
|
||||
- 未经过完整测试,使用需要谨慎
|
||||
- 当前支持类型有:
|
||||
- string。简单测试。
|
||||
- 整型。简单测试。
|
||||
- 浮点型。未测试。
|
||||
- 用整型(比如time_t)接收TIME/DATETIME/TIMESTAMP。未测试。
|
||||
- 自定义类型转换,is_xpack_mysql_xtype,类似于xtype。未测试。
|
||||
- api有两个(xpack::mysql::) :
|
||||
- `static void decode(MYSQL_RES *result, T &val)`
|
||||
- 用来将MYSQL_RES转成结构体或者vector<>,如果是非vector,则只转换第一个row
|
||||
- `static void decode(MYSQL_RES *result, const std::string&field, T &val)`
|
||||
- 用来解析某个字段,用于只想获得某个字段内容的场景,比如select id from mytable where name = lilei,只想获得id信息。val支持vector
|
||||
|
||||
|
||||
重要说明
|
||||
----
|
||||
- 变量名尽量不要用__x_pack开头,不然可能会和库有冲突。
|
||||
- vc6不支持。
|
||||
- msvc没有做很多测试,只用2019做过简单测试。
|
||||
- json的序列化反序列化用的是[rapidjson](https://github.com/Tencent/rapidjson)
|
||||
- xml的反序列化用的是[rapidxml](http://rapidxml.sourceforge.net)
|
||||
- xml的序列化是我自己写的,没有参考RFC,可能有和标准不一样的地方.
|
||||
- 有疑问可以加QQ群878041110
|
||||
54
util/xpack/bson.h
Executable file
54
util/xpack/bson.h
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_BSON_H
|
||||
#define __X_PACK_BSON_H
|
||||
|
||||
#include "bson_decoder.h"
|
||||
#include "bson_encoder.h"
|
||||
#include "xpack.h"
|
||||
|
||||
#ifdef X_PACK_SUPPORT_CXX0X // support c++11 or later
|
||||
#include "bson_builder.h"
|
||||
#endif
|
||||
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class bson {
|
||||
public:
|
||||
template <class T>
|
||||
static void decode(const std::string &data, T &val) {
|
||||
BsonDecoder de;
|
||||
de.decode(data, val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void decode(const uint8_t* data, size_t len, T &val) {
|
||||
BsonDecoder de;
|
||||
de.decode(data, len, val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string encode(const T &val) {
|
||||
BsonEncoder en;
|
||||
return en.encode(val);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
588
util/xpack/bson_builder.h
Executable file
588
util/xpack/bson_builder.h
Executable file
|
|
@ -0,0 +1,588 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_BSON_BUILDER_H
|
||||
#define __X_PACK_BSON_BUILDER_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include "bson_encoder.h"
|
||||
|
||||
#ifndef X_PACK_SUPPORT_CXX0X // support c++11 or later
|
||||
#error "need c++11 or later"
|
||||
#endif
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class BsonBuilder {
|
||||
enum {
|
||||
Unknow = 0,
|
||||
ObjectBegin = 1<<0,
|
||||
ObjectEnd = 1<<1,
|
||||
ArrayBegin = 1<<2,
|
||||
ArrayEnd = 1<<3,
|
||||
Comma = 1<<4,
|
||||
Colon = 1<<5,
|
||||
Integer = 1<<6,
|
||||
Float = 1<<7,
|
||||
String = 1<<8,
|
||||
Bool = 1<<9,
|
||||
Variable = 1<<10,
|
||||
BEof = 1<<11
|
||||
};
|
||||
|
||||
std::string tokenName(int type) const {
|
||||
std::string ret;
|
||||
if (0 != (ObjectBegin&type)) {
|
||||
ret += "/{";
|
||||
}
|
||||
if (0 != (ObjectEnd&type)) {
|
||||
ret += "/}";
|
||||
}
|
||||
if (0 != (ArrayBegin&type)) {
|
||||
ret += "/[";
|
||||
}
|
||||
if (0 != (ArrayEnd&type)) {
|
||||
ret += "/]";
|
||||
}
|
||||
if (0 != (Comma&type)) {
|
||||
ret += "/,";
|
||||
}
|
||||
if (0 != (Colon&type)) {
|
||||
ret += "/:";
|
||||
}
|
||||
if (0 != ((Float|Integer|Bool)&type)) {
|
||||
ret += "/number/bool";
|
||||
}
|
||||
if (0 != (String&type)) {
|
||||
ret += "/string";
|
||||
}
|
||||
if (0 != (Variable&type)) {
|
||||
ret += "/variable";
|
||||
}
|
||||
|
||||
if (!ret.empty()) {
|
||||
ret = ret.substr(1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
struct Token {
|
||||
int type; // see enum
|
||||
union {
|
||||
const char *sval;
|
||||
long lval;
|
||||
double dval;
|
||||
bool bval;
|
||||
};
|
||||
Token():type(Unknow),sval(NULL){}
|
||||
};
|
||||
struct Item {
|
||||
Token tk;
|
||||
const char *key;
|
||||
bool kvar; // key is variable
|
||||
Item():tk(),key(NULL), kvar(false) {
|
||||
}
|
||||
};
|
||||
struct Encoder {
|
||||
const std::vector<const Item*>* items;
|
||||
BsonWriter wr;
|
||||
XEncoder<BsonWriter> en;
|
||||
|
||||
size_t idx; // items index;
|
||||
size_t vidx; // variable index;
|
||||
|
||||
std::vector<std::string> vkeys; // store variable key
|
||||
Item tmpIt; // key:value when key is a variable, copy item to here
|
||||
Item *pIt; // point to tmpIt
|
||||
|
||||
std::vector<size_t> arrayIndex;
|
||||
std::vector<const char*> objKeys; // store object key. use in object end
|
||||
std::vector<const char*> arrKeys; // store array key, use in array end
|
||||
|
||||
Encoder(const std::vector<const Item*>&its):items(&its), en(wr), idx(0), vidx(0), pIt(NULL){}
|
||||
|
||||
// array key. index: "0", "1", "2", "3"
|
||||
const char *Key(const char *raw) {
|
||||
if (NULL != raw) {
|
||||
return raw;
|
||||
} else if (arrayIndex.size()>0) {
|
||||
size_t idx = arrayIndex.size() - 1;
|
||||
return wr.IndexKey(arrayIndex[idx]++);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
BsonBuilder(const std::string& _fmt):raw(_fmt),en(NULL) {
|
||||
dup = new char[raw.length()+1];
|
||||
strcpy(dup, raw.c_str());
|
||||
if (parse()) {
|
||||
for (size_t i=0; i<items.size(); ++i) {
|
||||
if (items[i]->kvar || items[i]->tk.type==Variable) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// no variable. pre build it
|
||||
bstr = Encode();
|
||||
}
|
||||
}
|
||||
|
||||
~BsonBuilder() {
|
||||
if (NULL != dup) {
|
||||
for (size_t i=0; i<items.size(); ++i) {
|
||||
delete items[i];
|
||||
}
|
||||
delete[] dup;
|
||||
dup = NULL;
|
||||
} else if (NULL != en) {
|
||||
delete en;
|
||||
en = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Error() const {
|
||||
return fmtErr;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string Encode(Args... args) {
|
||||
if (!bstr.empty()) {
|
||||
return bstr;
|
||||
} else if (!fmtErr.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
BsonBuilder bd(*this);
|
||||
bd.iencode(args...);
|
||||
bd.end(NULL);
|
||||
return bd.en->en.String();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string EncodeAsJson(Args... args) {
|
||||
if (!fmtErr.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
BsonBuilder bd(*this);
|
||||
bd.iencode(args...);
|
||||
bd.end(NULL);
|
||||
|
||||
return bd.en->wr.Json();
|
||||
}
|
||||
template <typename... Args>
|
||||
static std::string En(const std::string&fmt, Args... args) {
|
||||
BsonBuilder bb(fmt);
|
||||
return bb.Encode(args...);
|
||||
}
|
||||
|
||||
private: // encoder
|
||||
BsonBuilder(const BsonBuilder&bd):dup(NULL) {
|
||||
en = new Encoder(bd.items);
|
||||
}
|
||||
|
||||
// implement iencode()/iencode(T)/iencode(T, Args...) to expand template arguments
|
||||
void iencode() {
|
||||
}
|
||||
void iencode(const char*val) { // xencoder not allow pointer
|
||||
std::string s(val);
|
||||
encode(s);
|
||||
++en->vidx;
|
||||
}
|
||||
template <typename T>
|
||||
void iencode(const T &val) {
|
||||
encode(val);
|
||||
++en->vidx;
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void iencode(const T& first, Args... args) {
|
||||
iencode(first);
|
||||
iencode(args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
BsonBuilder& encode(const T &val) {
|
||||
// encode data items without variable
|
||||
for (; en->idx<en->items->size(); ++en->idx) {
|
||||
const Item *it = en->items->at(en->idx);
|
||||
if ((!it->kvar) && it->tk.type!=Variable) {
|
||||
add(it, 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (en->idx >= en->items->size()) { // finish
|
||||
return *this;
|
||||
} else if (NULL != en->pIt) { // key:val. key and val is variable, key replaced in last encode
|
||||
add(en->pIt, val);
|
||||
en->pIt = NULL;
|
||||
++en->idx;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Item *it = en->items->at(en->idx);
|
||||
if (it->kvar) { // key:val and key is variable, we fill string to key
|
||||
en->tmpIt = *it; // copy item info
|
||||
en->pIt = &en->tmpIt;
|
||||
en->pIt->key = dumpStr(val); // dump key string
|
||||
en->pIt->kvar = false;
|
||||
if (it->tk.type != Variable) { // value not variable
|
||||
add(en->pIt, 1);
|
||||
en->pIt = NULL;
|
||||
++en->idx;
|
||||
}
|
||||
} else { // val is variable
|
||||
add(it, val);
|
||||
++en->idx;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// add items to encoder
|
||||
template <typename T>
|
||||
void add(const Item *it, const T&val) {
|
||||
const char *key = en->Key(it->key);
|
||||
|
||||
switch (it->tk.type) {
|
||||
case ObjectBegin:
|
||||
en->en.ob(key);
|
||||
en->objKeys.push_back(key);
|
||||
break;
|
||||
case ObjectEnd:
|
||||
en->en.oe(en->objKeys.back());
|
||||
en->objKeys.pop_back();
|
||||
break;
|
||||
case ArrayBegin:
|
||||
en->arrayIndex.push_back(0);
|
||||
en->en.ab(key);
|
||||
en->arrKeys.push_back(key);
|
||||
break;
|
||||
case ArrayEnd:
|
||||
en->arrayIndex.pop_back();
|
||||
en->en.ae(en->arrKeys.back());
|
||||
en->arrKeys.pop_back();
|
||||
break;
|
||||
case Integer:
|
||||
en->en.add(key, it->tk.lval);
|
||||
break;
|
||||
case Float:
|
||||
en->en.add(key, it->tk.dval);
|
||||
break;
|
||||
case String:
|
||||
en->en.add(key, std::string(it->tk.sval));
|
||||
break;
|
||||
case Bool:
|
||||
en->en.add(key, it->tk.bval);
|
||||
break;
|
||||
case Variable:
|
||||
en->en.add(key, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// encode the last none variable item
|
||||
void end(std::string *err) {
|
||||
for (; en->idx<en->items->size(); ++en->idx) {
|
||||
const Item *it = en->items->at(en->idx);
|
||||
if (it->kvar || it->tk.type==Variable) {
|
||||
if (NULL != err) {
|
||||
*err = "less variable";
|
||||
}
|
||||
return;
|
||||
}
|
||||
add(it, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// type to const char*
|
||||
const char *dumpStr(const std::string&str) {
|
||||
en->vkeys.push_back(str);
|
||||
return en->vkeys[en->vkeys.size()-1].c_str();
|
||||
}
|
||||
const char *dumpStr(const char *key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const char *dumpStr(const T&val) {
|
||||
(void)val;
|
||||
std::string err = "variable "+Util::itoa(en->vidx)+" is a key, must be std::string or const char*";
|
||||
throw std::runtime_error(err);
|
||||
return "";
|
||||
}
|
||||
|
||||
bool isEnd(char ch) {
|
||||
return ch==' ' || ch==':' || ch==',' || ch=='}' || ch==']'|| ch=='\0';
|
||||
}
|
||||
|
||||
// a simple bson string parser
|
||||
bool parse() {
|
||||
std::vector<char> stack;
|
||||
Item *item;
|
||||
char *p = dup;
|
||||
char *end = p;
|
||||
int keyIndex = -1;
|
||||
char ch;
|
||||
bool waitkey = false; // {key:value, expect key
|
||||
|
||||
int exp = ObjectBegin; // expect type
|
||||
while (true) {
|
||||
item = new Item;
|
||||
p = end;
|
||||
nextToken(p, &end, item->tk);
|
||||
|
||||
if (item->tk.type == BEof) {
|
||||
delete item;
|
||||
if (!fmtErr.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stack.size() > 0) {
|
||||
if ((ch=stack[stack.size()-1]) == '{') { // in object
|
||||
fmtErr = "miss } at the end of string";
|
||||
} else {
|
||||
fmtErr = "miss ] at the end of string";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (item->tk.type == Unknow) {
|
||||
fmtErr = "unknow token:";
|
||||
fmtErr += p;
|
||||
delete item;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((item->tk.type&exp) == 0) {
|
||||
fmtErr = "unexpected token. expect["+tokenName(exp)+"]. but get["+tokenName(item->tk.type)+"]";
|
||||
if (NULL != item->tk.sval) {
|
||||
fmtErr += ". in [";
|
||||
fmtErr += item->tk.sval;
|
||||
fmtErr += "]";
|
||||
}
|
||||
delete item;
|
||||
break;
|
||||
}
|
||||
|
||||
// key:value parse value done
|
||||
if (keyIndex >= 0) {
|
||||
const Item *it = items[keyIndex];
|
||||
items.pop_back();
|
||||
keyIndex = -1;
|
||||
if (it->tk.type == String) {
|
||||
item->key = it->tk.sval;
|
||||
} else {
|
||||
item->kvar = true;
|
||||
}
|
||||
delete it;
|
||||
}
|
||||
|
||||
switch (item->tk.type) {
|
||||
case ObjectBegin:
|
||||
items.push_back(item);
|
||||
exp = ObjectEnd | Variable | String;
|
||||
stack.push_back('{');
|
||||
waitkey = true;
|
||||
break;
|
||||
case ObjectEnd:
|
||||
waitkey = false;
|
||||
case ArrayEnd:
|
||||
items.push_back(item);
|
||||
stack.pop_back();
|
||||
if (stack.size() == 0) {
|
||||
exp = BEof;
|
||||
} else if ((ch=stack[stack.size()-1]) == '{') { // in object
|
||||
exp = ObjectEnd | Comma | String | Variable;
|
||||
} else {
|
||||
exp = ArrayEnd | Comma | Integer | Float | String | Bool | Variable;
|
||||
}
|
||||
break;
|
||||
case ArrayBegin:
|
||||
items.push_back(item);
|
||||
exp = ObjectBegin | ArrayBegin | ArrayEnd | Integer | Float | String | Bool | Variable;
|
||||
stack.push_back('[');
|
||||
break;
|
||||
case Comma:
|
||||
if ((ch=stack[stack.size()-1]) == '{') { // in object
|
||||
exp = String | Variable;
|
||||
waitkey = true;
|
||||
} else {
|
||||
exp = ObjectBegin | ArrayBegin | Integer | Float | String | Bool | Variable;
|
||||
}
|
||||
delete item;
|
||||
break;
|
||||
case Colon:
|
||||
exp = ObjectBegin | ArrayBegin | Integer | Float | String | Bool | Variable;
|
||||
keyIndex = int(items.size()) - 1;
|
||||
waitkey = false;
|
||||
delete item;
|
||||
break;
|
||||
case Integer:
|
||||
case Float:
|
||||
case String:
|
||||
case Bool:
|
||||
case Variable:
|
||||
items.push_back(item);
|
||||
if ((ch=stack[stack.size()-1]) == '{') { // in object
|
||||
if (waitkey) {
|
||||
waitkey = false;
|
||||
exp = Colon;
|
||||
} else {
|
||||
exp = ObjectEnd | Comma;
|
||||
}
|
||||
} else {
|
||||
exp = ArrayEnd | Comma | Integer | Float | String | Bool | Variable;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// get next token from data, may modify data
|
||||
void nextToken(char* data, char**end, Token &tk) {
|
||||
char ch;
|
||||
size_t i = 0;
|
||||
|
||||
*end = NULL;
|
||||
while (data[i] == ' ') {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (data[i] == '\0') {
|
||||
tk.type = BEof;
|
||||
return;
|
||||
}
|
||||
|
||||
tk.sval = data+i;
|
||||
while ((ch=data[i++]) != '\0') {
|
||||
if (tk.type == String) {
|
||||
if (ch != '\'') {
|
||||
continue;
|
||||
} else if (isEnd(data[i])) {
|
||||
data[i-1] = '\0';
|
||||
*end = data+i;
|
||||
} else {
|
||||
tk.type = Unknow;
|
||||
}
|
||||
return;
|
||||
} else if (tk.type == Integer || tk.type == Float) {
|
||||
if (ch>='0' && ch<='9') {
|
||||
continue;
|
||||
} else if (ch == '.') {
|
||||
tk.type = Float;
|
||||
continue;
|
||||
} else if (isEnd(ch)) {
|
||||
if (tk.type == Integer) {
|
||||
data[i-1] = '\0';
|
||||
if (Util::atoi(tk.sval, tk.lval)) {
|
||||
*end = data+i-1;
|
||||
} else {
|
||||
tk.type = Unknow;
|
||||
}
|
||||
data[i-1] = ch;
|
||||
} else {
|
||||
char *dend;
|
||||
tk.dval = strtod(tk.sval, &dend);
|
||||
if (dend != data+i-1) {
|
||||
tk.type = Unknow;
|
||||
} else {
|
||||
*end = dend;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tk.type = Unknow;
|
||||
}
|
||||
return;
|
||||
} else if (tk.type == Variable) {
|
||||
if ((ch>='0' && ch<='9') || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || ch=='_') {
|
||||
continue;
|
||||
} else if (isEnd(ch)) {
|
||||
*end = data+i-1;
|
||||
} else {
|
||||
tk.type = Unknow;
|
||||
}
|
||||
return;
|
||||
} else if (ch == '{') {
|
||||
tk.type = ObjectBegin;
|
||||
break;
|
||||
} else if (ch == '}') {
|
||||
tk.type = ObjectEnd;
|
||||
break;
|
||||
} else if (ch == '[') {
|
||||
tk.type = ArrayBegin;
|
||||
break;
|
||||
} else if (ch == ']') {
|
||||
tk.type = ArrayEnd;
|
||||
break;
|
||||
} else if (ch == ',') {
|
||||
tk.type = Comma;
|
||||
break;
|
||||
} else if (ch == ':') {
|
||||
tk.type = Colon;
|
||||
break;
|
||||
} else if (ch == '\'') { // string
|
||||
tk.type = String;
|
||||
tk.sval = data+i;
|
||||
} else if (ch == '?') {
|
||||
tk.type = Variable;
|
||||
} else if (ch=='-' || ch=='+' || (ch>='0' && ch<='9')) {
|
||||
tk.type = Integer;
|
||||
tk.sval = data+i-1;
|
||||
} else if (ch == 't') { //
|
||||
if (strncmp(data+i-1, "true", 4) == 0 && isEnd(data[i+3])) {
|
||||
tk.type = Bool;
|
||||
tk.bval = true;
|
||||
*end = data+i+3;
|
||||
}
|
||||
return;
|
||||
} else if (ch == 'f') { //
|
||||
if (strncmp(data+i-1, "false", 5) == 0 && isEnd(data[i+4])) {
|
||||
tk.type = Bool;
|
||||
tk.bval = false;
|
||||
*end = data+i+4;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (tk.type != Unknow) {
|
||||
if (*end==NULL && (tk.type==String||tk.type==Float||tk.type==Integer||tk.type==Variable)) {
|
||||
fmtErr = "no end for string/integer/float/variable";
|
||||
tk.type = BEof;
|
||||
} else {
|
||||
*end = data+i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string raw;
|
||||
std::string fmtErr;
|
||||
std::string lastErr;
|
||||
std::string bstr; // for that without any variable
|
||||
char* dup; // for parse
|
||||
std::vector<const Item*> items;
|
||||
Encoder *en;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
279
util/xpack/bson_decoder.h
Executable file
279
util/xpack/bson_decoder.h
Executable file
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_BSON_DECODER_H
|
||||
#define __X_PACK_BSON_DECODER_H
|
||||
|
||||
#include <string.h>
|
||||
#include <libbson-1.0/bson.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "xdecoder.h"
|
||||
#include "bson_type.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
|
||||
class BsonNode {
|
||||
typedef XDecoder<BsonNode> decoder;
|
||||
friend class BsonDecoder;
|
||||
public:
|
||||
typedef size_t Iterator;
|
||||
|
||||
BsonNode(const bson_iter_t* iter = NULL):it(iter),inited(false) {
|
||||
if (NULL != it) {
|
||||
type = bson_iter_type(it);
|
||||
}
|
||||
}
|
||||
|
||||
inline static const char * Name() {
|
||||
return "bson";
|
||||
}
|
||||
operator bool () const {
|
||||
return it != NULL;
|
||||
}
|
||||
bool IsNull() const {
|
||||
return NULL!=it && BSON_TYPE_NULL==bson_iter_type(it);
|
||||
}
|
||||
BsonNode Find(decoder&de, const char*key, const Extend *ext) {
|
||||
(void)de;
|
||||
(void)ext;
|
||||
|
||||
if (!inited) {
|
||||
this->init();
|
||||
}
|
||||
|
||||
if (BSON_TYPE_DOCUMENT != type) {
|
||||
de.decode_exception("not document", NULL);
|
||||
}
|
||||
|
||||
node_index::iterator iter = _childs_index.find(key);
|
||||
if (iter != _childs_index.end()) {
|
||||
return BsonNode(&_childs[iter->second]);
|
||||
} else {
|
||||
return BsonNode();
|
||||
}
|
||||
}
|
||||
size_t Size(decoder&de) {
|
||||
(void)de;
|
||||
if (!inited) {
|
||||
this->init();
|
||||
}
|
||||
|
||||
if (BSON_TYPE_ARRAY == type) {
|
||||
return _childs.size();
|
||||
} else {
|
||||
de.decode_exception("not array", NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
BsonNode At(size_t index) const { // no exception
|
||||
return BsonNode(&(_childs[index]));
|
||||
}
|
||||
BsonNode Next(decoder&de, BsonNode&p, Iterator&iter, std::string&key) {
|
||||
(void)de;
|
||||
if (!p.inited) {
|
||||
p.init();
|
||||
}
|
||||
if (BSON_TYPE_DOCUMENT != p.type) {
|
||||
de.decode_exception("not document", NULL);
|
||||
}
|
||||
|
||||
if (it != p.it) {
|
||||
++iter;
|
||||
} else {
|
||||
iter = 0;
|
||||
}
|
||||
|
||||
if (iter != p._childs.size()) {
|
||||
bson_iter_t *t = &p._childs[iter];
|
||||
key = bson_iter_key(t);
|
||||
return BsonNode(t);
|
||||
}
|
||||
|
||||
return BsonNode();
|
||||
}
|
||||
|
||||
bool Get(decoder&de, std::string&val, const Extend*ext) {
|
||||
(void)ext;
|
||||
|
||||
if (BSON_TYPE_UTF8 == type) {
|
||||
uint32_t length;
|
||||
const char* data = bson_iter_utf8(it, &length);
|
||||
if (NULL != data) {
|
||||
val = std::string(data, length);
|
||||
}
|
||||
} else if (BSON_TYPE_NULL != type) {
|
||||
de.decode_exception("not string", NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Get(decoder&de, bool &val, const Extend*ext) {
|
||||
(void)de;
|
||||
(void)ext;
|
||||
val = bson_iter_as_bool(it);
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer, bool>::type Get(decoder&de, T &val, const Extend*ext){
|
||||
(void)de;
|
||||
(void)ext;
|
||||
val = (T)bson_iter_as_int64(it);
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type Get(decoder&de, T &val, const Extend*ext){
|
||||
(void)de;
|
||||
(void)ext;
|
||||
val = (T)bson_iter_double(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*std::string json() const {
|
||||
if (NULL == _data) {
|
||||
return "";
|
||||
}
|
||||
size_t length=BSON_UINT32_TO_LE(*(int32_t*)_data);
|
||||
bson_t b; // local is ok
|
||||
bson_init_static(&b, _data, length);
|
||||
|
||||
size_t s;
|
||||
char *jstr = bson_as_json(&b, &s);
|
||||
if (jstr) {
|
||||
std::string j(jstr);
|
||||
bson_free(jstr);
|
||||
return j;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}*/
|
||||
|
||||
// bson type
|
||||
bool decode_type_spec(bson_oid_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
const bson_oid_t *t = bson_iter_oid(it);
|
||||
if (t != NULL) {
|
||||
bson_oid_init_from_data(&val, t->bytes);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool decode_type_spec(bson_date_time_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
val.ts = bson_iter_date_time(it);
|
||||
return true;
|
||||
}
|
||||
bool decode_type_spec(bson_timestamp_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_iter_timestamp(it, &val.timestamp, &val.increment);
|
||||
return true;
|
||||
}
|
||||
bool decode_type_spec(bson_decimal128_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return bson_iter_decimal128(it, &val);
|
||||
}
|
||||
bool decode_type_spec(bson_regex_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
const char *options = NULL;
|
||||
const char *regex = bson_iter_regex(it, &options);
|
||||
if (NULL != regex) {
|
||||
val.pattern = regex;
|
||||
}
|
||||
if (NULL != options) {
|
||||
val.options = options;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool decode_type_spec(bson_binary_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
uint32_t len = 0;
|
||||
const uint8_t *data = NULL;
|
||||
bson_iter_binary(it, &val.subType, &len, &data);
|
||||
if (data != NULL && len > 0) {
|
||||
val.data = std::string((const char*)data, size_t(len));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
typedef std::map<const char*, size_t, cmp_str> node_index; // index of _childs
|
||||
|
||||
// get object or array info
|
||||
void init(bool top = false) {
|
||||
inited = true;
|
||||
|
||||
bson_iter_t sub;
|
||||
if (NULL != it) {
|
||||
if (top) {
|
||||
type = BSON_TYPE_DOCUMENT;
|
||||
memcpy((void*)&sub, (void*)it, sizeof(sub));
|
||||
} else if (!bson_iter_recurse(it, &sub)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
while (bson_iter_next(&sub)) {
|
||||
_childs.push_back(sub);
|
||||
if (type == BSON_TYPE_DOCUMENT) {
|
||||
_childs_index[bson_iter_key(&sub)] = i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bson_iter_t* it;
|
||||
bson_type_t type;
|
||||
bool inited;
|
||||
std::vector<bson_iter_t> _childs; // childs
|
||||
node_index _childs_index;
|
||||
};
|
||||
|
||||
|
||||
class BsonDecoder {
|
||||
public:
|
||||
// if length==0, length will get from data
|
||||
template <class T>
|
||||
bool decode(const uint8_t*data, size_t length, T&val) {
|
||||
length = (length>0)?length:BSON_UINT32_TO_LE(*(int32_t*)data);
|
||||
|
||||
bson_t b;
|
||||
bson_iter_t it;
|
||||
bson_init_static(&b, data, length);
|
||||
bson_iter_init(&it, &b);
|
||||
|
||||
BsonNode node(&it);
|
||||
node.init(true);
|
||||
return XDecoder<BsonNode>(NULL, (const char*)NULL, node).decode(val, NULL);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool decode(const std::string&data, T&val) {
|
||||
return decode((const uint8_t*)data.data(), data.length(), val);
|
||||
}
|
||||
};
|
||||
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_oid_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_date_time_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_timestamp_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_decimal128_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_binary_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_regex_t> {static bool const value = true;};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
246
util/xpack/bson_encoder.h
Executable file
246
util/xpack/bson_encoder.h
Executable file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_BSON_ENCODER_H
|
||||
#define __X_PACK_BSON_ENCODER_H
|
||||
|
||||
#include <libbson-1.0/bson.h>
|
||||
|
||||
#include "xpack/util.h"
|
||||
#include "xpack/xencoder.h"
|
||||
#include "bson_type.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class BsonWriter: private noncopyable {
|
||||
friend class BsonBuilder;
|
||||
struct Node {
|
||||
const char *key;
|
||||
Node *parent;
|
||||
bson_t data;
|
||||
|
||||
Node(const char *_key = NULL, Node *_parent=NULL):key(_key), parent(_parent) {
|
||||
if (NULL == parent) {
|
||||
bson_init(&data);
|
||||
}
|
||||
}
|
||||
~Node() {
|
||||
if (NULL == parent) {
|
||||
bson_destroy(&data);
|
||||
}
|
||||
}
|
||||
};
|
||||
friend class XEncoder<BsonWriter>;
|
||||
friend class BsonEncoder;
|
||||
const static bool support_null = true;
|
||||
public:
|
||||
BsonWriter() {
|
||||
cur = new Node(NULL, NULL);
|
||||
nodes.push_back(cur);
|
||||
}
|
||||
|
||||
~BsonWriter() {
|
||||
std::list<Node*>::iterator it;
|
||||
for (it = nodes.begin(); it!=nodes.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
private:
|
||||
inline static const char *Name() {
|
||||
return "bson";
|
||||
}
|
||||
inline const char *IndexKey(size_t index) {
|
||||
if (index > indexStr.size()+1) {
|
||||
std::string s = Util::itoa(index);
|
||||
errCase.push_back(s);
|
||||
return errCase.back().c_str();
|
||||
}
|
||||
if (index >= indexStr.size()) {
|
||||
std::string s = Util::itoa(index);
|
||||
indexStr.push_back(s);
|
||||
}
|
||||
return indexStr[index].c_str();
|
||||
}
|
||||
// return bson binary data
|
||||
std::string String() const {
|
||||
return std::string((const char*)bson_get_data(&cur->data), cur->data.len);
|
||||
}
|
||||
// return json format string
|
||||
std::string Json() const {
|
||||
size_t len;
|
||||
char *jstr = bson_as_json(&cur->data, &len);
|
||||
std::string ret(jstr);
|
||||
bson_free(jstr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ArrayBegin(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (key != NULL) {
|
||||
Node *tmp = new Node(key, cur);
|
||||
nodes.push_back(tmp);
|
||||
|
||||
bson_append_array_begin(&cur->data, key, strlen(key), &tmp->data);
|
||||
cur = tmp;
|
||||
}
|
||||
}
|
||||
void ArrayEnd(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (NULL != key) {
|
||||
bson_append_array_end(&cur->parent->data, &cur->data);
|
||||
cur = cur->parent; // do not pop and delete
|
||||
}
|
||||
}
|
||||
void ObjectBegin(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (key != NULL) {
|
||||
Node *tmp = new Node(key, cur);
|
||||
nodes.push_back(tmp);
|
||||
|
||||
bson_append_document_begin(&cur->data, key, strlen(key), &tmp->data);
|
||||
cur = tmp;
|
||||
}
|
||||
}
|
||||
void ObjectEnd(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (NULL != key) { // in case of inherit, object key is NULL
|
||||
bson_append_document_end(&cur->parent->data, &cur->data);
|
||||
cur = cur->parent; // do not pop and delete
|
||||
}
|
||||
}
|
||||
bool WriteNull(const char*key, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_null(&cur->data, key, strlen(key));
|
||||
return true;
|
||||
}
|
||||
bool encode_bool(const char*key, const bool &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_bool(&cur->data, key, strlen(key), val);
|
||||
return true;
|
||||
}
|
||||
bool encode_string(const char*key, const char*val, size_t length, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_utf8(&cur->data, key, strlen(key), val, length);
|
||||
return true;
|
||||
}
|
||||
bool encode_string(const char*key, const std::string& val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_utf8(&cur->data, key, strlen(key), (const char*)val.data(), val.length());
|
||||
return true;
|
||||
}
|
||||
bool encode_string(const char*key, const char* val, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (NULL != val) {
|
||||
bson_append_utf8(&cur->data, key, strlen(key), val, strlen(val));
|
||||
} else {
|
||||
bson_append_utf8(&cur->data, key, strlen(key), "", 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define X_PACK_BSON_ENCODE_NUMBER(vtype, ftype, ctype) \
|
||||
inline bool encode_number(const char*key, const vtype&val, const Extend*ext) {\
|
||||
(void)ext;\
|
||||
bson_append_##ftype(&cur->data, key, strlen(key), (vtype)val);\
|
||||
return true; \
|
||||
}
|
||||
X_PACK_BSON_ENCODE_NUMBER(char, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(signed char, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned char, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(short, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned short, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(int, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned int, int32, int32_t)
|
||||
|
||||
X_PACK_BSON_ENCODE_NUMBER(long, int64, int64_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned long, int64, int64_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(long long, int64, int64_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned long long, int64, int64_t)
|
||||
|
||||
X_PACK_BSON_ENCODE_NUMBER(float, double, double)
|
||||
X_PACK_BSON_ENCODE_NUMBER(double, double, double)
|
||||
X_PACK_BSON_ENCODE_NUMBER(long double, double, double)
|
||||
|
||||
// bson types
|
||||
bool encode_type_spec(const char*key, const bson_oid_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_oid(&cur->data, key, strlen(key), &val);
|
||||
return true;
|
||||
}
|
||||
bool encode_type_spec(const char*key, const bson_date_time_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_date_time(&cur->data, key, strlen(key), val.ts);
|
||||
return true;
|
||||
}
|
||||
bool encode_type_spec(const char *key, const bson_timestamp_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_timestamp(&cur->data, key, strlen(key), val.timestamp, val.increment);
|
||||
return true;
|
||||
}
|
||||
bool encode_type_spec(const char *key, const bson_decimal128_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return bson_append_decimal128(&cur->data, key, strlen(key), &val);
|
||||
}
|
||||
bool encode_type_spec(const char *key, const bson_regex_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return bson_append_regex(&cur->data, key, strlen(key), val.pattern.c_str(), val.options.c_str());
|
||||
}
|
||||
bool encode_type_spec(const char *key, const bson_binary_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return bson_append_binary(&cur->data, key, strlen(key), val.subType, (const uint8_t*)val.data.data(), val.data.length());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> indexStr;
|
||||
std::list<std::string> errCase;
|
||||
std::list<Node*> nodes;
|
||||
Node *cur;
|
||||
};
|
||||
|
||||
class BsonEncoder {
|
||||
public:
|
||||
BsonEncoder() {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string encode(const T&val) {
|
||||
BsonWriter wr;
|
||||
XEncoder<BsonWriter> en(wr);
|
||||
en.encode(NULL, val, NULL);
|
||||
return wr.String();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string encode_as_json(const T&val) {
|
||||
BsonWriter wr;
|
||||
XEncoder<BsonWriter> en(wr);
|
||||
en.encode(NULL, val, NULL);
|
||||
return wr.Json();
|
||||
}
|
||||
};
|
||||
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_oid_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_date_time_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_timestamp_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_decimal128_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_binary_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_regex_t> {static bool const value = true;};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
450
util/xpack/bson_type.h
Executable file
450
util/xpack/bson_type.h
Executable file
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_BSON_TYPE_H
|
||||
#define __X_PACK_BSON_TYPE_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libbson-1.0/bson.h>
|
||||
|
||||
#include "xencoder.h"
|
||||
#include "xdecoder.h"
|
||||
#include "xpack.h"
|
||||
|
||||
/*
|
||||
// define in this file
|
||||
bson_date_time_t
|
||||
bson_timestamp_t
|
||||
bson_binary_t
|
||||
bson_regex_t
|
||||
|
||||
// define in bson.h
|
||||
bson_oid_t
|
||||
bson_decimal128_t
|
||||
*/
|
||||
|
||||
// define in global namespace for consistency with bson
|
||||
struct bson_timestamp_t {
|
||||
uint32_t timestamp;
|
||||
uint32_t increment;
|
||||
bson_timestamp_t(const uint32_t&t=0, const uint32_t&i=0):timestamp(t),increment(i){}
|
||||
XPACK(A(timestamp, "t", increment, "i"));
|
||||
};
|
||||
struct bson_regex_t {
|
||||
std::string pattern; // libbson not escape string, this should be a bug
|
||||
std::string options;
|
||||
// ver==1 {"$regularExpression": {pattern: <string>, "options": <string>"}}
|
||||
// ver==2 {"$regex: <string>, $options: <string>"}
|
||||
int ver; // ver==1
|
||||
bson_regex_t():ver(2){}
|
||||
};
|
||||
struct bson_date_time_t {
|
||||
int64_t ts; // milliseconds
|
||||
bson_date_time_t(const int64_t&t=0):ts(t){}
|
||||
operator int64_t() const {return ts;}
|
||||
|
||||
// parse rfc3339 time format(milliseconds). C++ doesn't even have a full-featured standard time library T_T
|
||||
// "2000-01-01T01:01:01[.001]Z[07:00]" string should ends with \0
|
||||
bool parse_rfc3339(const char buf[]) {
|
||||
struct tm tm;
|
||||
memset((void*)&tm, 0, sizeof(tm));
|
||||
|
||||
const char *end = strptime(buf, "%Y-%m-%dT%H:%M:%S", &tm);
|
||||
if (end == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int msec = 0;
|
||||
int offset = 0;
|
||||
try {
|
||||
size_t pos;
|
||||
if (*end == '.') {
|
||||
msec = std::stoi(end+1, &pos);
|
||||
if (pos==0 || pos > 3) {
|
||||
return false;
|
||||
}
|
||||
end += pos+1;
|
||||
}
|
||||
if (*end != 'Z') {
|
||||
pos = 0;
|
||||
int hour = std::stoi(end, &pos);
|
||||
if (pos == 0 || pos > 3) {
|
||||
return false;
|
||||
}
|
||||
end += pos;
|
||||
if (*end != ':') {
|
||||
return false;
|
||||
}
|
||||
int min = std::stoi(end+1, &pos);
|
||||
if (hour > 0) {
|
||||
offset = hour*3600 + min*60;
|
||||
} else {
|
||||
offset = -(-hour*3600 + min*60);
|
||||
}
|
||||
} else {
|
||||
++end;
|
||||
if (*end != '\0') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch(...) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time_t tmp = mktime(&tm);
|
||||
ts = tmp*1000 + msec - offset - timezone*1000;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct bson_binary_t {
|
||||
std::string data; // std::string is more general, so don't use std::basic_string<uint8_t>
|
||||
bson_subtype_t subType;
|
||||
|
||||
inline static const char *b64() {
|
||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
}
|
||||
|
||||
// b64_ntop and b64_pton maybe should move to a public place
|
||||
static void b64_ntop(const uint8_t *bin, size_t size, std::string&out) {
|
||||
const char *b = b64();
|
||||
|
||||
out.reserve((size+2)/3*4);
|
||||
size_t n = size/3*3;
|
||||
size_t i;
|
||||
for (i=0; i<n; i+=3) {
|
||||
out.push_back(b[bin[i]>>2]);
|
||||
out.push_back(b[((bin[i]&0x3)<<4) | (bin[i+1]>>4)]);
|
||||
out.push_back(b[((bin[i+1]&0xf)<<2) | (bin[i+2]>>6)]);
|
||||
out.push_back(b[bin[i+2]&0x3f]);
|
||||
}
|
||||
size_t left = size%3;
|
||||
if (left == 1) {
|
||||
out.push_back(b[bin[i]>>2]);
|
||||
out.push_back(b[(bin[i]&0x3)<<4]);
|
||||
out.push_back('=');
|
||||
out.push_back('=');
|
||||
} else if (left == 2) {
|
||||
out.push_back(b[bin[i]>>2]);
|
||||
out.push_back(b[((bin[i]&0x3)<<4) | (bin[i+1]>>4)]);
|
||||
out.push_back(b[(bin[i+1]&0xf)<<2]);
|
||||
out.push_back('=');
|
||||
}
|
||||
}
|
||||
static bool b64_pton(const std::string&in, std::string&out) {
|
||||
static uint8_t bmap[256] = {0};
|
||||
if (bmap[255] == 0) { // init bmap, thread safe
|
||||
for (size_t i=0; i<255; i++) bmap[i] = 0xff;
|
||||
const char *p = b64();
|
||||
for (uint8_t i=0; p[i]!='\0'; ++i) bmap[(int)p[i]] = i;
|
||||
bmap[255] = 0xff;
|
||||
}
|
||||
|
||||
size_t size = in.length();
|
||||
if (size==0 || 0 != (size&0x3)) {
|
||||
return false;
|
||||
}
|
||||
out.reserve((size+3)/4*3);
|
||||
|
||||
const char *data = in.data();
|
||||
for (size_t i=0; i<size; i+=4) {
|
||||
uint8_t i1 = bmap[(uint8_t)data[i]];
|
||||
uint8_t i2 = bmap[(uint8_t)data[i+1]];
|
||||
uint8_t i3 = bmap[(uint8_t)data[i+2]];
|
||||
uint8_t i4 = bmap[(uint8_t)data[i+3]];
|
||||
if (i1!=0xff && i2!=0xff) {
|
||||
out.push_back((char)((i1<<2) | (i2>>4)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i3 != 0xff) {
|
||||
out.push_back((char)((i2<<4) | (i3>>2)));
|
||||
} else if (data[i+2]=='=' && data[i+3]=='=' && i+4==size) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (i4 != 0xff) {
|
||||
out.push_back((char)((i3<<6) | i4));
|
||||
} else if (data[i+3]=='=' && i+4==size) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace xpack {
|
||||
|
||||
// bson type to json
|
||||
// ref https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#conversion-table
|
||||
// Relaxed Extended JSON Format Only
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ObjectId ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
// {"$oid":"xxxxx"}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_oid_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_oid_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
char buf[25];
|
||||
bool ret = de.decode("$oid", buf, NULL);
|
||||
if (ret) {
|
||||
bson_oid_init_from_string(&val, buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_oid_t &val, const Extend *ext) {
|
||||
char buf[25];
|
||||
bson_oid_to_string(&val, buf);
|
||||
en.ObjectBegin(key, ext);
|
||||
en.encode("$oid", buf, NULL);
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ date time ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
// {"$date": 12345}
|
||||
// {"$date":"2006-01-02T15:04:05Z"}
|
||||
// {"$date":{"$numberLong":"123456"}}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_date_time_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_date_time_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
static const char *dkey = "$date";
|
||||
|
||||
bool ret;
|
||||
try {
|
||||
ret = de.decode(dkey, val.ts, NULL);
|
||||
return ret;
|
||||
} catch (...){}
|
||||
|
||||
char buf[25];
|
||||
try {
|
||||
ret = de.decode(dkey, buf, NULL);
|
||||
if (ret) {
|
||||
ret = val.parse_rfc3339(buf);
|
||||
}
|
||||
return ret;
|
||||
} catch (...) {}
|
||||
|
||||
try {
|
||||
ret = de.decode("$numberLong", buf, NULL);
|
||||
if (ret) {
|
||||
ret = Util::atoi(buf, val.ts);
|
||||
}
|
||||
return ret;
|
||||
} catch (...) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_date_time_t &val, const Extend *ext) {
|
||||
en.ObjectBegin(key, ext);
|
||||
if (val.ts >= 0) {
|
||||
char buf[32];
|
||||
int msecs = int(val.ts % 1000);
|
||||
time_t secs = (time_t)(val.ts/1000);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
struct tm posix_date;
|
||||
size_t sz = strftime(buf, sizeof buf, "%FT%T", gmtime_r(&secs, &posix_date));
|
||||
#else
|
||||
size_t sz = strftime(buf, sizeof buf, "%FT%T", gmtime(&secs));
|
||||
#endif
|
||||
|
||||
if (msecs > 0) {
|
||||
sprintf(&buf[sz], ".%03dZ", msecs);
|
||||
} else {
|
||||
strcpy(&buf[sz], "Z");
|
||||
}
|
||||
en.encode("$date", buf, NULL);
|
||||
} else { // key:{"$date":{"$numberLong":ts}} ts use string not int
|
||||
en.ObjectBegin("$date", NULL);
|
||||
en.encode("$numberLong", Util::itoa(val.ts), NULL);
|
||||
en.ObjectEnd("$date", NULL);
|
||||
}
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ timestamp ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
// {"$timestamp":{"t":xxx, "i":xxx}}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_timestamp_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_timestamp_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bool ret = de.decode_struct("$timestamp", val, NULL);
|
||||
return ret;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_timestamp_t &val, const Extend *ext) {
|
||||
en.ObjectBegin(key, ext);
|
||||
en.encode_struct("$timestamp", val, NULL);
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ numberDecimal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
// {"$numberDecimal":"123.4"}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_decimal128_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_decimal128_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
char buf[BSON_DECIMAL128_STRING];
|
||||
bool ret = de.decode("$numberDecimal", buf, NULL);
|
||||
if (ret) {
|
||||
bson_decimal128_from_string(buf, &val);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_decimal128_t &val, const Extend *ext) {
|
||||
char buf[BSON_DECIMAL128_STRING];
|
||||
bson_decimal128_to_string(&val, buf);
|
||||
en.ObjectBegin(key, ext);
|
||||
en.encode("$numberDecimal", buf, NULL);
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ binary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
// {"$binary":{"base64":"aGVsbG8=","subType":"80"}}
|
||||
// {"$binary":"aGVsbG8=", "$type":"80"}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_binary_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_binary_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
try {
|
||||
std::string subType;
|
||||
std::string data;
|
||||
bool ret1;
|
||||
bool ret2;
|
||||
|
||||
Decoder st = de.Find("$type", NULL);
|
||||
if (!st) {
|
||||
Decoder bd = de.Find("$binary", NULL);
|
||||
if (!bd) {
|
||||
return false;
|
||||
}
|
||||
ret1 = bd.decode("subType", subType, NULL);
|
||||
ret2 = bd.decode("base64", data, NULL);
|
||||
} else {
|
||||
ret1 = st.decode(subType, NULL);
|
||||
ret2 = de.decode("$binary", data, NULL);
|
||||
}
|
||||
|
||||
if (ret1 && (subType.length()==1 || subType.length()==2)) {
|
||||
int st = 0;
|
||||
for (size_t i=0; i<subType.length(); ++i) {
|
||||
int tmp = (int)(subType[i]);
|
||||
if (tmp>='0' && tmp<='9') {
|
||||
tmp -= '0';
|
||||
} else if (tmp>='a' && tmp<='f') {
|
||||
tmp = 10 + tmp-'a';
|
||||
} else if (tmp>='A' && tmp<='F') {
|
||||
tmp = 10 + tmp-'A';
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
st = (st<<4) + tmp;
|
||||
}
|
||||
val.subType = (bson_subtype_t)st;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ret2) {
|
||||
ret2 = bson_binary_t::b64_pton(data, val.data);
|
||||
}
|
||||
return ret2;
|
||||
} catch (...){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_binary_t &val, const Extend *ext) {
|
||||
en.ObjectBegin(key, ext);
|
||||
en.ObjectBegin("$binary", NULL);
|
||||
|
||||
std::string b64;
|
||||
bson_binary_t::b64_ntop((const uint8_t*)val.data.data(), val.data.length(), b64);
|
||||
en.encode("base64", b64, NULL);
|
||||
|
||||
std::stringstream ss;
|
||||
ss<<std::hex<<val.subType;
|
||||
en.encode("subType", ss.str(), NULL);
|
||||
|
||||
en.ObjectEnd("$binary", NULL);
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ regex ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_regex_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_regex_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
Decoder v1 = de.Find("$regularExpression", NULL);
|
||||
try {
|
||||
if (v1) {
|
||||
v1.decode("pattern", val.pattern, NULL);
|
||||
v1.decode("options", val.options, NULL);
|
||||
val.ver = 1;
|
||||
} else {
|
||||
de.decode("$regex", val.pattern, NULL);
|
||||
de.decode("$options", val.options, NULL);
|
||||
val.ver = 2;
|
||||
}
|
||||
} catch(...){}
|
||||
return true;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_regex_t &val, const Extend *ext) {
|
||||
en.ObjectBegin(key, ext);
|
||||
if (val.ver == 1) {
|
||||
en.ObjectBegin("$regularExpression", NULL);
|
||||
en.encode("pattern", val.pattern, NULL);
|
||||
en.encode("options", val.options, NULL);
|
||||
en.ObjectEnd("$regularExpression", NULL);
|
||||
} else {
|
||||
en.encode("$regex", val.pattern, NULL);
|
||||
en.encode("$options", val.options, NULL);
|
||||
}
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
25
util/xpack/config.h
Executable file
25
util/xpack/config.h
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_CONFIG_H
|
||||
#define __X_PACK_CONFIG_H
|
||||
|
||||
// support qt
|
||||
//#define XPACK_SUPPORT_QT
|
||||
|
||||
|
||||
#endif
|
||||
27
util/xpack/example/alias.cpp
Executable file
27
util/xpack/example/alias.cpp
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(A(uid, "id xml:xid"), O(name)); // xml use 'xid' and others use 'id'
|
||||
};
|
||||
|
||||
int main() {
|
||||
Test t;
|
||||
string json="{\"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.uid<<endl;
|
||||
|
||||
string xstr = xpack::xml::encode(t, "root");
|
||||
cout<<xstr<<endl;
|
||||
Test t1;
|
||||
xpack::xml::decode(xstr, t1);
|
||||
cout<<t1.uid<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
util/xpack/example/bitfield.cpp
Executable file
23
util/xpack/example/bitfield.cpp
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
short ver:8;
|
||||
short len:8;
|
||||
string name;
|
||||
XPACK(B(F(0), ver, len), O(name));
|
||||
};
|
||||
|
||||
int main() {
|
||||
Test t;
|
||||
string json="{\"ver\":4, \"len\":20, \"name\":\"IPv4\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.ver<<endl;
|
||||
cout<<t.len<<endl;
|
||||
cout<<xpack::xml::encode(t, "root")<<endl;
|
||||
return 0;
|
||||
}
|
||||
40
util/xpack/example/char_array.cpp
Executable file
40
util/xpack/example/char_array.cpp
Executable file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Test {
|
||||
char name[64];
|
||||
char email[64];
|
||||
XPACK(O(name, email));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
Test t;
|
||||
string json="{\"name\":\"Pony\", \"email\":\"pony@xpack.com\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.email<<endl;
|
||||
return 0;
|
||||
}
|
||||
66
util/xpack/example/custom.cpp
Executable file
66
util/xpack/example/custom.cpp
Executable file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
unsigned int uid;
|
||||
string name;
|
||||
XPACK(C(hexint, F(0), uid), O(name));
|
||||
};
|
||||
|
||||
namespace xpack {
|
||||
|
||||
template <class Decoder>
|
||||
bool hexint_decode(Decoder&de, Test&t, const char *name, unsigned int&data, const xpack::Extend *ext) {
|
||||
(void)t;
|
||||
string raw;
|
||||
bool ret = de.decode(name, raw, ext);
|
||||
if (ret) {
|
||||
sscanf(raw.c_str(), "%x", &data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class Encoder>
|
||||
bool hexint_encode(Encoder&en, const Test&t, const char *name, const unsigned &data, const xpack::Extend *ext) {
|
||||
(void)t;
|
||||
char buf[64];
|
||||
sprintf(buf, "%x", data);
|
||||
bool ret = en.encode(name, buf, ext);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
Test t;
|
||||
t.uid = 127;
|
||||
t.name = "PonyJack";
|
||||
|
||||
string str = xpack::json::encode(t);
|
||||
cout<<str<<endl;
|
||||
|
||||
Test n;
|
||||
xpack::json::decode(str, t);
|
||||
cout<<t.uid<<endl;
|
||||
return 0;
|
||||
}
|
||||
45
util/xpack/example/encoder.cpp
Executable file
45
util/xpack/example/encoder.cpp
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
vector<int> vi(3);
|
||||
vi[0] = 1;
|
||||
vi[1] = 2;
|
||||
vi[2] = 3;
|
||||
|
||||
xpack::JsonWriter jw;
|
||||
xpack::XEncoder<xpack::JsonWriter> je(jw);
|
||||
|
||||
xpack::XmlWriter xw;
|
||||
xpack::XEncoder<xpack::XmlWriter> xe(xw);
|
||||
|
||||
je.ob(NULL).add("vv", vi).add("i",10).add("s","hello").oe();
|
||||
xe.ob("root").add("vv", vi).add("i",10).add("s","hello").oe();
|
||||
|
||||
cout<<je.String()<<endl;
|
||||
cout<<xe.String()<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue