Compare commits

...

10 Commits

Author SHA1 Message Date
luocai
32c2c860d9 Add utf8 to gbk function. 2024-06-13 10:08:09 +08:00
2ad8209814 add wstring to stirng. 2024-05-28 15:18:38 +02:00
264ac80d2b try use boost.stackstrace print exception call stack. 2024-05-05 17:21:45 +08:00
88bc6c11a1 correct http method. 2024-05-03 21:39:01 +08:00
e81337c3aa update ApplicationSettings. 2024-01-21 18:08:16 +08:00
72acf69550 Update ApplicationSettings api. 2024-01-21 13:11:09 +08:00
luocai
e05d90f1b3 make Universal PIC. 2024-01-17 11:56:24 +08:00
edeb230c46 1.log添加函数打印。 2024-01-14 21:20:04 +08:00
df14b67695 add http use default certificates api. 2024-01-14 17:54:26 +08:00
20750d1a80 add settings class. 2024-01-06 00:06:35 +08:00
23 changed files with 4795 additions and 459 deletions

View File

@ -4,7 +4,7 @@
"name": "Linux", "name": "Linux",
"includePath": [ "includePath": [
"${workspaceFolder}/**", "${workspaceFolder}/**",
"/opt/Libraries/boost_1_84_0/include" "/opt/Libraries/boost_1_85_0/include"
], ],
"defines": [], "defines": [],
"compilerPath": "/usr/bin/gcc", "compilerPath": "/usr/bin/gcc",

View File

@ -3,7 +3,6 @@ add_library(DataStructure
ArrayList.h ArrayList.h
BinaryTree.h BinaryTree.h
BinarySearchTree.h BinarySearchTree.h
CircularDoublyLinkedList.h
CircularLinkedList.h CircularLinkedList.h
DoublyLinkedList.h DoublyLinkedList.h
DynamicArray.h DynamicArray.h

View File

@ -1,141 +0,0 @@
#ifndef DUALCIRCULARLIST_H
#define DUALCIRCULARLIST_H
#include "DoublyLinkedList.h"
namespace Kylin {
template <typename T>
class CircularDoublyLinkedList : public DoublyLinkedList<T> {
using Node = typename DoublyLinkedList<T>::Node;
using Iterator = typename DoublyLinkedList<T>::Iterator;
public:
static constexpr size_t npos = static_cast<size_t>(-1);
CircularDoublyLinkedList() {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
}
CircularDoublyLinkedList(std::initializer_list<T> init) {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
for (auto &value : init) append(value);
}
CircularDoublyLinkedList(const CircularDoublyLinkedList &other) {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
auto sourceNode = other.m_header.next;
auto targetNode = reinterpret_cast<Node *>(&this->m_header);
for (size_t i = 0; i < other.m_size; i++) {
auto newNode = this->create();
if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
newNode->value = sourceNode->value;
newNode->prev = targetNode;
newNode->next = targetNode->next;
targetNode->next = newNode;
targetNode = newNode;
sourceNode = sourceNode->next;
this->m_size++;
this->m_last = targetNode;
}
}
CircularDoublyLinkedList(CircularDoublyLinkedList &&other) {
this->m_size = other.m_size;
this->m_header = other.m_header;
this->m_last = other.m_last;
other.m_size = 0;
other.m_header.next = nullptr;
other.m_last = reinterpret_cast<Node *>(&other.m_header);
}
void insert(size_t index, const T &value) override {
index = index % (this->m_size + 1);
if (index == this->m_size) return append(value);
auto node = this->create();
if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No momery to insert new element...");
node->value = value;
auto prev = position(index);
auto next = prev->next;
node->next = next;
node->prev = prev;
prev->next = node;
next->prev = node;
this->m_size++;
}
inline void append(const T &value) {
auto node = this->create();
if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
node->value = value;
node->prev = this->m_last;
node->next = this->m_last->next;
this->m_last->next->prev = node;
this->m_last->next = node;
this->m_last = node;
this->m_size++;
}
void removeAt(size_t index) override {
index = mod(index);
auto prev = position(index);
auto toDel = prev->next;
auto next = toDel->next;
prev->next = next;
next->prev = prev;
this->destroy(toDel);
this->m_size--;
}
T &last() override {
if (this->m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the container.");
return this->m_header.prev->value;
}
void clear() override {
while (this->m_size > 0) {
removeAt(0);
}
}
Iterator end() override { return Iterator(reinterpret_cast<Node *>(&this->m_header)); }
Iterator end() const override { return Iterator(reinterpret_cast<Node *>(&this->m_header)); }
~CircularDoublyLinkedList() { clear(); }
T &operator[](size_t index) override {
index = mod(index);
return position(index)->next->value;
}
protected:
size_t mod(size_t index) const { return (this->m_size == 0) ? 0 : (index % this->m_size); }
Node *position(size_t index) const override {
auto node = reinterpret_cast<Node *>(&(this->m_header));
for (size_t i = 0; i < index; i++) {
node = node->next;
}
return node;
}
};
} // namespace Kylin
#endif // DUALCIRCULARLIST_H

View File

@ -28,7 +28,7 @@ target_include_directories(mbedtls-${MBEDTLS_VERSION}
) )
target_link_libraries(Encrypt target_link_libraries(Encrypt
PRIVATE mbedtls-${MBEDTLS_VERSION} PUBLIC mbedtls-${MBEDTLS_VERSION}
) )
if(UNIX) if(UNIX)

View File

@ -1,5 +1,6 @@
project(HttpProxy project(HttpProxy
DESCRIPTION "router api is copy of boost_1_84_0/libs/url/example/router" DESCRIPTION "router api is copy of boost_1_84_0/libs/url/example/router
root_certificates.hpp is copy of boost_1_84_0/libs/beast/example/common/root_certificates.hpp"
) )
find_package(Boost COMPONENTS url REQUIRED) find_package(Boost COMPONENTS url REQUIRED)
@ -9,18 +10,23 @@ add_library(HttpProxy
ProxyHttpSession.h ProxyHttpSession.cpp ProxyHttpSession.h ProxyHttpSession.cpp
ProxyListener.h ProxyListener.cpp ProxyListener.h ProxyListener.cpp
ProxyTcpSession.h ProxyTcpSession.cpp ProxyTcpSession.h ProxyTcpSession.cpp
root_certificates.hpp
router.hpp
detail/impl/router.cpp detail/impl/router.cpp
impl/matches.cpp impl/matches.cpp
) )
target_include_directories(HttpProxy target_include_directories(HttpProxy
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${OpenSSL_INCLUDE_DIR} PRIVATE ${OPENSSL_INCLUDE_DIR}
)
target_link_directories(HttpProxy
PUBLIC ${OPENSSL_LIBRARY_DIRS}
) )
target_link_libraries(HttpProxy target_link_libraries(HttpProxy
PUBLIC ${Boost_LIBRARIES} PUBLIC ${Boost_LIBRARIES}
PUBLIC Universal PUBLIC Universal
PRIVATE ${OpenSSL_LIBRARY} PRIVATE ${OPENSSL_LIBRARIES}
) )

View File

@ -1,166 +1,32 @@
#include "NetworkUtility.h" #include "NetworkUtility.h"
#include "BoostLog.h" #include "BoostLog.h"
#include "root_certificates.hpp"
#include <boost/beast/core.hpp> #include <boost/beast/core.hpp>
#include <boost/beast/http.hpp> #include <boost/beast/http/dynamic_body.hpp>
#include <boost/beast/ssl.hpp> #include <boost/beast/http/read.hpp>
#include <boost/beast/http/write.hpp>
#include <boost/beast/ssl/ssl_stream.hpp>
#include <boost/beast/version.hpp> #include <boost/beast/version.hpp>
#include <optional>
static std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream>> std::string Https::get(boost::asio::io_context &ioContext, const std::string &host, const std::string &port,
makeSslStream(boost::asio::io_context &ioContext, const std::string_view &host, const std::string_view &port, const std::string &url, boost::system::error_code &error, Http::Version version) {
boost::system::error_code &error); Http::Client client(ioContext, Http::SSL, version);
return client.get(host, port, url, error);
std::string Https::get(boost::asio::io_context &ioContext, const std::string_view &host, const std::string_view &port,
const std::string_view &url, boost::system::error_code &error, Http::Version version) {
namespace beast = boost::beast;
namespace http = boost::beast::http;
auto stream = makeSslStream(ioContext, host, port, error);
if (!stream) return std::string();
http::request<http::string_body> req{http::verb::get, url, static_cast<unsigned>(version)};
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
http::write(*stream, req, error);
if (error) {
// LOG(error) << error.message();
return std::string();
}
beast::flat_buffer buffer;
http::response_parser<http::dynamic_body> parser;
parser.body_limit(std::numeric_limits<std::uint64_t>::max());
http::read(*stream, buffer, parser, error);
if (error) {
LOG(error) << error.message();
return std::string();
}
beast::error_code ec;
stream->shutdown(ec);
return boost::beast::buffers_to_string(parser.get().body().data());
} }
std::string Https::post(boost::asio::io_context &ioContext, const std::string_view &host, const std::string_view &port, std::string Https::post(boost::asio::io_context &ioContext, const std::string &host, const std::string &port,
const std::string_view &url, const std::string_view &body, boost::system::error_code &error, const std::string &url, const std::string &body, boost::system::error_code &error,
Http::Version version) { Http::Version version) {
namespace beast = boost::beast; Http::Client client(ioContext, Http::SSL, version);
namespace http = boost::beast::http; return client.post(host, port, url, body, error);
auto stream = makeSslStream(ioContext, host, port, error);
if (!stream) return std::string();
http::request<http::string_body> req{http::verb::post, url.data(), static_cast<unsigned>(version)};
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.body() = body;
req.prepare_payload();
http::write(*stream, req, error);
if (error) {
LOG(error) << error.message();
return std::string();
}
beast::flat_buffer buffer;
http::response<boost::beast::http::dynamic_body> response;
http::read(*stream, buffer, response, error);
if (error) {
LOG(error) << error.message();
return std::string();
}
beast::error_code ec;
stream->shutdown(ec);
return boost::beast::buffers_to_string(response.body().data());
} }
std::string Https::put(boost::asio::io_context &ioContext, const std::string &host, const std::string &port, std::string Https::put(boost::asio::io_context &ioContext, const std::string &host, const std::string &port,
const std::string &url, const std::string &body, boost::system::error_code &error, const std::string &url, const std::string &body, boost::system::error_code &error,
Http::Version version) { Http::Version version) {
namespace beast = boost::beast; Http::Client client(ioContext, Http::SSL, version);
namespace http = boost::beast::http; return client.put(host, port, url, body, error);
auto stream = makeSslStream(ioContext, host, port, error);
if (!stream) return std::string();
http::request<http::string_body> req{http::verb::put, url.data(), static_cast<unsigned>(version)};
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.body() = body;
req.prepare_payload();
http::write(*stream, req, error);
if (error) {
LOG(error) << error.message();
return std::string();
}
beast::flat_buffer buffer;
http::response<boost::beast::http::dynamic_body> response;
http::read(*stream, buffer, response, error);
if (error) {
LOG(error) << error.message();
return std::string();
}
beast::error_code ec;
stream->shutdown(ec);
return boost::beast::buffers_to_string(response.body().data());
}
static std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream>>
makeSslStream(boost::asio::io_context &ioContext, const std::string_view &host, const std::string_view &port,
boost::system::error_code &error) {
namespace beast = boost::beast;
namespace http = boost::beast::http;
namespace asio = boost::asio; // from <boost/asio.hpp>
using tcp = asio::ip::tcp;
namespace ssl = asio::ssl;
ssl::context sslContext(ssl::context::sslv23_client);
sslContext.set_default_verify_paths(error);
if (error) {
LOG(error) << error.message();
return std::nullopt;
}
boost::asio::ip::tcp::resolver resolver(ioContext);
beast::ssl_stream<beast::tcp_stream> stream(ioContext, sslContext);
auto const results = resolver.resolve(host, port, error);
if (error) {
LOG(error) << error.message();
return std::nullopt;
}
beast::get_lowest_layer(stream).connect(results);
stream.handshake(ssl::stream_base::client);
return std::make_optional(std::move(stream));
}
std::vector<Http::ParseItem> Http::parseFormData(const std::string_view &buffer) {
std::vector<ParseItem> ret;
auto pos = buffer.find("\r\n");
std::string_view m_spliter = buffer.substr(0, pos);
size_t m_end = buffer.rfind(m_spliter);
pos = 0;
while (pos != m_end) {
pos = buffer.find(m_spliter, pos);
if (pos == m_end) break;
ParseItem item;
auto dataSpliterPos = buffer.find("\r\n\r\n", pos);
item.begin = dataSpliterPos + 4;
item.end = buffer.find(m_spliter, pos + 1) - 2;
auto meta = buffer.substr(pos, dataSpliterPos - pos);
auto beginPos = meta.find("filename=\"") + 10;
auto endPos = meta.find("\"", beginPos);
item.filename = meta.substr(beginPos, endPos - beginPos);
pos++;
ret.push_back(item);
}
return ret;
} }
uint64_t Network::htonll(uint64_t val) { uint64_t Network::htonll(uint64_t val) {
@ -200,3 +66,184 @@ Network::~Network() {
::WSACleanup(); ::WSACleanup();
#endif #endif
} }
namespace Http {
std::vector<ParseItem> parseFormData(const std::string_view &buffer) {
std::vector<ParseItem> ret;
auto pos = buffer.find("\r\n");
std::string_view m_spliter = buffer.substr(0, pos);
size_t m_end = buffer.rfind(m_spliter);
pos = 0;
while (pos != m_end) {
pos = buffer.find(m_spliter, pos);
if (pos == m_end) break;
ParseItem item;
auto dataSpliterPos = buffer.find("\r\n\r\n", pos);
item.begin = dataSpliterPos + 4;
item.end = buffer.find(m_spliter, pos + 1) - 2;
auto meta = buffer.substr(pos, dataSpliterPos - pos);
auto beginPos = meta.find("filename=\"") + 10;
auto endPos = meta.find("\"", beginPos);
item.filename = meta.substr(beginPos, endPos - beginPos);
pos++;
ret.push_back(item);
}
return ret;
}
class ClientPrivate {
public:
std::unique_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>> sslStream;
std::unique_ptr<boost::beast::tcp_stream> tcpStream;
};
Client::Client(boost::asio::io_context &ioContext, Type type, Version version)
: m_d(new ClientPrivate()), m_ioContext(ioContext) {
m_request.version(static_cast<unsigned>(version));
using namespace boost::asio;
using namespace boost::beast;
m_request.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
if (type == SSL) {
m_sslContext = std::make_shared<ssl::context>(ssl::context::sslv23_client);
}
}
Client::~Client() {
boost::system::error_code error;
shutdown(error);
if (error) {
LOG(error) << error.message();
}
if (m_d != nullptr) delete m_d;
}
void Client::loadRootCertificates(boost::system::error_code &error) {
if (m_sslContext) {
load_root_certificates(*m_sslContext, error);
if (!error) {
m_certificateLocation = CertificateLocation::Default;
}
}
}
std::string Client::get(const std::string &host, const std::string &port, const std::string &url,
boost::system::error_code &error) {
using namespace boost::beast;
m_request.method(http::verb::get);
m_request.target(url);
m_request.set(http::field::host, host);
return execute(host, port, m_request, error);
}
std::string Client::post(const std::string &host, const std::string &port, const std::string &url,
const std::string &body, boost::system::error_code &error) {
using namespace boost::beast;
m_request.method(http::verb::post);
m_request.target(url);
m_request.set(http::field::host, host);
m_request.body() = body;
m_request.prepare_payload();
return execute(host, port, m_request, error);
}
std::string Client::put(const std::string &host, const std::string &port, const std::string &url,
const std::string &body, boost::system::error_code &error) {
using namespace boost::beast;
m_request.method(http::verb::put);
m_request.target(url);
m_request.set(http::field::host, host);
m_request.body() = body;
m_request.prepare_payload();
return execute(host, port, m_request, error);
}
void Client::addRequestField(boost::beast::http::field name, const std::string &value) {
m_request.set(name, value);
}
std::string Client::execute(const std::string &host, const std::string &port, const Request &request,
boost::system::error_code &error) {
using namespace boost::beast;
if ((m_host != host) || (m_port != port) || (!m_d->sslStream && !m_d->tcpStream)) {
if (m_d->sslStream || m_d->tcpStream) {
boost::system::error_code errorCode;
shutdown(errorCode);
if (errorCode) {
LOG(error) << errorCode.message();
}
}
connect(host, port, error);
if (error) {
return std::string();
}
}
if (m_d->sslStream) {
http::write(*m_d->sslStream, request, error);
} else if (m_d->tcpStream) {
http::write(*m_d->tcpStream, request, error);
}
http::response<http::dynamic_body> response;
if (!error) {
flat_buffer buffer;
if (m_d->sslStream) {
http::read(*m_d->sslStream, buffer, response, error);
} else if (m_d->tcpStream) {
http::read(*m_d->tcpStream, buffer, response, error);
}
}
return boost::beast::buffers_to_string(response.body().data());
}
void Client::connect(const std::string &host, const std::string &port, boost::system::error_code &error) {
using namespace boost::asio::ip;
using namespace boost::beast;
tcp::resolver resolver(m_ioContext);
auto const results = resolver.resolve(host, port, error);
if (error) {
return;
}
if (m_sslContext) {
if (m_certificateLocation == CertificateLocation::None) {
m_sslContext->set_default_verify_paths(error);
if (!error) m_certificateLocation = CertificateLocation::SystemDependent;
}
m_d->sslStream = std::make_unique<ssl_stream<tcp_stream>>(m_ioContext, *m_sslContext);
get_lowest_layer(*m_d->sslStream).connect(results, error);
if (error) {
return;
}
m_d->sslStream->handshake(ssl::stream_base::client, error);
} else {
m_d->tcpStream = std::make_unique<tcp_stream>(m_ioContext);
m_d->tcpStream->connect(results, error);
}
if (error) {
return;
}
m_host = host;
m_port = port;
}
void Client::shutdown(boost::system::error_code &error) {
using namespace boost::asio::ip;
if (m_d->sslStream) {
m_d->sslStream->shutdown(error);
m_d->sslStream.reset();
} else if (m_d->tcpStream) {
m_d->tcpStream->socket().shutdown(tcp::socket::shutdown_both, error);
m_d->tcpStream.reset();
}
}
} // namespace Http

View File

@ -1,12 +1,21 @@
#ifndef __NETWORKUTILITY_H__ #ifndef __NETWORKUTILITY_H__
#define __NETWORKUTILITY_H__ #define __NETWORKUTILITY_H__
#include "Singleton.h" #include "Singleton.h"
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <string> #include <string>
#include <string_view> #include <string_view>
namespace boost {
namespace asio {
namespace ssl {
class context;
}
} // namespace asio
} // namespace boost
class Network { class Network {
friend class Amass::Singleton<Network, Amass::GlobalInstance>; friend class Amass::Singleton<Network, Amass::GlobalInstance>;
@ -20,49 +29,91 @@ protected:
~Network(); ~Network();
}; };
class Http { namespace Http {
public: using Request = boost::beast::http::request<boost::beast::http::string_body>;
enum Version : unsigned { enum Type {
Version_1_1 = 11, Transparent,
}; SSL,
struct ParseItem {
std::string filename;
// std::string::const_iterator begin;
// std::string::const_iterator end;
size_t begin;
size_t end;
};
/**
* @brief
*
* @param buffer
* @return std::vector<ParseItem>
* @example auto items = parseFormData(request.body());
* for (auto &item : items) {
* std::string filename("E:/");
* filename += item.filename;
* std::ofstream ofs(filename.c_str(), std::ios::binary);
* ofs.write(buffer.data() + item.begin, item.end - item.begin);
* ofs.close();
* }
*/
static std::vector<ParseItem> parseFormData(const std::string_view &buffer);
}; };
enum CertificateLocation {
None,
Default,
SystemDependent,
};
enum Version : unsigned {
Version_1_1 = 11,
};
struct ParseItem {
std::string filename;
// std::string::const_iterator begin;
// std::string::const_iterator end;
size_t begin;
size_t end;
};
/**
* @brief
*
* @param buffer
* @return std::vector<ParseItem>
* @example auto items = parseFormData(request.body());
* for (auto &item : items) {
* std::string filename("E:/");
* filename += item.filename;
* std::ofstream ofs(filename.c_str(), std::ios::binary);
* ofs.write(buffer.data() + item.begin, item.end - item.begin);
* ofs.close();
* }
*/
static std::vector<ParseItem> parseFormData(const std::string_view &buffer);
class ClientPrivate;
class Client {
public:
Client(boost::asio::io_context &ioContext, Type type, Version version = Version_1_1);
~Client();
void loadRootCertificates(boost::system::error_code &error);
std::string get(const std::string &host, const std::string &port, const std::string &url,
boost::system::error_code &error);
std::string post(const std::string &host, const std::string &port, const std::string &url, const std::string &body,
boost::system::error_code &error);
std::string put(const std::string &host, const std::string &port, const std::string &url, const std::string &body,
boost::system::error_code &error);
void addRequestField(boost::beast::http::field name, const std::string &value);
protected:
std::string execute(const std::string &host, const std::string &port, const Request &request,
boost::system::error_code &error);
void connect(const std::string &host, const std::string &port, boost::system::error_code &error);
void shutdown(boost::system::error_code &error);
private:
ClientPrivate *m_d = nullptr;
boost::asio::io_context &m_ioContext;
std::shared_ptr<boost::asio::ssl::context> m_sslContext;
CertificateLocation m_certificateLocation = CertificateLocation::None;
std::string m_host;
std::string m_port;
Request m_request;
};
} // namespace Http
class Https { class Https {
public: public:
static std::string get(boost::asio::io_context &ioContext, const std::string_view &host, static std::string get(boost::asio::io_context &ioContext, const std::string &host, const std::string &port,
const std::string_view &port, const std::string_view &url, boost::system::error_code &error, const std::string &url, boost::system::error_code &error,
Http::Version version = Http::Version_1_1); Http::Version version = Http::Version_1_1);
static std::string post(boost::asio::io_context &ioContext, const std::string_view &host, static std::string post(boost::asio::io_context &ioContext, const std::string &host, const std::string &port,
const std::string_view &port, const std::string_view &url, const std::string_view &body, const std::string &url, const std::string &body, boost::system::error_code &error,
boost::system::error_code &error, Http::Version version = Http::Version_1_1); Http::Version version = Http::Version_1_1);
static std::string put(boost::asio::io_context &ioContext, const std::string &host, const std::string &port, static std::string put(boost::asio::io_context &ioContext, const std::string &host, const std::string &port,
const std::string &url, const std::string &body, boost::system::error_code &error, const std::string &url, const std::string &body, boost::system::error_code &error,
Http::Version version = Http::Version_1_1); Http::Version version = Http::Version_1_1);
}; };
#endif // __NETWORKUTILITY_H__ #endif // __NETWORKUTILITY_H__

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(UnitTest main.cpp add_executable(UnitTest main.cpp
DataStructure/BinarySearchTreeTest.cpp DataStructure/BinarySearchTreeTest.cpp
DataStructure/BinaryTreeTest.cpp DataStructure/BinaryTreeTest.cpp
DataStructure/CircularDoublyLinkedListTest.cpp
DataStructure/CircularLinkedListTest.cpp DataStructure/CircularLinkedListTest.cpp
DataStructure/DoublyLinkedListTest.cpp DataStructure/DoublyLinkedListTest.cpp
DataStructure/DynamicArrayListTest.cpp DataStructure/DynamicArrayListTest.cpp
@ -31,6 +30,9 @@ add_executable(UnitTest main.cpp
HttpProxy/BoostUrlTest.cpp HttpProxy/BoostUrlTest.cpp
Universal/BoostLogTest.cpp Universal/BoostLogTest.cpp
Universal/DateTimeTest.cpp
Universal/MessageManagerTest.cpp
Universal/SingletonTest.cpp
) )
target_compile_definitions(UnitTest target_compile_definitions(UnitTest

View File

@ -1,108 +0,0 @@
#include "CircularDoublyLinkedList.h"
#include <boost/test/unit_test.hpp>
#include <iostream>
using namespace Kylin;
class CircularDoublyLinkedListTest {
public:
CircularDoublyLinkedList<size_t> list{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
};
BOOST_AUTO_TEST_SUITE(CircularDoublyLinkedListTestCase)
BOOST_FIXTURE_TEST_CASE(At, CircularDoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.at(5), 5); }
BOOST_FIXTURE_TEST_CASE(Size, CircularDoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.size(), 10); }
BOOST_FIXTURE_TEST_CASE(Last, CircularDoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.last(), 9); }
BOOST_FIXTURE_TEST_CASE(EmptyListCallLastCauseException, CircularDoublyLinkedListTest) {
CircularDoublyLinkedList<size_t> emptyList;
BOOST_CHECK_THROW(emptyList.last(), InvalidOperationException);
}
BOOST_FIXTURE_TEST_CASE(CallLastAfterRemoveLastElement, CircularDoublyLinkedListTest) {
list.removeAt(list.size() - 1);
BOOST_CHECK_EQUAL(list.last(), 8);
}
BOOST_FIXTURE_TEST_CASE(RemoveIndexLessThenSize, CircularDoublyLinkedListTest) {
list.removeAt(3);
BOOST_CHECK_EQUAL(list[3], 4);
BOOST_CHECK_EQUAL(list.length(), 9);
}
BOOST_FIXTURE_TEST_CASE(RemoveIndexBigThenSize, CircularDoublyLinkedListTest) {
list.removeAt(15);
BOOST_CHECK_EQUAL(list[5], 6);
BOOST_CHECK_EQUAL(list.length(), 9);
}
BOOST_FIXTURE_TEST_CASE(Clear, CircularDoublyLinkedListTest) {
list.clear();
BOOST_CHECK_EQUAL(list.length(), 0);
}
BOOST_FIXTURE_TEST_CASE(IndexOf, CircularDoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.indexOf(5), 5); }
BOOST_FIXTURE_TEST_CASE(Append, CircularDoublyLinkedListTest) {
list.append(198);
BOOST_CHECK_EQUAL(list.length(), 11);
BOOST_CHECK_EQUAL(list.at(list.size() - 1), 198);
}
BOOST_FIXTURE_TEST_CASE(Swap, CircularDoublyLinkedListTest) {
CircularDoublyLinkedList<size_t> list2;
for (size_t i = 0; i < 5; i++) {
list2.insert(list2.length(), i + 10);
}
list2.swap(list);
BOOST_CHECK_EQUAL(list.size(), 5);
BOOST_CHECK_EQUAL(list2.size(), 10);
for (size_t i = 0; i < 5; i++) {
BOOST_CHECK_EQUAL(list.at(i), i + 10);
}
for (size_t i = 0; i < 10; i++) {
BOOST_CHECK_EQUAL(list2.at(i), i);
}
}
BOOST_FIXTURE_TEST_CASE(InsertToIndexLessThenSize, CircularDoublyLinkedListTest) {
list.insert(4, 456);
BOOST_CHECK_EQUAL(list.length(), 11);
BOOST_CHECK_EQUAL(list.at(4), 456);
BOOST_CHECK_EQUAL(list.at(5), 4);
}
BOOST_FIXTURE_TEST_CASE(InsertToIndexEuqalSize, CircularDoublyLinkedListTest) {
list.insert(list.size(), 456);
BOOST_CHECK_EQUAL(list.length(), 11);
BOOST_CHECK_EQUAL(list.at(list.size() - 1), 456);
}
BOOST_FIXTURE_TEST_CASE(CopyConstructor, CircularDoublyLinkedListTest) {
auto list2(list);
BOOST_CHECK_EQUAL(list2.size(), 10);
list[9] = 2; //测试是否为浅拷贝
BOOST_CHECK_EQUAL(list2[9], 9);
}
BOOST_FIXTURE_TEST_CASE(MoveConstructor, CircularDoublyLinkedListTest) {
auto list2(std::move(list));
BOOST_CHECK_EQUAL(list.empty(), true);
BOOST_CHECK_EQUAL(list2.size(), 10);
BOOST_CHECK_EQUAL(list2[9], 9);
}
BOOST_FIXTURE_TEST_CASE(Iterator, CircularDoublyLinkedListTest) {
size_t i = 0;
for (const auto &value : list) {
BOOST_CHECK_EQUAL(value, i++);
}
BOOST_CHECK_EQUAL(list.size(), i);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,83 @@
#include <BoostLog.h>
#include <DateTime.h>
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(DateTimeTest, *boost::unit_test::enabled())
BOOST_AUTO_TEST_CASE(BasicUse) {
std::time_t c_current = std::time(nullptr);
auto c_local = localtime(&c_current);
auto now = DateTime::currentDateTime();
BOOST_CHECK_EQUAL(now.year(), c_local->tm_year + 1900);
BOOST_CHECK_EQUAL(now.month(), c_local->tm_mon + 1);
BOOST_CHECK_EQUAL(now.day(), c_local->tm_mday);
BOOST_CHECK_EQUAL(now.hour(), c_local->tm_hour);
BOOST_CHECK_EQUAL(now.minute(), c_local->tm_min);
BOOST_CHECK_EQUAL(now.second(), c_local->tm_sec);
// std::cout << "now: " << DateTime::toString(std::chrono::system_clock::now()) << std::endl;
// std::cout << "now: " << DateTime::currentDateTime().toString() << std::endl;
auto day = DateTime::makeDateTime(2018, 8, 15, 13, 14, 59);
DateTime r(day);
BOOST_CHECK_EQUAL(r.week(), DateTime::Wednesday);
BOOST_CHECK_EQUAL(DateTime::toString(day), "2018-08-15 13:14:59");
}
BOOST_AUTO_TEST_CASE(IsLeapYearTest) {
BOOST_TEST(DateTime::isLeapYear(2008));
BOOST_TEST(!DateTime::isLeapYear(2100));
}
BOOST_AUTO_TEST_CASE(TomorrowTest) {
DateTime day(2018, 8, 15, 13, 14, 59);
auto t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2018-08-16 13:14:59");
day = DateTime(2018, 12, 31, 13, 14, 59);
t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2019-01-01 13:14:59");
day = DateTime(2020, 2, 28, 13, 14, 59);
t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2020-02-29 13:14:59");
day = DateTime(2021, 2, 28, 13, 14, 59);
t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2021-03-01 13:14:59");
day = DateTime(2021, 10, 25, 22, 31, 59);
t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2021-10-26 22:31:59");
}
BOOST_AUTO_TEST_CASE(CurrentMSecsSinceEpoch) {
BOOST_CHECK_EQUAL(DateTime::currentMSecsSinceEpoch(),
std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now())
.time_since_epoch()
.count());
}
BOOST_AUTO_TEST_CASE(ParseTimeString) {
auto [hour, minute, second] = DateTime::parseTime("12:14:15");
BOOST_CHECK_EQUAL(hour, 12);
BOOST_CHECK_EQUAL(minute, 14);
BOOST_CHECK_EQUAL(second, 15);
std::tie(hour, minute, second) = DateTime::parseTime("15:12");
BOOST_CHECK_EQUAL(hour, 15);
BOOST_CHECK_EQUAL(minute, 12);
BOOST_CHECK_EQUAL(second, 0);
std::tie(hour, minute, second) = DateTime::parseTime("00:09:07");
BOOST_CHECK_EQUAL(hour, 0);
BOOST_CHECK_EQUAL(minute, 9);
BOOST_CHECK_EQUAL(second, 7);
std::tie(hour, minute, second) = DateTime::parseTime("15:12");
BOOST_CHECK_EQUAL(hour, 15);
BOOST_CHECK_EQUAL(minute, 12);
BOOST_CHECK_EQUAL(second, 0);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,187 @@
#include <BoostLog.h>
#include <FunctionTraits.h>
#include <MessageManager.h>
#include <boost/function_types/function_type.hpp>
#include <boost/test/unit_test.hpp>
static int test(int a, int b) {
return a + b;
}
class Test {
public:
int test(int a, int b) {
result = a + b + 3;
return result;
}
int result{0};
};
BOOST_AUTO_TEST_SUITE(MessageManagerTest, *boost::unit_test::enabled())
// returned-function-return-type (* function-name (parameter-list) ) (function-to-return-parameter-list)
BOOST_AUTO_TEST_CASE(FunctionTraitsNormalFunctionTest) {
using namespace std::placeholders;
MessageManager m;
m.registerTopic("123", [](int a) -> void { a = a + 102; });
BOOST_CHECK_EQUAL(m.topicCount<int(int)>("123"), 1);
Test t;
m.registerTopic("123", [&t](int a, int b) { return t.test(a, b); });
BOOST_CHECK_EQUAL(m.topicCount<int(int, int)>("123"), 1);
m.registerTopic("123", std::bind(&Test::test, &t, _1, _2));
BOOST_CHECK_EQUAL(m.topicCount<int(int, int)>("123"), 2);
m.registerTopic("123", &test);
BOOST_CHECK_EQUAL(m.topicCount<int(int, int)>("123"), 3);
m.removeTopic<int(int, int)>("123");
BOOST_CHECK_EQUAL(m.topicCount<int(int, int)>("123"), 0);
m.registerTopic("123", [](const std::string &title) {});
m.registerTopic(
"123", [](int type, const std::string &title, const std::string &message, const std::function<void()> &yes) {});
}
BOOST_AUTO_TEST_CASE(SyncMessage) {
using namespace std::placeholders;
MessageManager manager;
int result1 = 0;
std::thread::id id;
manager.registerTopic("123", [&result1](int a) {
result1 += a;
return a + 102;
});
int result2 = 0;
manager.registerTopic("123", [&result2](const int &a) {
result2 = a + 102;
return result2;
});
manager.sendMessage("123", 5);
BOOST_CHECK_EQUAL(result1, 5);
BOOST_CHECK_EQUAL(result2, 107);
int result3 = 0;
manager.registerTopic("123", [&result3](int a, int b) {
result3 = a + b;
return 0;
});
Test t;
manager.registerTopic("123", std::bind(&Test::test, &t, _1, _2));
manager.sendMessage("123", 12, 13);
BOOST_CHECK_EQUAL(result3, 25);
BOOST_CHECK_EQUAL(t.result, 28);
int result4 = 0;
manager.registerTopic("123", [&result4]() {
result4 = 102;
return result4;
});
manager.sendMessage("123");
BOOST_CHECK_EQUAL(result4, 102);
constexpr auto magic = "MagicString";
std::string result5;
manager.registerTopic("test", [&result5](const std::string &text) { result5 = text; });
// manager.sendMessage<std::string>("test", magic); // 编译不通过
// manager.sendMessage("test", magic); // const char*无法匹配到std::string
// BOOST_CHECK_EQUAL(result5, magic);
// result5.clear();
manager.sendMessage<void(const std::string &), std::string>("test", magic);
BOOST_CHECK_EQUAL(result5, magic);
result5.clear();
manager.sendMessage<void(const std::string &)>("test", std::string(magic));
BOOST_CHECK_EQUAL(result5, magic);
result5.clear();
manager.sendMessage<void(std::string)>("test", magic);
BOOST_CHECK_EQUAL(result5, magic);
result5.clear();
manager.sendMessage("test", std::string(magic));
BOOST_CHECK_EQUAL(result5, magic);
}
BOOST_AUTO_TEST_CASE(SyncMessageWithVoidArg) {
MessageManager manager;
constexpr auto Topic = MessageManager::Message<>("test1");
int result = 0;
manager.registerTopic("test1", [&result]() -> void { result = 250; });
manager.sendMessage("test1");
BOOST_CHECK_EQUAL(result, 250);
result = 0;
manager.sendMessage(Topic);
BOOST_CHECK_EQUAL(result, 250);
}
BOOST_AUTO_TEST_CASE(AsyncMessage) {
int result = 0;
std::thread::id id;
auto test1 = [&result, &id](int a, int b) -> void {
result = a + b;
id = std::this_thread::get_id();
};
MessageManager manager;
manager.registerTopic("test1", test1);
manager.sendAsyncMessage("test1", 2, 6);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
BOOST_CHECK_EQUAL(result, 8);
BOOST_CHECK_NE(std::this_thread::get_id(), id);
constexpr auto magic = "MagicString";
manager.registerTopic("StringCompare", [magic](const std::string &text) { BOOST_CHECK_EQUAL(text, magic); });
{
std::string string(magic);
manager.sendAsyncMessage("StringCompare", string);
}
}
BOOST_AUTO_TEST_CASE(AsyncMessageImplictConversion) {
float result1 = 0;
auto test1 = [&result1](int a, int b) -> void { result1 = a + b; };
float result2 = 0;
auto test2 = [&result2](int a, int b) -> void { result2 = a + b; };
MessageManager manager;
manager.registerTopic("test1", test1);
manager.registerTopic("test2", test2);
manager.sendAsyncMessage<decltype(test1)>("test1", 2.6, 6);
manager.sendAsyncMessage("test2", (int)3.6, 6);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
BOOST_CHECK_EQUAL(result1, 8);
BOOST_CHECK_EQUAL(result2, 9);
}
BOOST_AUTO_TEST_CASE(DefineTopicUseMessage) {
constexpr auto TestTopic1 = MessageManager::Message<int, int>("TestTopic1");
int result1 = 0;
auto test1 = [&result1](int a, int b) -> void { result1 = a + b; };
MessageManager manager;
manager.registerTopic(TestTopic1, test1);
manager.sendMessage(TestTopic1, 2, 3);
BOOST_CHECK_EQUAL(result1, 5);
std::string result2;
constexpr auto TestTopic2 = MessageManager::Message<const std::string &>("TestTopic2");
auto test2 = [&result2](const std::string &text) -> void { result2 = text; };
manager.registerTopic(TestTopic2, test2);
manager.sendMessage(TestTopic2, std::string("hello"));
std::string message("hello");
// manager.sendMessage(TestTopic2, message);
// manager.sendMessage(TestTopic2, "hello");
BOOST_CHECK_EQUAL(result2, "hello");
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,39 @@
#include "Singleton.h"
#include <boost/test/unit_test.hpp>
class Test {
public:
size_t index;
};
BOOST_AUTO_TEST_CASE(LocalInstance) {
auto test = Amass::Singleton<Test>::instance();
BOOST_TEST(!test);
{
auto local = Amass::Singleton<Test>::instance<Amass::Construct>();
BOOST_TEST(local);
auto refer = Amass::Singleton<Test>::instance();
BOOST_TEST(refer);
}
test = Amass::Singleton<Test>::instance();
BOOST_TEST(!test);
}
BOOST_AUTO_TEST_CASE(GlobalInstance) {
auto test = Amass::Singleton<Test, Amass::GlobalInstance>::instance();
BOOST_TEST(test);
{
auto local = Amass::Singleton<Test, Amass::GlobalInstance>::instance();
BOOST_TEST(local);
auto refer = Amass::Singleton<Test, Amass::GlobalInstance>::instance();
BOOST_TEST(refer);
}
test = Amass::Singleton<Test, Amass::GlobalInstance>::instance();
BOOST_TEST(test);
}

View File

@ -0,0 +1,90 @@
#ifndef __APPLICATIONSETTINGS_H__
#define __APPLICATIONSETTINGS_H__
#include "BoostLog.h"
#include <boost/asio/steady_timer.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/tuple/to_seq.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <filesystem>
template <typename Child>
class ApplicationSettings {
#define BUILD_SETTING_FIELD(Category, Type, Name, DefaultValue) \
inline void set##Name(const Type &value) { \
std::lock_guard locker(m_mutex); \
m_ptree.put(#Category "." #Name, value); \
m_needSave = true; \
} \
inline Type get##Name() const { \
std::lock_guard locker(m_mutex); \
return m_ptree.get<Type>(#Category "." #Name, DefaultValue); \
}
#define BUILD_STATUS(Type, Name, DefaultValue) BUILD_SETTING_FIELD(Status, Type, Name, DefaultValue)
#define BUILD_SETTING(Type, Name, DefaultValue) BUILD_SETTING_FIELD(Settings, Type, Name, DefaultValue)
#define INITIALIZE_FIELD(Name) set##Name(get##Name());
#define MACRO(r, data, elem) INITIALIZE_FIELD(elem)
#define INITIALIZE_FIELDS(...) \
inline void initializeFileds() final { \
BOOST_PP_SEQ_FOR_EACH(MACRO, _, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))) \
}
public:
ApplicationSettings(const std::string &path) : m_path(path) {
if (std::filesystem::exists(path)) {
try {
boost::property_tree::read_ini(path, m_ptree);
} catch (const boost::property_tree::ini_parser_error &e) {
LOG(error) << e.what();
}
} else {
static_cast<Child *>(this)->initializeFileds();
save();
}
}
void startCheckInterval(boost::asio::io_context &ioContext, uint32_t seconds) {
m_timer = std::make_unique<boost::asio::steady_timer>(ioContext);
m_interval = seconds;
run();
}
protected:
void save() {
if (!m_needSave) return;
try {
std::lock_guard locker(m_mutex);
boost::property_tree::write_ini(m_path, m_ptree);
m_needSave = false;
} catch (const boost::property_tree::ini_parser_error &e) {
LOG(error) << e.what();
}
}
void run() {
m_timer->expires_after(std::chrono::seconds(m_interval));
m_timer->async_wait([this](const boost::system::error_code &error) {
if (error) {
LOG(error) << error.message();
return;
}
save();
run();
});
}
virtual void initializeFileds() {
}
boost::property_tree::ptree m_ptree;
bool m_needSave = false;
mutable std::mutex m_mutex;
private:
std::string m_path;
std::unique_ptr<boost::asio::steady_timer> m_timer;
uint32_t m_interval;
};
#endif // __APPLICATIONSETTINGS_H__

View File

@ -7,16 +7,11 @@
#include "AndroidBoostLog.h" #include "AndroidBoostLog.h"
#endif #endif
BOOST_LOG_GLOBAL_LOGGER_INIT(location_logger, LocationLogger<boost::log::trivial::severity_level>) {
LocationLogger<boost::log::trivial::severity_level> lg;
auto consoleSink = boost::log::add_console_log();
consoleSink->set_formatter(&boost::log::defaultFormatter);
boost::log::add_common_attributes();
return lg;
}
namespace boost { namespace boost {
namespace log { namespace log {
static bool enableConsole = true;
static decltype(boost::log::add_console_log()) console;
void initialize(const std::string &filename, const std::string &target, boost::log::trivial::severity_level filter) { void initialize(const std::string &filename, const std::string &target, boost::log::trivial::severity_level filter) {
static bool initialized = false; static bool initialized = false;
using namespace boost::log; using namespace boost::log;
@ -67,5 +62,23 @@ void defaultFormatter(const boost::log::record_view &record, boost::log::formatt
ostream << record[expressions::smessage]; ostream << record[expressions::smessage];
} }
void removeConsoleLog() {
if (console) {
boost::log::core::get()->remove_sink(console);
console.reset();
}
enableConsole = false;
}
} // namespace log } // namespace log
} // namespace boost } // namespace boost
BOOST_LOG_GLOBAL_LOGGER_INIT(location_logger, LocationLogger<boost::log::trivial::severity_level>) {
LocationLogger<boost::log::trivial::severity_level> lg;
boost::log::add_common_attributes();
if (boost::log::enableConsole) {
boost::log::console = boost::log::add_console_log();
boost::log::console->set_formatter(&boost::log::defaultFormatter);
}
return lg;
}

View File

@ -66,16 +66,19 @@ void initialize(const std::string &filename = "logs/app", const std::string &tar
trivial::severity_level filter = static_cast<trivial::severity_level>(LOG_FILTER_LEVEL)); trivial::severity_level filter = static_cast<trivial::severity_level>(LOG_FILTER_LEVEL));
void defaultFormatter(boost::log::record_view const &record, boost::log::formatting_ostream &ostream); void defaultFormatter(boost::log::record_view const &record, boost::log::formatting_ostream &ostream);
void removeConsoleLog();
} // namespace log } // namespace log
} // namespace boost } // namespace boost
namespace AmassKeywords { namespace AmassKeywords {
BOOST_PARAMETER_KEYWORD(FilenameNS, FilenameTag) BOOST_PARAMETER_KEYWORD(FilenameNS, FilenameTag)
BOOST_PARAMETER_KEYWORD(FunctionNS, FunctionTag)
BOOST_PARAMETER_KEYWORD(LineNS, LineTag) BOOST_PARAMETER_KEYWORD(LineNS, LineTag)
BOOST_PARAMETER_KEYWORD(CategoryNS, CategoryTag) BOOST_PARAMETER_KEYWORD(CategoryNS, CategoryTag)
BOOST_LOG_ATTRIBUTE_KEYWORD(filename, "Filename", std::string) BOOST_LOG_ATTRIBUTE_KEYWORD(filename, "Filename", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(function, "Function", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(line, "Line", size_t) BOOST_LOG_ATTRIBUTE_KEYWORD(line, "Line", size_t)
BOOST_LOG_ATTRIBUTE_KEYWORD(category, "Category", std::string) BOOST_LOG_ATTRIBUTE_KEYWORD(category, "Category", std::string)
@ -138,6 +141,28 @@ protected:
struct FilenameTagger : public boost::mpl::quote1<FilenameTaggerFeature> {}; struct FilenameTagger : public boost::mpl::quote1<FilenameTaggerFeature> {};
template <typename BaseT>
class FunctionTaggerFeature : public BaseT {
public:
typedef typename BaseT::char_type char_type;
typedef typename BaseT::threading_model threading_model;
FunctionTaggerFeature() = default;
FunctionTaggerFeature(const FunctionTaggerFeature &obj);
template <typename ArgsT>
FunctionTaggerFeature(const ArgsT &args);
typedef typename boost::log::strictest_lock<boost::lock_guard<threading_model>, typename BaseT::open_record_lock,
typename BaseT::add_attribute_lock,
typename BaseT::remove_attribute_lock>::type open_record_lock;
protected:
template <typename ArgsT>
boost::log::record open_record_unlocked(const ArgsT &args);
};
struct FunctionTagger : public boost::mpl::quote1<FunctionTaggerFeature> {};
template <typename BaseT> template <typename BaseT>
class LineTaggerFeature : public BaseT { class LineTaggerFeature : public BaseT {
public: public:
@ -164,8 +189,8 @@ template <typename LevelT = int>
class LocationLogger class LocationLogger
: public boost::log::sources::basic_composite_logger< : public boost::log::sources::basic_composite_logger<
char, LocationLogger<LevelT>, boost::log::sources::multi_thread_model<boost::log::aux::light_rw_mutex>, char, LocationLogger<LevelT>, boost::log::sources::multi_thread_model<boost::log::aux::light_rw_mutex>,
boost::log::sources::features<boost::log::sources::severity<LevelT>, FilenameTagger, LineTagger, boost::log::sources::features<boost::log::sources::severity<LevelT>, FilenameTagger, FunctionTagger,
CategoryTagger>> { LineTagger, CategoryTagger>> {
typedef typename LocationLogger::logger_base base_type; typedef typename LocationLogger::logger_base base_type;
public: public:
@ -180,12 +205,14 @@ BOOST_LOG_GLOBAL_LOGGER(location_logger, LocationLogger<boost::log::trivial::sev
BOOST_LOG_STREAM_WITH_PARAMS(::location_logger::get(),\ BOOST_LOG_STREAM_WITH_PARAMS(::location_logger::get(),\
(::boost::log::keywords::severity = ::boost::log::trivial::lvl) \ (::boost::log::keywords::severity = ::boost::log::trivial::lvl) \
(AmassKeywords::FilenameTag = (AmassKeywords::fileName(__FILE__))) \ (AmassKeywords::FilenameTag = (AmassKeywords::fileName(__FILE__))) \
(AmassKeywords::FunctionTag = __func__) \
(AmassKeywords::LineTag = __LINE__)) (AmassKeywords::LineTag = __LINE__))
#define LOG_CAT( lvl, cat) \ #define LOG_CAT( lvl, cat) \
BOOST_LOG_STREAM_WITH_PARAMS(::location_logger::get(),\ BOOST_LOG_STREAM_WITH_PARAMS(::location_logger::get(),\
(::boost::log::keywords::severity = ::boost::log::trivial::lvl) \ (::boost::log::keywords::severity = ::boost::log::trivial::lvl) \
(AmassKeywords::FilenameTag = (AmassKeywords::fileName(__FILE__))) \ (AmassKeywords::FilenameTag = (AmassKeywords::fileName(__FILE__))) \
(AmassKeywords::FunctionTag = __func__) \
(AmassKeywords::LineTag = __LINE__) \ (AmassKeywords::LineTag = __LINE__) \
(AmassKeywords::CategoryTag = #cat)) (AmassKeywords::CategoryTag = #cat))

View File

@ -125,6 +125,36 @@ boost::log::record FilenameTaggerFeature<BaseT>::open_record_unlocked(const Args
return BaseT::open_record_unlocked(args); return BaseT::open_record_unlocked(args);
} }
template <typename BaseT>
FunctionTaggerFeature<BaseT>::FunctionTaggerFeature(const FunctionTaggerFeature &obj)
: BaseT(static_cast<const BaseT &>(obj)) {
}
template <typename BaseT>
template <typename ArgsT>
FunctionTaggerFeature<BaseT>::FunctionTaggerFeature(const ArgsT &args) : BaseT(args) {}
template <typename BaseT>
template <typename ArgsT>
boost::log::record FunctionTaggerFeature<BaseT>::open_record_unlocked(const ArgsT &args) {
std::string tag_value = args[AmassKeywords::FunctionTag | std::string()];
boost::log::attribute_set &attrs = BaseT::attributes();
boost::log::attribute_set::iterator tag = attrs.end();
if (!tag_value.empty()) {
// Add the tag as a new attribute
std::pair<boost::log::attribute_set::iterator, bool> res =
BaseT::add_attribute_unlocked("Function", boost::log::attributes::constant<std::string>(tag_value));
if (res.second) tag = res.first;
}
BOOST_SCOPE_EXIT_TPL((&tag)(&attrs)) {
if (tag != attrs.end()) attrs.erase(tag);
}
BOOST_SCOPE_EXIT_END
return BaseT::open_record_unlocked(args);
}
template <typename BaseT> template <typename BaseT>
template <typename ArgsT> template <typename ArgsT>
LineTaggerFeature<BaseT>::LineTaggerFeature(const ArgsT &args) : BaseT(args) {} LineTaggerFeature<BaseT>::LineTaggerFeature(const ArgsT &args) : BaseT(args) {}

View File

@ -1,6 +1,7 @@
find_package(Boost REQUIRED COMPONENTS log log_setup program_options) find_package(Boost REQUIRED COMPONENTS log log_setup program_options)
add_library(Universal add_library(Universal
ApplicationSettings.h
BoostLog.h BoostLog.inl BoostLog.cpp BoostLog.h BoostLog.inl BoostLog.cpp
BufferUtility.h BufferUtility.cpp BufferUtility.h BufferUtility.cpp
DateTime.h DateTime.cpp DateTime.h DateTime.cpp
@ -14,6 +15,10 @@ add_library(Universal
StringUtility.h StringUtility.cpp StringUtility.h StringUtility.cpp
) )
set_property(TARGET Universal
PROPERTY POSITION_INDEPENDENT_CODE ON
)
if(CMAKE_VERSION VERSION_LESS 3.20) if(CMAKE_VERSION VERSION_LESS 3.20)
get_filename_component(KYLIN_CORE_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) get_filename_component(KYLIN_CORE_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
if(NOT Boost_USE_STATIC_LIBS) if(NOT Boost_USE_STATIC_LIBS)

View File

@ -36,6 +36,11 @@ public:
std::chrono::time_point<std::chrono::system_clock> operator()(); std::chrono::time_point<std::chrono::system_clock> operator()();
std::string toString(const std::string_view &format = "%F %T") const; std::string toString(const std::string_view &format = "%F %T") const;
/**
* @brief 2023-10-12 12:10:23 then return 2023-10-13 12:10:23
*
* @return DateTime
*/
DateTime tomorrow(); DateTime tomorrow();
// Returns the number of milliseconds since 1970-01-01T00:00:00 Universal Coordinated Time. This number is like the // Returns the number of milliseconds since 1970-01-01T00:00:00 Universal Coordinated Time. This number is like the

View File

@ -1,6 +1,7 @@
#include "IoContext.h" #include "IoContext.h"
#include <boost/asio/executor_work_guard.hpp> #include <boost/asio/executor_work_guard.hpp>
#include <boost/scope_exit.hpp> #include <boost/scope_exit.hpp>
#include <boost/stacktrace.hpp>
IoContext::~IoContext() { IoContext::~IoContext() {
m_ioContext->stop(); m_ioContext->stop();
@ -23,6 +24,7 @@ void IoContext::runIoContext() {
} catch (const boost::exception &e) { } catch (const boost::exception &e) {
LOG(error) << boost::diagnostic_information(e); LOG(error) << boost::diagnostic_information(e);
} catch (const std::exception &e) { } catch (const std::exception &e) {
LOG(error) << e.what(); boost::stacktrace::stacktrace trace = boost::stacktrace::stacktrace::from_current_exception();
LOG(error) << e.what() << ", trace:\n" << trace;
} }
} }

View File

@ -1,8 +1,10 @@
#include "StringUtility.h" #include "StringUtility.h"
#include "BoostLog.h" #include "BoostLog.h"
#include <algorithm>
#include <cctype> #include <cctype>
#include <codecvt> #include <codecvt>
#ifdef WIN32
#include <Windows.h>
#endif
namespace Amass { namespace Amass {
@ -54,6 +56,18 @@ std::wstring stringToWString(const std::string &string) {
return converter.from_bytes(string); return converter.from_bytes(string);
} }
std::string wstringToString(const std::wstring &string) {
#ifdef WIN32
int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, string.c_str(), string.size(), NULL, 0, NULL, NULL);
std::string ret(sizeNeeded, 0);
WideCharToMultiByte(CP_UTF8, 0, string.c_str(), string.size(), &ret[0], sizeNeeded, NULL, NULL);
#else
std::string ret;
assert(false && "not implement.");
#endif
return ret;
}
bool equal(std::string_view lhs, std::string_view rhs, bool caseSensitivity) { bool equal(std::string_view lhs, std::string_view rhs, bool caseSensitivity) {
auto n = lhs.size(); auto n = lhs.size();
if (rhs.size() != n) return false; if (rhs.size() != n) return false;
@ -82,5 +96,25 @@ slow:
return true; return true;
} }
std::string UTF8ToGBK(const std::string &utf8Str) {
int wideStrLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, NULL, 0);
if (wideStrLen == 0) {
return "";
}
std::wstring wideStr(wideStrLen, 0);
MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &wideStr[0], wideStrLen);
int gbkStrLen = WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, NULL, 0, NULL, NULL);
if (gbkStrLen == 0) {
return "";
}
std::string gbkStr(gbkStrLen, 0);
WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, &gbkStr[0], gbkStrLen, NULL, NULL);
return gbkStr;
}
} // namespace StringUtility } // namespace StringUtility
} // namespace Amass } // namespace Amass

View File

@ -60,6 +60,8 @@ size_t utf8Length(const std::string &text);
std::string_view utf8At(const std::string &text, size_t index); std::string_view utf8At(const std::string &text, size_t index);
size_t utf8CharacterByteSize(const char *character); size_t utf8CharacterByteSize(const char *character);
std::wstring stringToWString(const std::string &string); std::wstring stringToWString(const std::string &string);
std::string wstringToString(const std::wstring &string);
std::string UTF8ToGBK(const std::string &utf8Str);
} // namespace StringUtility } // namespace StringUtility

View File

@ -1,9 +1,9 @@
#!/bin/bash #!/bin/bash
base_path=$(pwd) base_path=$(pwd)
qt_prefix_path="/opt/Qt/6.6.1/gcc_64" qt_prefix_path="/opt/Qt/6.6.2/gcc_64"
libraries_root="/opt/Libraries" libraries_root="/opt/Libraries"
if [ $base_path==/home/* ]; then if [ $base_path == /home/* ]; then
build_path=${base_path}/build build_path=${base_path}/build
else else
build_path=/tmp/build build_path=/tmp/build
@ -35,7 +35,7 @@ elif [ -d "/opt/Qt/5.15.2/gcc_64" ]; then
-DQt5Svg_DIR=${qt_prefix_path}/lib/cmake/Qt5Svg " -DQt5Svg_DIR=${qt_prefix_path}/lib/cmake/Qt5Svg "
else else
cmake_qt_parameters="" cmake_qt_parameters=""
echo "please install qt6.6.1 or qt5.15.2 ..." echo "please install qt6.6.2 or qt5.15.2 ..."
fi fi
function cmake_scan() { function cmake_scan() {
@ -48,7 +48,7 @@ function cmake_scan() {
-B ${build_path} \ -B ${build_path} \
-DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_BUILD_TYPE=Debug \
-DUNIT_TEST=ON \ -DUNIT_TEST=ON \
-DBOOST_ROOT=${libraries_root}/boost_1_84_0 \ -DBOOST_ROOT=${libraries_root}/boost_1_85_0 \
-DZeroMQ_ROOT=${libraries_root}/zeromq-4.3.4_debug \ -DZeroMQ_ROOT=${libraries_root}/zeromq-4.3.4_debug \
${cmake_qt_parameters} ${cmake_qt_parameters}
} }
@ -66,7 +66,7 @@ function build() {
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
exit 1 exit 1
fi fi
build/UnitTest/UnitTest $build_path/UnitTest/UnitTest
} }
function main() { function main() {