Compare commits
29 Commits
16a818c95e
...
9eecbbab6e
| Author | SHA1 | Date | |
|---|---|---|---|
| 9eecbbab6e | |||
| 3641e636d2 | |||
| 4acab04895 | |||
| aa963a4bda | |||
| bdd18b614f | |||
| e186e0adff | |||
| f105f616f6 | |||
|
|
b99c51181d | ||
|
|
bc6b584480 | ||
| eb97de1413 | |||
| 97f1c25ff8 | |||
| 97aad47a21 | |||
| 43bd1d8550 | |||
|
|
3255199b3f | ||
| 224412e20a | |||
| 000ce2a54d | |||
|
|
f992bf4cbb | ||
|
|
96625bd93d | ||
| 9d4357c066 | |||
| 7a945f47b1 | |||
| 9a352bfc83 | |||
| aa2f117075 | |||
| bf5bb45771 | |||
| cdc966bd8c | |||
| 17b902ebcc | |||
| 996b7ea403 | |||
| da4b09be9e | |||
| b24b5a1346 | |||
| 0d94699206 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,4 +3,5 @@
|
||||
/doc/rtf
|
||||
_unsused
|
||||
CMakeLists.txt.user*
|
||||
/include
|
||||
/include
|
||||
/release
|
||||
|
||||
@@ -75,11 +75,15 @@ option(INTROSPECTION "Build with introspection" OFF)
|
||||
option(TESTS "Build tests and perform their before install step" ${PIP_BUILD_DEBUG})
|
||||
option(COVERAGE "Build project with coverage info" OFF)
|
||||
set(PIP_UTILS 1)
|
||||
set(BUILDING_pip 1 PARENT_SCOPE)
|
||||
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
shstk_is_parent_exists(_pe)
|
||||
if (_pe)
|
||||
set(BUILDING_pip 1 PARENT_SCOPE)
|
||||
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
|
||||
# Basic
|
||||
set(PIP_MODULES)
|
||||
@@ -92,7 +96,7 @@ set(PIP_UTILS_LIST)
|
||||
set(PIP_TESTS_LIST)
|
||||
set(PIP_EXPORTS)
|
||||
|
||||
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;cloud;lua")
|
||||
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua")
|
||||
foreach(_m ${PIP_SRC_MODULES})
|
||||
set(PIP_MSG_${_m} "no")
|
||||
endforeach()
|
||||
@@ -392,6 +396,7 @@ if (NOT CROSSTOOLS)
|
||||
pip_find_lib(sodium)
|
||||
if(sodium_FOUND)
|
||||
pip_module(crypt "sodium" "PIP crypt support" "" "" "")
|
||||
pip_module(client_server "pip_io_utils" "PIP client-server helper" "" "" "")
|
||||
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
|
||||
endif()
|
||||
|
||||
@@ -480,7 +485,7 @@ if (NOT CROSSTOOLS)
|
||||
#target_link_libraries(pip_plugin pip)
|
||||
|
||||
add_executable(pip_test "main.cpp")
|
||||
target_link_libraries(pip_test pip pip_io_utils)
|
||||
target_link_libraries(pip_test pip pip_io_utils pip_client_server)
|
||||
if(sodium_FOUND)
|
||||
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
||||
target_link_libraries(pip_cloud_test pip_cloud)
|
||||
@@ -585,7 +590,7 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
set(DOXY_DEFINES "${PIP_EXPORTS}")
|
||||
foreach (_m "console" "usb" "compress" "crypt" "cloud" "fftw" "opencl" "io_utils" "lua")
|
||||
foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua")
|
||||
string(TOUPPER "${_m}" _mdef)
|
||||
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
|
||||
endforeach()
|
||||
|
||||
@@ -9,6 +9,7 @@ Create imported targets:
|
||||
* PIP::FFTW
|
||||
* PIP::OpenCL
|
||||
* PIP::IOUtils
|
||||
* PIP::ClientServer
|
||||
* PIP::Cloud
|
||||
* PIP::Lua
|
||||
|
||||
@@ -22,7 +23,7 @@ include(SHSTKMacros)
|
||||
|
||||
shstk_set_find_dirs(PIP)
|
||||
|
||||
set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua")
|
||||
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua")
|
||||
|
||||
if (BUILDING_PIP)
|
||||
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua")
|
||||
@@ -83,15 +84,16 @@ if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION)
|
||||
message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!")
|
||||
endif()
|
||||
|
||||
set(__module_usb USB )
|
||||
set(__module_console Console )
|
||||
set(__module_crypt Crypt )
|
||||
set(__module_fftw FFTW )
|
||||
set(__module_compress Compress )
|
||||
set(__module_opencl OpenCL )
|
||||
set(__module_io_utils IOUtils )
|
||||
set(__module_cloud Cloud )
|
||||
set(__module_lua Lua )
|
||||
set(__module_usb USB )
|
||||
set(__module_console Console )
|
||||
set(__module_crypt Crypt )
|
||||
set(__module_fftw FFTW )
|
||||
set(__module_compress Compress )
|
||||
set(__module_opencl OpenCL )
|
||||
set(__module_io_utils IOUtils )
|
||||
set(__module_client_server ClientServer)
|
||||
set(__module_cloud Cloud )
|
||||
set(__module_lua Lua )
|
||||
|
||||
foreach (_l ${__libs})
|
||||
set( __inc_${_l} "")
|
||||
@@ -99,8 +101,9 @@ foreach (_l ${__libs})
|
||||
set(__libs_${_l} "")
|
||||
endforeach()
|
||||
|
||||
set(__deps_io_utils "PIP::Crypt")
|
||||
set(__deps_cloud "PIP::IOUtils")
|
||||
set(__deps_io_utils "PIP::Crypt" )
|
||||
set(__deps_client_server "PIP::IOUtils")
|
||||
set(__deps_cloud "PIP::IOUtils")
|
||||
|
||||
|
||||
if (BUILDING_PIP)
|
||||
|
||||
54
libs/client_server/piclientserver_client.cpp
Normal file
54
libs/client_server/piclientserver_client.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piclientserver_client.h"
|
||||
|
||||
#include "piclientserver_server.h"
|
||||
#include "piethernet.h"
|
||||
|
||||
|
||||
void PIClientServer::ServerClient::createForServer(Server * parent, PIEthernet * tcp_) {
|
||||
tcp = tcp_;
|
||||
tcp->setParameter(PIEthernet::KeepConnection, false);
|
||||
init();
|
||||
CONNECTL(tcp, disconnected, ([this, parent](bool) { parent->clientDisconnected(this); }));
|
||||
}
|
||||
|
||||
|
||||
PIClientServer::Client::Client() {
|
||||
tcp = new PIEthernet(PIEthernet::TCP_Client);
|
||||
tcp->setParameter(PIEthernet::KeepConnection, true);
|
||||
own_tcp = true;
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
PIClientServer::Client::~Client() {
|
||||
if (tcp) tcp->setDebug(false);
|
||||
close();
|
||||
stopAndWait();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Client::connect(PINetworkAddress addr) {
|
||||
if (!tcp || !own_tcp) return;
|
||||
close();
|
||||
config.apply(this);
|
||||
tcp->connect(addr, true);
|
||||
tcp->startThreadedRead();
|
||||
}
|
||||
95
libs/client_server/piclientserver_client_base.cpp
Normal file
95
libs/client_server/piclientserver_client_base.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piclientserver_client_base.h"
|
||||
|
||||
#include "piethernet.h"
|
||||
#include "piliterals_time.h"
|
||||
|
||||
|
||||
PIClientServer::ClientBase::ClientBase() {}
|
||||
|
||||
|
||||
PIClientServer::ClientBase::~ClientBase() {
|
||||
close();
|
||||
stopAndWait();
|
||||
if (own_tcp) piDeleteSafety(tcp);
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::close() {
|
||||
if (!tcp) return;
|
||||
can_write = false;
|
||||
tcp->stop();
|
||||
stream.clear();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::stopAndWait() {
|
||||
if (!tcp) return;
|
||||
tcp->stopAndWait(10_s);
|
||||
if (tcp->isThreadedRead()) tcp->terminateThreadedRead();
|
||||
tcp->close();
|
||||
stream.clear();
|
||||
}
|
||||
|
||||
|
||||
int PIClientServer::ClientBase::write(const void * d, const size_t s) {
|
||||
if (!tcp) return -1;
|
||||
if (!can_write) return 0;
|
||||
PIMutexLocker guard(write_mutex);
|
||||
// piCout << "... send ...";
|
||||
stream.send(PIByteArray(d, s));
|
||||
// piCout << "... send ok";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::init() {
|
||||
if (!tcp) return;
|
||||
CONNECTL(&stream, sendRequest, [this](const PIByteArray & ba) {
|
||||
if (!can_write) return;
|
||||
tcp->send(ba);
|
||||
// piMSleep(1);
|
||||
});
|
||||
CONNECTL(&stream, packetReceiveEvent, [this](PIByteArray & ba) { readed(ba); });
|
||||
CONNECTL(tcp, threadedReadEvent, [this](const uchar * readed, ssize_t size) {
|
||||
if (!can_write) return;
|
||||
stream.received(readed, size);
|
||||
});
|
||||
CONNECTL(tcp, connected, [this]() {
|
||||
can_write = true;
|
||||
// piCout << "Connected";
|
||||
connected();
|
||||
});
|
||||
CONNECTL(tcp, disconnected, [this](bool) {
|
||||
can_write = false;
|
||||
stream.clear();
|
||||
// piCout << "Disconnected";
|
||||
disconnected();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::destroy() {
|
||||
write_mutex.lock();
|
||||
close();
|
||||
piDeleteSafety(tcp);
|
||||
write_mutex.unlock();
|
||||
// piCout << "Destroyed";
|
||||
}
|
||||
50
libs/client_server/piclientserver_config.cpp
Normal file
50
libs/client_server/piclientserver_config.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piclientserver_config.h"
|
||||
|
||||
#include "piclientserver_client_base.h"
|
||||
|
||||
|
||||
void PIClientServer::Config::setPacketSign(ushort sign) {
|
||||
packet_sign = sign;
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Config::setPacketSize(int bytes) {
|
||||
packet_size = bytes;
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Config::enableSymmetricEncryption(const PIByteArray & key) {
|
||||
crypt_key = key;
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Config::apply(ClientBase * client) {
|
||||
auto & s(client->stream);
|
||||
|
||||
s.setPacketSign(packet_sign);
|
||||
s.setMaxPacketSize(packet_size);
|
||||
|
||||
if (crypt_key.isNotEmpty()) {
|
||||
s.setCryptEnabled(true);
|
||||
s.setCryptKey(crypt_key);
|
||||
} else
|
||||
s.setCryptEnabled(false);
|
||||
}
|
||||
143
libs/client_server/piclientserver_server.cpp
Normal file
143
libs/client_server/piclientserver_server.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piclientserver_server.h"
|
||||
|
||||
#include "piclientserver_client.h"
|
||||
#include "piethernet.h"
|
||||
#include "piliterals_time.h"
|
||||
|
||||
|
||||
PIClientServer::Server::Server() {
|
||||
tcp_server = new PIEthernet(PIEthernet::TCP_Server);
|
||||
clean_thread = new PIThread();
|
||||
client_factory = [] { return new ServerClient(); };
|
||||
CONNECTL(tcp_server, newConnection, [this](PIEthernet * c) {
|
||||
PIMutexLocker guard(clients_mutex);
|
||||
if (clients.size_s() >= max_clients) {
|
||||
piCout << "Server::newConnection overflow clients count";
|
||||
delete c;
|
||||
return;
|
||||
}
|
||||
auto sc = client_factory();
|
||||
if (!sc) {
|
||||
piCout << "ClientFactory returns nullptr!";
|
||||
return;
|
||||
}
|
||||
sc->createForServer(this, c);
|
||||
newClient(sc);
|
||||
});
|
||||
|
||||
clean_thread->start([this]() {
|
||||
clean_notifier.wait();
|
||||
PIVector<ServerClient *> to_delete;
|
||||
clients_mutex.lock();
|
||||
for (auto c: clients) {
|
||||
const PIEthernet * eth = c->getTCP();
|
||||
if (!eth) continue;
|
||||
if (eth->isConnected()) continue;
|
||||
c->can_write = false;
|
||||
to_delete << c;
|
||||
}
|
||||
for (auto c: to_delete)
|
||||
clients.removeOne(c);
|
||||
clients_mutex.unlock();
|
||||
for (auto c: to_delete) {
|
||||
c->aboutDelete();
|
||||
c->destroy();
|
||||
delete c;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
PIClientServer::Server::~Server() {
|
||||
clean_thread->stop();
|
||||
clean_notifier.notify();
|
||||
clean_thread->waitForFinish();
|
||||
piDeleteSafety(clean_thread);
|
||||
stopServer();
|
||||
for (auto c: clients) {
|
||||
c->aboutDelete();
|
||||
c->destroy();
|
||||
delete c;
|
||||
}
|
||||
piDeleteSafety(tcp_server);
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::listen(PINetworkAddress addr) {
|
||||
if (!tcp_server) return;
|
||||
stopServer();
|
||||
is_closing = false;
|
||||
tcp_server->listen(addr, true);
|
||||
// piCout << "Listen on" << addr.toString();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::closeAll() {
|
||||
clients_mutex.lock();
|
||||
for (auto c: clients) {
|
||||
c->aboutDelete();
|
||||
c->destroy();
|
||||
delete c;
|
||||
}
|
||||
clients.clear();
|
||||
clients_mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::setMaxClients(int new_max_clients) {
|
||||
max_clients = new_max_clients;
|
||||
}
|
||||
|
||||
|
||||
int PIClientServer::Server::clientsCount() const {
|
||||
PIMutexLocker guard(clients_mutex);
|
||||
return clients.size_s();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::forEachClient(std::function<void(ServerClient *)> func) {
|
||||
PIMutexLocker guard(clients_mutex);
|
||||
for (auto * c: clients) {
|
||||
func(c);
|
||||
if (is_closing) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::stopServer() {
|
||||
if (!tcp_server) return;
|
||||
is_closing = true;
|
||||
tcp_server->stopThreadedListen();
|
||||
tcp_server->stopAndWait();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::newClient(ServerClient * c) {
|
||||
clients << c;
|
||||
config.apply(c);
|
||||
c->tcp->startThreadedRead();
|
||||
c->connected();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::clientDisconnected(ServerClient * c) {
|
||||
clean_notifier.notify();
|
||||
}
|
||||
@@ -120,6 +120,7 @@ void PIStreamPacker::send(const PIByteArray & data) {
|
||||
|
||||
|
||||
void PIStreamPacker::received(const uchar * readed, ssize_t size) {
|
||||
if (size <= 0) return;
|
||||
received(PIByteArray(readed, size));
|
||||
}
|
||||
|
||||
|
||||
58
libs/main/application/piapplicationmodule.h
Normal file
58
libs/main/application/piapplicationmodule.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//! \defgroup Application Application
|
||||
//! \~\brief
|
||||
//! \~english Application-level classes.
|
||||
//! \~russian Классы уровня "приложение".
|
||||
//!
|
||||
//! \~\details
|
||||
//! \~english \section cmake_module_Application Building with CMake
|
||||
//! \~russian \section cmake_module_Application Сборка с использованием CMake
|
||||
//!
|
||||
//! \~\code
|
||||
//! find_package(PIP REQUIRED)
|
||||
//! target_link_libraries([target] PIP)
|
||||
//! \endcode
|
||||
//!
|
||||
//! \~english \par Common
|
||||
//! \~russian \par Общее
|
||||
//!
|
||||
//! \~english
|
||||
//! These files provides some classes for help to create application
|
||||
//!
|
||||
//! \~russian
|
||||
//! Эти файлы предоставляют классы для облегчения создания приложения
|
||||
//!
|
||||
//! \~\authors
|
||||
//! \~english
|
||||
//! Ivan Pelipenko peri4ko@yandex.ru;
|
||||
//! Andrey Bychkov work.a.b@yandex.ru;
|
||||
//! \~russian
|
||||
//! Иван Пелипенко peri4ko@yandex.ru;
|
||||
//! Андрей Бычков work.a.b@yandex.ru;
|
||||
//!
|
||||
|
||||
#ifndef PIAPPLICATIONMODULE_H
|
||||
#define PIAPPLICATIONMODULE_H
|
||||
|
||||
#include "picli.h"
|
||||
#include "pisingleapplication.h"
|
||||
#include "pisystemmonitor.h"
|
||||
|
||||
#endif
|
||||
@@ -69,11 +69,6 @@
|
||||
|
||||
|
||||
PICLI::PICLI(int argc, char * argv[]) {
|
||||
needParse = debug_ = true;
|
||||
_prefix_short = "-";
|
||||
_prefix_full = "--";
|
||||
_count_opt = 0;
|
||||
_count_mand = 0;
|
||||
for (int i = 0; i < argc; ++i)
|
||||
_args_raw << argv[i];
|
||||
if (argc > 0) PISystemInfo::instance()->execCommand = argv[0];
|
||||
@@ -89,7 +84,7 @@ void PICLI::parse() {
|
||||
if (cra.left(2) == _prefix_full) {
|
||||
last = 0;
|
||||
full = cra.right(cra.length() - 2);
|
||||
piForeach(Argument & a, _args) {
|
||||
for (auto & a: _args) {
|
||||
if (a.full_key == full) {
|
||||
a.found = true;
|
||||
last = &a;
|
||||
@@ -101,7 +96,7 @@ void PICLI::parse() {
|
||||
last = 0;
|
||||
for (int j = 1; j < cra.length(); ++j) {
|
||||
bool found = false;
|
||||
piForeach(Argument & a, _args) {
|
||||
for (auto & a: _args) {
|
||||
if ((a.short_key != '\0') && (a.short_key == cra[j])) {
|
||||
a.found = true;
|
||||
last = &a;
|
||||
@@ -121,7 +116,7 @@ void PICLI::parse() {
|
||||
_args_opt << cra;
|
||||
continue;
|
||||
}
|
||||
piCoutObj << "[PICli] Arguments overflow, \"" << cra << "\" ignored";
|
||||
piCoutObj << "Arguments overflow, \"" << cra << "\" ignored";
|
||||
}
|
||||
if (last == 0 ? false : last->has_value) {
|
||||
last->value = cra;
|
||||
@@ -132,3 +127,129 @@ void PICLI::parse() {
|
||||
}
|
||||
needParse = false;
|
||||
}
|
||||
|
||||
|
||||
void PICLI::addArgument(const PIString & name, bool value) {
|
||||
_args << Argument(name, name[0], name, value);
|
||||
needParse = true;
|
||||
}
|
||||
|
||||
|
||||
void PICLI::addArgument(const PIString & name, const PIChar & shortKey, bool value) {
|
||||
_args << Argument(name, shortKey, name, value);
|
||||
needParse = true;
|
||||
}
|
||||
|
||||
|
||||
void PICLI::addArgument(const PIString & name, const char * shortKey, bool value) {
|
||||
_args << Argument(name, PIChar::fromUTF8(shortKey), name, value);
|
||||
needParse = true;
|
||||
}
|
||||
|
||||
|
||||
void PICLI::addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value) {
|
||||
_args << Argument(name, shortKey, fullKey, value);
|
||||
needParse = true;
|
||||
}
|
||||
|
||||
|
||||
void PICLI::addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value) {
|
||||
_args << Argument(name, PIChar::fromUTF8(shortKey), fullKey, value);
|
||||
needParse = true;
|
||||
}
|
||||
|
||||
|
||||
PIString PICLI::rawArgument(int index) {
|
||||
parse();
|
||||
return _args_raw[index];
|
||||
}
|
||||
|
||||
|
||||
PIString PICLI::mandatoryArgument(int index) {
|
||||
parse();
|
||||
return _args_mand[index];
|
||||
}
|
||||
|
||||
|
||||
PIString PICLI::optionalArgument(int index) {
|
||||
parse();
|
||||
return _args_opt[index];
|
||||
}
|
||||
|
||||
|
||||
const PIStringList & PICLI::rawArguments() {
|
||||
parse();
|
||||
return _args_raw;
|
||||
}
|
||||
|
||||
|
||||
const PIStringList & PICLI::mandatoryArguments() {
|
||||
parse();
|
||||
return _args_mand;
|
||||
}
|
||||
|
||||
|
||||
const PIStringList & PICLI::optionalArguments() {
|
||||
parse();
|
||||
return _args_opt;
|
||||
}
|
||||
|
||||
|
||||
PIString PICLI::programCommand() {
|
||||
parse();
|
||||
return _args_raw.isNotEmpty() ? _args_raw.front() : PIString();
|
||||
}
|
||||
|
||||
|
||||
bool PICLI::hasArgument(const PIString & name) {
|
||||
parse();
|
||||
for (const auto & i: _args)
|
||||
if (i.name == name && i.found) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIString PICLI::argumentValue(const PIString & name) {
|
||||
parse();
|
||||
for (const auto & i: _args)
|
||||
if (i.name == name && i.found) return i.value;
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PICLI::argumentShortKey(const PIString & name) {
|
||||
for (const auto & i: _args)
|
||||
if (i.name == name) return PIString(i.short_key);
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PICLI::argumentFullKey(const PIString & name) {
|
||||
for (const auto & i: _args)
|
||||
if (i.name == name) return i.full_key;
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
void PICLI::setShortKeyPrefix(const PIString & prefix) {
|
||||
_prefix_short = prefix;
|
||||
needParse = true;
|
||||
}
|
||||
|
||||
|
||||
void PICLI::setFullKeyPrefix(const PIString & prefix) {
|
||||
_prefix_full = prefix;
|
||||
needParse = true;
|
||||
}
|
||||
|
||||
|
||||
void PICLI::setMandatoryArgumentsCount(const int count) {
|
||||
_count_mand = count;
|
||||
needParse = true;
|
||||
}
|
||||
|
||||
|
||||
void PICLI::setOptionalArgumentsCount(const int count) {
|
||||
_count_opt = count;
|
||||
needParse = true;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*! \file picli.h
|
||||
* \ingroup Core
|
||||
* \ingroup Application
|
||||
* \~\brief
|
||||
* \~english Command-Line parser
|
||||
* \~russian Парсер командной строки
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "piset.h"
|
||||
#include "pistringlist.h"
|
||||
|
||||
//! \ingroup Core
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Command-Line parser.
|
||||
//! \~russian Парсер командной строки.
|
||||
@@ -42,131 +42,65 @@ public:
|
||||
|
||||
//! \~english Add argument with name "name", short key = name first letter and full key = name.
|
||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени.
|
||||
void addArgument(const PIString & name, bool value = false) {
|
||||
_args << Argument(name, name[0], name, value);
|
||||
needParse = true;
|
||||
}
|
||||
void addArgument(const PIString & name, bool value = false);
|
||||
|
||||
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
|
||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
|
||||
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {
|
||||
_args << Argument(name, shortKey, name, value);
|
||||
needParse = true;
|
||||
}
|
||||
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false);
|
||||
|
||||
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
|
||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
|
||||
void addArgument(const PIString & name, const char * shortKey, bool value = false) {
|
||||
_args << Argument(name, PIChar::fromUTF8(shortKey), name, value);
|
||||
needParse = true;
|
||||
}
|
||||
void addArgument(const PIString & name, const char * shortKey, bool value = false);
|
||||
|
||||
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
|
||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
|
||||
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {
|
||||
_args << Argument(name, shortKey, fullKey, value);
|
||||
needParse = true;
|
||||
}
|
||||
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false);
|
||||
|
||||
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
|
||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
|
||||
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {
|
||||
_args << Argument(name, PIChar::fromUTF8(shortKey), fullKey, value);
|
||||
needParse = true;
|
||||
}
|
||||
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false);
|
||||
|
||||
|
||||
//! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command.
|
||||
//! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы.
|
||||
PIString rawArgument(int index) {
|
||||
parse();
|
||||
return _args_raw[index];
|
||||
}
|
||||
PIString mandatoryArgument(int index) {
|
||||
parse();
|
||||
return _args_mand[index];
|
||||
}
|
||||
PIString optionalArgument(int index) {
|
||||
parse();
|
||||
return _args_opt[index];
|
||||
}
|
||||
PIString rawArgument(int index);
|
||||
PIString mandatoryArgument(int index);
|
||||
PIString optionalArgument(int index);
|
||||
|
||||
//! \~english Returns unparsed command-line arguments.
|
||||
//! \~russian Возвращает исходные аргументы командной строки.
|
||||
const PIStringList & rawArguments() {
|
||||
parse();
|
||||
return _args_raw;
|
||||
}
|
||||
const PIStringList & mandatoryArguments() {
|
||||
parse();
|
||||
return _args_mand;
|
||||
}
|
||||
const PIStringList & optionalArguments() {
|
||||
parse();
|
||||
return _args_opt;
|
||||
}
|
||||
const PIStringList & rawArguments();
|
||||
const PIStringList & mandatoryArguments();
|
||||
const PIStringList & optionalArguments();
|
||||
|
||||
//! \~english Returns program execute command without arguments.
|
||||
//! \~russian Возвращает команду вызова программы без аргументов.
|
||||
PIString programCommand() {
|
||||
parse();
|
||||
return _args_raw.size() > 0 ? _args_raw.front() : PIString();
|
||||
}
|
||||
PIString programCommand();
|
||||
|
||||
//! \~english Returns if argument "name" found.
|
||||
//! \~russian Возвращает найден ли аргумент "name".
|
||||
bool hasArgument(const PIString & name) {
|
||||
parse();
|
||||
piForeach(Argument & i, _args)
|
||||
if (i.name == name && i.found) return true;
|
||||
return false;
|
||||
}
|
||||
bool hasArgument(const PIString & name);
|
||||
|
||||
//! \~english Returns argument "name" value, or empty string if this is no value.
|
||||
//! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет.
|
||||
PIString argumentValue(const PIString & name) {
|
||||
parse();
|
||||
piForeach(Argument & i, _args)
|
||||
if (i.name == name && i.found) return i.value;
|
||||
return PIString();
|
||||
}
|
||||
PIString argumentValue(const PIString & name);
|
||||
|
||||
//! \~english Returns short key of argument "name", or empty string if this is no argument.
|
||||
//! \~russian Возвращает короткий ключ аргумента "name" или пустую строку, если аргумента нет.
|
||||
PIString argumentShortKey(const PIString & name) {
|
||||
piForeach(Argument & i, _args)
|
||||
if (i.name == name) return PIString(i.short_key);
|
||||
return PIString();
|
||||
}
|
||||
PIString argumentShortKey(const PIString & name);
|
||||
|
||||
//! \~english Returns full key of argument "name", or empty string if this is no argument.
|
||||
//! \~russian Возвращает полный ключ аргумента "name" или пустую строку, если аргумента нет.
|
||||
PIString argumentFullKey(const PIString & name) {
|
||||
piForeach(Argument & i, _args)
|
||||
if (i.name == name) return i.full_key;
|
||||
return PIString();
|
||||
}
|
||||
PIString argumentFullKey(const PIString & name);
|
||||
|
||||
const PIString & shortKeyPrefix() const { return _prefix_short; }
|
||||
const PIString & fullKeyPrefix() const { return _prefix_full; }
|
||||
int mandatoryArgumentsCount() const { return _count_mand; }
|
||||
int optionalArgumentsCount() const { return _count_opt; }
|
||||
void setShortKeyPrefix(const PIString & prefix) {
|
||||
_prefix_short = prefix;
|
||||
needParse = true;
|
||||
}
|
||||
void setFullKeyPrefix(const PIString & prefix) {
|
||||
_prefix_full = prefix;
|
||||
needParse = true;
|
||||
}
|
||||
void setMandatoryArgumentsCount(const int count) {
|
||||
_count_mand = count;
|
||||
needParse = true;
|
||||
}
|
||||
void setOptionalArgumentsCount(const int count) {
|
||||
_count_opt = count;
|
||||
needParse = true;
|
||||
}
|
||||
void setShortKeyPrefix(const PIString & prefix);
|
||||
void setFullKeyPrefix(const PIString & prefix);
|
||||
void setMandatoryArgumentsCount(const int count);
|
||||
void setOptionalArgumentsCount(const int count);
|
||||
|
||||
bool debug() const { return debug_; }
|
||||
void setDebug(bool debug) { debug_ = debug; }
|
||||
@@ -175,29 +109,28 @@ public:
|
||||
|
||||
private:
|
||||
struct Argument {
|
||||
Argument() { has_value = found = false; }
|
||||
Argument() {}
|
||||
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {
|
||||
name = n;
|
||||
short_key = s;
|
||||
full_key = f;
|
||||
has_value = v;
|
||||
found = false;
|
||||
}
|
||||
PIString name;
|
||||
PIChar short_key;
|
||||
PIString full_key;
|
||||
PIString value;
|
||||
bool has_value, found;
|
||||
bool has_value = false, found = false;
|
||||
};
|
||||
|
||||
void parse();
|
||||
|
||||
PIString _prefix_short, _prefix_full;
|
||||
PIString _prefix_short = "-", _prefix_full = "--";
|
||||
PIStringList _args_raw, _args_mand, _args_opt;
|
||||
PISet<PIString> keys_full, keys_short;
|
||||
PIVector<Argument> _args;
|
||||
int _count_mand, _count_opt;
|
||||
bool needParse, debug_;
|
||||
int _count_mand = 0, _count_opt = 0;
|
||||
bool needParse = true, debug_ = true;
|
||||
};
|
||||
|
||||
#endif // PICLI_H
|
||||
229
libs/main/application/pilog.cpp
Normal file
229
libs/main/application/pilog.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
High-level log
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pilog.h"
|
||||
|
||||
#include "pidir.h"
|
||||
#include "piliterals_string.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pitime.h"
|
||||
|
||||
|
||||
//! \class PILog pilog.h
|
||||
//! \details
|
||||
//! \~english \section PILog_sec0 Synopsis
|
||||
//! \~russian \section PILog_sec0 Краткий обзор
|
||||
//! \~english
|
||||
//! This class provide handy parsing of command-line arguments. First you should add
|
||||
//! arguments to %PICLI with function \a addArgument(). Then you can check if there
|
||||
//! is some argument in application command-line with function \a hasArgument(),
|
||||
//! or obtain argument value by \a argumentValue().
|
||||
//!
|
||||
//! \~russian
|
||||
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
|
||||
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
|
||||
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
|
||||
//! а также получать их значения при помощи \a argumentValue().
|
||||
//!
|
||||
//! \~english \section PICLI_sec1 Example
|
||||
//! \~russian \section PICLI_sec1 Пример
|
||||
//! \~\code
|
||||
//! int main(int argc, char ** argv) {
|
||||
//! PICLI cli(argc, argv);
|
||||
//! cli.addArgument("console");
|
||||
//! cli.addArgument("debug");
|
||||
//! cli.addArgument("Value", "v", "value", true);
|
||||
//! if (cli.hasArgument("console"))
|
||||
//! piCout << "console active";
|
||||
//! if (cli.hasArgument("debug"))
|
||||
//! piCout << "debug active";
|
||||
//! piCout << "Value =" << cli.argumentValue("Value");
|
||||
//! return 0;
|
||||
//! }
|
||||
//! \endcode
|
||||
//!
|
||||
//! \~english These executions are similar:
|
||||
//! \~russian Эти вызовы будут идентичны:
|
||||
//!
|
||||
//! \~\code
|
||||
//! a.out -cd -v 10
|
||||
//! a.out --value 10 -dc
|
||||
//! a.out -c -v 10 -d
|
||||
//! a.out --console -d -v 10
|
||||
//! a.out --debug -c --value 10
|
||||
//! \endcode
|
||||
//!
|
||||
|
||||
|
||||
PILog::PILog(): PIThread(), log_ts(&log_file) {
|
||||
setName("PILog");
|
||||
split_time = 8_h;
|
||||
timestamp_format = "yyyy-MM-dd hh:mm:ss.zzz";
|
||||
setLineFormat("t - c: m");
|
||||
id_by_cat[Level::Info] = PICout::registerExternalBufferID();
|
||||
id_by_cat[Level::Debug] = PICout::registerExternalBufferID();
|
||||
id_by_cat[Level::Warning] = PICout::registerExternalBufferID();
|
||||
id_by_cat[Level::Error] = PICout::registerExternalBufferID();
|
||||
CONNECTU(PICout::Notifier::object(), finished, this, coutDone);
|
||||
}
|
||||
|
||||
|
||||
PILog::~PILog() {
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
void PILog::setDir(const PIString & d) {
|
||||
stopAndWait();
|
||||
log_dir = d;
|
||||
if (output[File]) {
|
||||
PIDir::make(log_dir);
|
||||
newFile();
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
void PILog::setLineFormat(const PIString & f) {
|
||||
line_format = f;
|
||||
line_format_p = line_format;
|
||||
line_format_p.replace("t", "${t}").replace("c", "${c}").replace("m", "${m}");
|
||||
}
|
||||
|
||||
|
||||
void PILog::setLevel(Level l) {
|
||||
max_level = l;
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::error(PIObject * context) {
|
||||
return makePICout(context, Level::Error);
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::warning(PIObject * context) {
|
||||
return makePICout(context, Level::Warning);
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::info(PIObject * context) {
|
||||
return makePICout(context, Level::Info);
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::debug(PIObject * context) {
|
||||
return makePICout(context, Level::Debug);
|
||||
}
|
||||
|
||||
|
||||
void PILog::stop() {
|
||||
while (true) {
|
||||
log_mutex.lock();
|
||||
bool done = queue.isEmpty();
|
||||
log_mutex.unlock();
|
||||
if (done) break;
|
||||
piMinSleep();
|
||||
}
|
||||
PIThread::stopAndWait();
|
||||
}
|
||||
|
||||
|
||||
void PILog::coutDone(int id, PIString * buffer) {
|
||||
if (!buffer) return;
|
||||
if (!id_by_cat.containsValue(id)) return;
|
||||
auto cat = id_by_cat.key(id, PILog::Level::Debug);
|
||||
if (cat > max_level) return;
|
||||
enqueue(*buffer, cat);
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::makePICout(PIObject * context, Level cat) {
|
||||
auto buffer = new PIString();
|
||||
if (context) {
|
||||
*buffer = "["_a + context->className();
|
||||
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
|
||||
*buffer += "] ";
|
||||
}
|
||||
return PICout::withExternalBuffer(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
|
||||
}
|
||||
|
||||
|
||||
void PILog::enqueue(const PIString & msg, Level cat) {
|
||||
auto t = PIDateTime::fromSystemTime(PISystemTime::current());
|
||||
PIMutexLocker ml(log_mutex);
|
||||
queue.enqueue({cat, t, msg});
|
||||
}
|
||||
|
||||
|
||||
PIString PILog::entryToString(const Entry & e) const {
|
||||
static PIStringList categories{"error", "warn ", "info ", "debug"};
|
||||
PIString t = e.time.toString(timestamp_format);
|
||||
PIString ret = line_format_p;
|
||||
ret.replace("${t}", t).replace("${c}", categories[static_cast<int>(e.cat)]).replace("${m}", e.msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PILog::newFile() {
|
||||
PIString aname = log_name;
|
||||
if (aname.isNotEmpty()) aname += "__";
|
||||
log_file.open(log_dir + "/" + aname + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss") + ".log." +
|
||||
PIString::fromNumber(++part_number),
|
||||
PIIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
|
||||
void PILog::run() {
|
||||
if (output[File]) {
|
||||
if (split_tm.elapsed() >= split_time) {
|
||||
split_tm.reset();
|
||||
newFile();
|
||||
}
|
||||
}
|
||||
log_mutex.lock();
|
||||
if (queue.isEmpty()) {
|
||||
log_mutex.unlock();
|
||||
piMSleep(20);
|
||||
return;
|
||||
}
|
||||
log_mutex.unlock();
|
||||
while (true) {
|
||||
log_mutex.lock();
|
||||
if (queue.isEmpty()) {
|
||||
log_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
auto qi = queue.dequeue();
|
||||
log_mutex.unlock();
|
||||
auto str = entryToString(qi);
|
||||
if (log_file.isOpened()) log_ts << str << "\n";
|
||||
if (output[Console]) {
|
||||
PICout out(qi.cat == Level::Error ? piCerr : piCout);
|
||||
if (color_console) {
|
||||
switch (qi.cat) {
|
||||
case Level::Error: out << PICoutManipulators::Red; break;
|
||||
case Level::Warning: out << PICoutManipulators::Yellow; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
out << str;
|
||||
}
|
||||
}
|
||||
}
|
||||
152
libs/main/application/pilog.h
Normal file
152
libs/main/application/pilog.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*! \file pilog.h
|
||||
* \ingroup Application
|
||||
* \~\brief
|
||||
* \~english High-level log
|
||||
* \~russian Высокоуровневый лог
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
High-level log
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIlog_H
|
||||
#define PIlog_H
|
||||
|
||||
#include "pifile.h"
|
||||
#include "piiostream.h"
|
||||
#include "pithread.h"
|
||||
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english High-level log
|
||||
//! \~russian Высокоуровневый лог
|
||||
class PIP_EXPORT PILog: public PIThread {
|
||||
PIOBJECT_SUBCLASS(PILog, PIThread)
|
||||
|
||||
public:
|
||||
PILog();
|
||||
~PILog();
|
||||
|
||||
enum class Level {
|
||||
Error,
|
||||
Warning,
|
||||
Info,
|
||||
Debug,
|
||||
};
|
||||
|
||||
enum Output {
|
||||
File = 0x1,
|
||||
Console = 0x2,
|
||||
All = 0xFF,
|
||||
};
|
||||
|
||||
//! \~english Set output target \"o\" to \"on\".
|
||||
void setOutput(Output o, bool on = true) { output.setFlag(o, on); }
|
||||
|
||||
//! \~english Returns prefix for filename.
|
||||
PIString logName() const { return log_name; }
|
||||
|
||||
//! \~english Set prefix for filename. Should be set \b before \a setDir()!
|
||||
void setLogName(const PIString & n) { log_name = n; }
|
||||
|
||||
//! \~english Returns if color for console output enabled.
|
||||
bool colorConsole() const { return color_console; }
|
||||
|
||||
//! \~english Set color for console output enabled. True by default.
|
||||
void setColorConsole(bool yes) { color_console = yes; }
|
||||
|
||||
|
||||
//! \~english Returns directory for log files.
|
||||
PIString dir() const { return log_dir; }
|
||||
|
||||
//! \~english Set directory for log files. Should be set \b after \a setApplicationName()!
|
||||
void setDir(const PIString & d);
|
||||
|
||||
|
||||
//! \~english Returns lifetime for file.
|
||||
PISystemTime fileSplitTime() const { return split_time; }
|
||||
|
||||
//! \~english Set lifetime for file. Each "st" interval new file will be created.
|
||||
void setFileSplitTime(PISystemTime st) { split_time = st; }
|
||||
|
||||
|
||||
//! \~english Returns timestamp format for line.
|
||||
PIString timestampFormat() const { return timestamp_format; }
|
||||
|
||||
//! \~english Set timestamp format for line. Default is "yyyy-MM-dd hh:mm:ss.zzz".
|
||||
void setTimestampFormat(const PIString & f) { timestamp_format = f; }
|
||||
|
||||
|
||||
//! \~english Returns line format.
|
||||
PIString lineFormat() const { return line_format; }
|
||||
|
||||
//! \~english Set line format. "t" is timestamp, "c" is category and "m" is message. Default is "t - c: m".
|
||||
void setLineFormat(const PIString & f);
|
||||
|
||||
|
||||
//! \~english Returns maximum level.
|
||||
Level level() const { return max_level; }
|
||||
|
||||
//! \~english Set maximum level. All levels greater than \"l\" will be ignored. Default if \a Level::Debug.
|
||||
void setLevel(Level l);
|
||||
|
||||
//! \~english Returns PICout for Level::Error level.
|
||||
PICout error(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Returns PICout for Level::Warning level.
|
||||
PICout warning(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Returns PICout for Level::Info level.
|
||||
PICout info(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Returns PICout for Level::Debug level.
|
||||
PICout debug(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Write all queued lines and stop. Also called in destructor.
|
||||
void stop();
|
||||
|
||||
private:
|
||||
EVENT_HANDLER2(void, coutDone, int, id, PIString *, buff);
|
||||
|
||||
PICout makePICout(PIObject * context, Level cat);
|
||||
void enqueue(const PIString & msg, Level cat = Level::Debug);
|
||||
|
||||
struct Entry {
|
||||
Level cat;
|
||||
PIDateTime time;
|
||||
PIString msg;
|
||||
};
|
||||
|
||||
PIString entryToString(const Entry & e) const;
|
||||
void newFile();
|
||||
void run() override;
|
||||
|
||||
PIMutex log_mutex;
|
||||
PIFile log_file;
|
||||
PIIOTextStream log_ts;
|
||||
PITimeMeasurer split_tm;
|
||||
PISystemTime split_time;
|
||||
PIString log_dir, timestamp_format, line_format, line_format_p, log_name;
|
||||
PIQueue<Entry> queue;
|
||||
PIMap<Level, int> id_by_cat;
|
||||
Level max_level = Level::Debug;
|
||||
PIFlags<Output> output = All;
|
||||
bool color_console = true;
|
||||
int part_number = -1, cout_id = -1;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -136,7 +136,7 @@ void PISingleApplication::run() {
|
||||
shm->read(readed.data(), readed.size(), hdr_sz);
|
||||
PIByteArray msg;
|
||||
readed >> msg;
|
||||
if (!msg.isEmpty()) {
|
||||
if (msg.isNotEmpty()) {
|
||||
messageReceived(msg);
|
||||
// piCoutObj << "message" << msg;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*! \file pisingleapplication.h
|
||||
* \ingroup System
|
||||
* \ingroup Application
|
||||
* \~\brief
|
||||
* \~english Single-instance application control
|
||||
* \~russian Контроль одного экземпляра приложения
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
class PISharedMemory;
|
||||
|
||||
//! \ingroup System
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Single-instance application control.
|
||||
//! \~russian Контроль одного экземпляра приложения.
|
||||
@@ -19,9 +19,10 @@
|
||||
|
||||
#include "pisystemmonitor.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pidir.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "piliterals.h"
|
||||
#include "piliterals_string.h"
|
||||
#include "piprocess.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "pitime_win.h"
|
||||
@@ -150,7 +151,7 @@ void PISystemMonitor::setStatistic(const PISystemMonitor::ProcessStats & s) {
|
||||
|
||||
|
||||
void PISystemMonitor::stop() {
|
||||
PIThread::stop();
|
||||
PIThread::stopAndWait();
|
||||
#ifdef WINDOWS
|
||||
if (PRIVATE->hProc != 0) {
|
||||
CloseHandle(PRIVATE->hProc);
|
||||
@@ -1,5 +1,5 @@
|
||||
/*! \file pisystemmonitor.h
|
||||
* \ingroup System
|
||||
* \ingroup Application
|
||||
* \~\brief
|
||||
* \~english System resources monitoring
|
||||
* \~russian Мониторинг ресурсов системы
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "pithread.h"
|
||||
|
||||
|
||||
//! \ingroup System
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Process monitoring.
|
||||
//! \~russian Мониторинг процесса.
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
~PISystemMonitor();
|
||||
|
||||
#pragma pack(push, 1)
|
||||
//! \ingroup System
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Process statistics (fixed-size fields).
|
||||
//! \~russian Статистика процесса (фиксированные поля).
|
||||
@@ -116,7 +116,7 @@ public:
|
||||
float cpu_load_user = 0.f;
|
||||
};
|
||||
|
||||
//! \ingroup System
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Thread statistics (fixed-size fields).
|
||||
//! \~russian Статистика потока (фиксированные поля).
|
||||
@@ -151,7 +151,7 @@ public:
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
//! \ingroup System
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Process statistics.
|
||||
//! \~russian Статистика процесса.
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
PIString data_memsize_readable;
|
||||
};
|
||||
|
||||
//! \ingroup System
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Thread statistics.
|
||||
//! \~russian Статистика потока.
|
||||
69
libs/main/client_server/piclientserver_client.h
Normal file
69
libs/main/client_server/piclientserver_client.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*! \file piclientserver_client.h
|
||||
* \ingroup ClientServer
|
||||
* \~\brief
|
||||
* \~english
|
||||
* \~russian
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef piclientserver_client_H
|
||||
#define piclientserver_client_H
|
||||
|
||||
#include "piclientserver_client_base.h"
|
||||
|
||||
|
||||
namespace PIClientServer {
|
||||
|
||||
|
||||
// ServerClient
|
||||
|
||||
class PIP_CLIENT_SERVER_EXPORT ServerClient: public ClientBase {
|
||||
friend class Server;
|
||||
NO_COPY_CLASS(ServerClient);
|
||||
|
||||
public:
|
||||
ServerClient() {}
|
||||
|
||||
protected:
|
||||
virtual void aboutDelete() {}
|
||||
|
||||
private:
|
||||
void createForServer(Server * parent, PIEthernet * tcp_);
|
||||
};
|
||||
|
||||
|
||||
// Client
|
||||
|
||||
class PIP_CLIENT_SERVER_EXPORT Client: public ClientBase {
|
||||
NO_COPY_CLASS(Client);
|
||||
|
||||
public:
|
||||
Client();
|
||||
~Client();
|
||||
|
||||
void connect(PINetworkAddress addr);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace PIClientServer
|
||||
|
||||
#endif
|
||||
78
libs/main/client_server/piclientserver_client_base.h
Normal file
78
libs/main/client_server/piclientserver_client_base.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*! \file piclientserver_client_base.h
|
||||
* \ingroup ClientServer
|
||||
* \~\brief
|
||||
* \~english
|
||||
* \~russian
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef piclientserver_client_base_H
|
||||
#define piclientserver_client_base_H
|
||||
|
||||
#include "piclientserver_config.h"
|
||||
#include "pip_client_server_export.h"
|
||||
#include "pistreampacker.h"
|
||||
|
||||
class PIEthernet;
|
||||
|
||||
namespace PIClientServer {
|
||||
|
||||
class Server;
|
||||
|
||||
class PIP_CLIENT_SERVER_EXPORT ClientBase {
|
||||
friend class Config;
|
||||
friend class Server;
|
||||
NO_COPY_CLASS(ClientBase);
|
||||
|
||||
public:
|
||||
ClientBase();
|
||||
virtual ~ClientBase();
|
||||
|
||||
const PIEthernet * getTCP() const { return tcp; }
|
||||
|
||||
void close();
|
||||
void stopAndWait();
|
||||
|
||||
int write(const void * d, const size_t s);
|
||||
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
|
||||
|
||||
Config & configuration() { return config; }
|
||||
|
||||
protected:
|
||||
virtual void readed(PIByteArray data) {}
|
||||
virtual void connected() {}
|
||||
virtual void disconnected() {}
|
||||
|
||||
void init();
|
||||
|
||||
bool own_tcp = false;
|
||||
std::atomic_bool can_write = {true};
|
||||
PIEthernet * tcp = nullptr;
|
||||
Config config;
|
||||
|
||||
private:
|
||||
void destroy();
|
||||
|
||||
PIStreamPacker stream;
|
||||
mutable PIMutex write_mutex;
|
||||
};
|
||||
|
||||
} // namespace PIClientServer
|
||||
|
||||
#endif
|
||||
60
libs/main/client_server/piclientserver_config.h
Normal file
60
libs/main/client_server/piclientserver_config.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*! \file piclientserver_config.h
|
||||
* \ingroup ClientServer
|
||||
* \~\brief
|
||||
* \~english
|
||||
* \~russian
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef piclientserver_config_H
|
||||
#define piclientserver_config_H
|
||||
|
||||
#include "pibytearray.h"
|
||||
#include "pip_client_server_export.h"
|
||||
|
||||
|
||||
namespace PIClientServer {
|
||||
|
||||
class Server;
|
||||
class Client;
|
||||
class ClientBase;
|
||||
|
||||
class PIP_CLIENT_SERVER_EXPORT Config {
|
||||
friend class Server;
|
||||
friend class Client;
|
||||
|
||||
public:
|
||||
void setPacketSign(ushort sign);
|
||||
void setPacketSize(int bytes);
|
||||
|
||||
void enableSymmetricEncryption(const PIByteArray & key);
|
||||
|
||||
protected:
|
||||
void apply(ClientBase * client);
|
||||
|
||||
PIByteArray crypt_key;
|
||||
ushort packet_sign = 0xAFBE;
|
||||
int packet_size = 1400;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace PIClientServer
|
||||
|
||||
#endif
|
||||
82
libs/main/client_server/piclientserver_server.h
Normal file
82
libs/main/client_server/piclientserver_server.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*! \file piclientserver_server.h
|
||||
* \ingroup ClientServer
|
||||
* \~\brief
|
||||
* \~english
|
||||
* \~russian
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef piclientserver_server_H
|
||||
#define piclientserver_server_H
|
||||
|
||||
#include "piclientserver_config.h"
|
||||
#include "pimutex.h"
|
||||
#include "pinetworkaddress.h"
|
||||
#include "pip_client_server_export.h"
|
||||
#include "pithreadnotifier.h"
|
||||
|
||||
class PIEthernet;
|
||||
class PIThread;
|
||||
|
||||
namespace PIClientServer {
|
||||
|
||||
class ServerClient;
|
||||
|
||||
class PIP_CLIENT_SERVER_EXPORT Server {
|
||||
friend class ServerClient;
|
||||
NO_COPY_CLASS(Server);
|
||||
|
||||
public:
|
||||
Server();
|
||||
virtual ~Server();
|
||||
|
||||
void listen(PINetworkAddress addr);
|
||||
void listenAll(ushort port) { listen({0, port}); }
|
||||
|
||||
void closeAll();
|
||||
|
||||
int getMaxClients() const { return max_clients; }
|
||||
void setMaxClients(int new_max_clients);
|
||||
int clientsCount() const;
|
||||
void forEachClient(std::function<void(ServerClient *)> func);
|
||||
|
||||
void setClientFactory(std::function<ServerClient *()> f) { client_factory = f; }
|
||||
|
||||
Config & configuration() { return config; }
|
||||
|
||||
private:
|
||||
void stopServer();
|
||||
void newClient(ServerClient * c);
|
||||
void clientDisconnected(ServerClient * c);
|
||||
|
||||
std::function<ServerClient *()> client_factory;
|
||||
std::atomic_bool is_closing = {false};
|
||||
PIEthernet * tcp_server = nullptr;
|
||||
PIThread * clean_thread = nullptr;
|
||||
PIThreadNotifier clean_notifier;
|
||||
Config config;
|
||||
PIVector<ServerClient *> clients;
|
||||
mutable PIMutex clients_mutex;
|
||||
|
||||
int max_clients = 1000;
|
||||
};
|
||||
|
||||
} // namespace PIClientServer
|
||||
|
||||
#endif
|
||||
@@ -220,7 +220,6 @@ void PIKbdListener::readKeyboard() {
|
||||
#ifdef WINDOWS
|
||||
INPUT_RECORD ir;
|
||||
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
|
||||
// piCout << ir.EventType;
|
||||
switch (ir.EventType) {
|
||||
case KEY_EVENT: {
|
||||
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
|
||||
@@ -542,6 +541,11 @@ void PIKbdListener::readKeyboard() {
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::stop() {
|
||||
PIThread::stop();
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::end() {
|
||||
// cout << "list end" << endl;
|
||||
#ifdef WINDOWS
|
||||
|
||||
@@ -29,9 +29,10 @@
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
|
||||
#define WAIT_FOR_EXIT \
|
||||
while (!PIKbdListener::exiting) \
|
||||
piMSleep(PIP_MIN_MSLEEP * 5); // TODO: rewrite with condvar
|
||||
#define WAIT_FOR_EXIT \
|
||||
while (!PIKbdListener::exiting) \
|
||||
piMSleep(PIP_MIN_MSLEEP * 5); \
|
||||
if (PIKbdListener::instance()) PIKbdListener::instance()->stopAndWait();
|
||||
|
||||
|
||||
class PIP_EXPORT PIKbdListener: public PIThread {
|
||||
@@ -179,6 +180,8 @@ public:
|
||||
|
||||
void readKeyboard();
|
||||
|
||||
void stop();
|
||||
|
||||
//! Returns if keyboard listening is active (not running!)
|
||||
bool isActive() { return is_active; }
|
||||
|
||||
|
||||
@@ -1383,7 +1383,7 @@ public:
|
||||
if (v.isEmpty()) return *this;
|
||||
#ifndef NDEBUG
|
||||
if (&v == this) {
|
||||
printf("error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&v != this);
|
||||
@@ -1738,7 +1738,7 @@ public:
|
||||
if (v.isEmpty()) return *this;
|
||||
#ifndef NDEBUG
|
||||
if (&v == this) {
|
||||
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&v != this);
|
||||
@@ -2400,7 +2400,7 @@ public:
|
||||
if (isEmpty()) return ret;
|
||||
#ifndef NDEBUG
|
||||
if (rows * cols != pid_size) {
|
||||
printf("error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(rows * cols == pid_size);
|
||||
@@ -2689,7 +2689,7 @@ private:
|
||||
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(pid_data), as * sizeof(T)));
|
||||
#ifndef NDEBUG
|
||||
if (!p_d) {
|
||||
printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(p_d);
|
||||
|
||||
@@ -355,7 +355,7 @@ public:
|
||||
inline PIMap<Key, T> & operator<<(const PIMap<Key, T> & other) {
|
||||
#ifndef NDEBUG
|
||||
if (&other == this) {
|
||||
printf("error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&other != this);
|
||||
|
||||
@@ -1341,7 +1341,7 @@ public:
|
||||
if (v.isEmpty()) return *this;
|
||||
#ifndef NDEBUG
|
||||
if (&v == this) {
|
||||
printf("error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&v != this);
|
||||
@@ -1663,7 +1663,7 @@ public:
|
||||
if (v.isEmpty()) return *this;
|
||||
#ifndef NDEBUG
|
||||
if (&v == this) {
|
||||
printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&v != this);
|
||||
@@ -2296,7 +2296,7 @@ public:
|
||||
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
|
||||
#ifndef NDEBUG
|
||||
if (rows * cols != piv_size) {
|
||||
printf("error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(rows * cols == piv_size);
|
||||
@@ -2565,7 +2565,7 @@ private:
|
||||
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), as * sizeof(T)));
|
||||
#ifndef NDEBUG
|
||||
if (!p_d) {
|
||||
printf("error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(p_d);
|
||||
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
inline Row & operator=(const PIVector<T> & other) {
|
||||
const size_t sz = piMin<size_t>(sz, other.size());
|
||||
const size_t sz = piMin<size_t>(sz_, other.size());
|
||||
p_->_copyRaw(p_->data(st_), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -677,15 +677,28 @@ public:
|
||||
//! \~\brief
|
||||
//! \~english Destructor that executes the function if it exists
|
||||
//! \~russian Деструктор, который выполняет функцию, если она существует
|
||||
~PIScopeExitCall() {
|
||||
if (func) func();
|
||||
}
|
||||
~PIScopeExitCall() { call(); }
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Method for canceling the function
|
||||
//! \~russian Метод для отмены функции
|
||||
void cancel() { func = nullptr; }
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Method for call the function
|
||||
//! \~russian Метод для вызова функции
|
||||
void call() {
|
||||
if (func) func();
|
||||
}
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Method for call and canceling the function
|
||||
//! \~russian Метод для вызова и отмены функции
|
||||
void callAndCancel() {
|
||||
call();
|
||||
cancel();
|
||||
}
|
||||
|
||||
private:
|
||||
NO_COPY_CLASS(PIScopeExitCall)
|
||||
|
||||
|
||||
@@ -328,7 +328,7 @@ typedef long long ssize_t;
|
||||
__PrivateInitializer__(const __PrivateInitializer__ & o); \
|
||||
~__PrivateInitializer__(); \
|
||||
__PrivateInitializer__ & operator=(const __PrivateInitializer__ & o); \
|
||||
__Private__ * p; \
|
||||
__Private__ * p = nullptr; \
|
||||
}; \
|
||||
__PrivateInitializer__ __privateinitializer__;
|
||||
|
||||
@@ -343,11 +343,10 @@ typedef long long ssize_t;
|
||||
p = new c::__Private__(); \
|
||||
} \
|
||||
c::__PrivateInitializer__::~__PrivateInitializer__() { \
|
||||
delete p; \
|
||||
p = 0; \
|
||||
piDeleteSafety(p); \
|
||||
} \
|
||||
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator=(const c::__PrivateInitializer__ &) { \
|
||||
if (p) delete p; \
|
||||
piDeleteSafety(p); \
|
||||
p = new c::__Private__(); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
#define PICOREMODULE_H
|
||||
|
||||
#include "pichunkstream.h"
|
||||
#include "picli.h"
|
||||
#include "picollection.h"
|
||||
#include "pijson.h"
|
||||
#include "piobject.h"
|
||||
|
||||
@@ -141,7 +141,7 @@ PIString & PICout::__string__() {
|
||||
return *ret;
|
||||
}
|
||||
|
||||
PICout::OutputDevices PICout::devs = PICout::StdOut;
|
||||
PICout::OutputDevices PICout::devs = PICout::Console;
|
||||
|
||||
PRIVATE_DEFINITION_START(PICout)
|
||||
PIStack<PICoutControls> cos_;
|
||||
@@ -158,35 +158,53 @@ WORD PICout::__Private__::dattr = 0;
|
||||
DWORD PICout::__Private__::smode = 0;
|
||||
#endif
|
||||
|
||||
PICout::PICout(int controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) {
|
||||
buffer_ = nullptr;
|
||||
|
||||
std::ostream & getStdStream(PICoutManipulators::PICoutStdStream s) {
|
||||
switch (s) {
|
||||
case PICoutManipulators::StdOut: return std::cout;
|
||||
case PICoutManipulators::StdErr: return std::cerr;
|
||||
default: break;
|
||||
}
|
||||
return std::cout;
|
||||
}
|
||||
|
||||
std::wostream & getStdWStream(PICoutManipulators::PICoutStdStream s) {
|
||||
switch (s) {
|
||||
case PICoutManipulators::StdOut: return std::wcout;
|
||||
case PICoutManipulators::StdErr: return std::wcerr;
|
||||
default: break;
|
||||
}
|
||||
return std::wcout;
|
||||
}
|
||||
|
||||
|
||||
PICout::PICout(int controls, PICoutStdStream stream): ctrl_(controls), stream_(stream) {
|
||||
init();
|
||||
}
|
||||
|
||||
PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) {
|
||||
buffer_ = nullptr;
|
||||
if (act_) init();
|
||||
PICout::PICout(bool active, PICoutStdStream stream): actve_(active), stream_(stream) {
|
||||
if (actve_) init();
|
||||
}
|
||||
|
||||
|
||||
PICout::PICout(const PICout & other)
|
||||
: fo_(other.fo_)
|
||||
, cc_(true)
|
||||
, fc_(false)
|
||||
, act_(other.act_)
|
||||
, cnb_(other.cnb_)
|
||||
, attr_(other.attr_)
|
||||
: first_out_(other.first_out_)
|
||||
, is_copy_(true)
|
||||
, actve_(other.actve_)
|
||||
, int_base_(other.int_base_)
|
||||
, win_attr_(other.win_attr_)
|
||||
, id_(other.id_)
|
||||
, buffer_(other.buffer_)
|
||||
, co_(other.co_) {}
|
||||
, ctrl_(other.ctrl_)
|
||||
, stream_(other.stream_) {}
|
||||
|
||||
|
||||
PICout::~PICout() {
|
||||
if (!act_) return;
|
||||
if (fc_) applyFormat(PICoutManipulators::Default);
|
||||
if (cc_) return;
|
||||
if (!actve_) return;
|
||||
if (format_changed_) applyFormat(PICoutManipulators::Default);
|
||||
if (is_copy_) return;
|
||||
newLine();
|
||||
if ((co_ & NoLock) != NoLock) {
|
||||
if ((ctrl_ & NoLock) != NoLock) {
|
||||
PICout::__mutex__().unlock();
|
||||
}
|
||||
if (buffer_) {
|
||||
@@ -196,7 +214,7 @@ PICout::~PICout() {
|
||||
|
||||
|
||||
PICout & PICout::operator<<(PICoutAction v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
#ifdef WINDOWS
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
COORD coord;
|
||||
@@ -204,12 +222,12 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
#endif
|
||||
switch (v) {
|
||||
case PICoutManipulators::Flush:
|
||||
if (!buffer_ && isOutputDeviceActive(StdOut)) {
|
||||
std::cout << std::flush;
|
||||
if (!buffer_ && isOutputDeviceActive(Console)) {
|
||||
getStdStream(stream_) << std::flush;
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::Backspace:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
coord = sbi.dwCursorPosition;
|
||||
@@ -223,7 +241,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ShowCursor:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||
curinfo.bVisible = true;
|
||||
@@ -234,7 +252,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::HideCursor:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||
curinfo.bVisible = false;
|
||||
@@ -245,7 +263,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ClearLine:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
coord = sbi.dwCursorPosition;
|
||||
@@ -266,7 +284,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ClearScreen:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
/// TODO : wondows ClearScreen !!!
|
||||
#else
|
||||
@@ -282,12 +300,31 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::setControl(PICoutManipulators::PICoutControl c, bool on) {
|
||||
ctrl_.setFlag(c, on);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::setControls(PICoutManipulators::PICoutControls c) {
|
||||
ctrl_ = c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::saveAndSetControls(PICoutManipulators::PICoutControls c) {
|
||||
saveControls();
|
||||
ctrl_ = c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::operator<<(PICoutManipulators::PICoutFormat v) {
|
||||
switch (v) {
|
||||
case PICoutManipulators::Bin: cnb_ = 2; break;
|
||||
case PICoutManipulators::Oct: cnb_ = 8; break;
|
||||
case PICoutManipulators::Dec: cnb_ = 10; break;
|
||||
case PICoutManipulators::Hex: cnb_ = 16; break;
|
||||
case PICoutManipulators::Bin: int_base_ = 2; break;
|
||||
case PICoutManipulators::Oct: int_base_ = 8; break;
|
||||
case PICoutManipulators::Dec: int_base_ = 10; break;
|
||||
case PICoutManipulators::Hex: int_base_ = 16; break;
|
||||
default: applyFormat(v);
|
||||
};
|
||||
return *this;
|
||||
@@ -295,10 +332,10 @@ PICout & PICout::operator<<(PICoutManipulators::PICoutFormat v) {
|
||||
|
||||
|
||||
PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) {
|
||||
if (v[PICoutManipulators::Bin]) cnb_ = 2;
|
||||
if (v[PICoutManipulators::Oct]) cnb_ = 8;
|
||||
if (v[PICoutManipulators::Dec]) cnb_ = 10;
|
||||
if (v[PICoutManipulators::Hex]) cnb_ = 16;
|
||||
if (v[PICoutManipulators::Bin]) int_base_ = 2;
|
||||
if (v[PICoutManipulators::Oct]) int_base_ = 8;
|
||||
if (v[PICoutManipulators::Dec]) int_base_ = 10;
|
||||
if (v[PICoutManipulators::Hex]) int_base_ = 16;
|
||||
if (v[PICoutManipulators::Bold]) applyFormat(PICoutManipulators::Bold);
|
||||
if (v[PICoutManipulators::Faint]) applyFormat(PICoutManipulators::Faint);
|
||||
if (v[PICoutManipulators::Italic]) applyFormat(PICoutManipulators::Italic);
|
||||
@@ -324,31 +361,78 @@ PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define PIINTCOUT(v) \
|
||||
{ \
|
||||
if (!act_) return *this; \
|
||||
space(); \
|
||||
if (cnb_ == 10) { \
|
||||
if (buffer_) { \
|
||||
(*buffer_) += PIString::fromNumber(v); \
|
||||
} else { \
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v); \
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v); \
|
||||
} \
|
||||
} else \
|
||||
write(PIString::fromNumber(v, cnb_)); \
|
||||
return *this; \
|
||||
|
||||
void PICout::stdoutPIString(const PIString & str, PICoutStdStream s) {
|
||||
#ifdef HAS_LOCALE
|
||||
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8conv;
|
||||
getStdStream(s) << utf8conv.to_bytes((char16_t *)&(const_cast<PIString &>(str).front()),
|
||||
(char16_t *)&(const_cast<PIString &>(str).front()) + str.size());
|
||||
#else
|
||||
for (PIChar c: str)
|
||||
getStdWStream(s).put(c.toWChar());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const char * str, int len) {
|
||||
if (!actve_ || !str) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(PIString(str, len));
|
||||
} else {
|
||||
if (isOutputDeviceActive(Console)) getStdStream(stream_).write(str, len);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__().append(PIString(str, len));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const PIString & s) {
|
||||
if (!actve_) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(s);
|
||||
} else {
|
||||
if (isOutputDeviceActive(Console)) stdoutPIString(s, stream_);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__().append(s);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void PICout::writeChar(char c) {
|
||||
if (buffer_) {
|
||||
buffer_->append(c);
|
||||
} else {
|
||||
if (isOutputDeviceActive(Console)) getStdStream(stream_) << c;
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__().append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define PIINTCOUT(v) \
|
||||
{ \
|
||||
if (!actve_) return *this; \
|
||||
space(); \
|
||||
if (int_base_ == 10) { \
|
||||
if (buffer_) { \
|
||||
(*buffer_) += PIString::fromNumber(v); \
|
||||
} else { \
|
||||
if (isOutputDeviceActive(Console)) getStdStream(stream_) << (v); \
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIString::fromNumber(v); \
|
||||
} \
|
||||
} else \
|
||||
write(PIString::fromNumber(v, int_base_)); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define PIFLOATCOUT(v) \
|
||||
{ \
|
||||
if (buffer_) { \
|
||||
(*buffer_) += PIString::fromNumber(v, 'g'); \
|
||||
} else { \
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v); \
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v, 'g'); \
|
||||
} \
|
||||
} \
|
||||
#define PIFLOATCOUT(v) \
|
||||
{ \
|
||||
if (buffer_) { \
|
||||
(*buffer_) += PIString::fromNumber(v, 'g'); \
|
||||
} else { \
|
||||
if (isOutputDeviceActive(Console)) getStdStream(stream_) << (v); \
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIString::fromNumber(v, 'g'); \
|
||||
} \
|
||||
} \
|
||||
return *this;
|
||||
|
||||
|
||||
@@ -361,7 +445,7 @@ PICout & PICout::operator<<(const PIString & v) {
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(const char * v) {
|
||||
if (!act_ || !v) return *this;
|
||||
if (!actve_ || !v) return *this;
|
||||
if (v[0] == '\0') return *this;
|
||||
space();
|
||||
quote();
|
||||
@@ -371,7 +455,7 @@ PICout & PICout::operator<<(const char * v) {
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(bool v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
if (v)
|
||||
write("true");
|
||||
@@ -381,7 +465,7 @@ PICout & PICout::operator<<(bool v) {
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(char v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
write(v);
|
||||
return *this;
|
||||
@@ -406,32 +490,32 @@ PICout & PICout::operator<<(llong v){PIINTCOUT(v)}
|
||||
PICout & PICout::operator<<(ullong v){PIINTCOUT(v)}
|
||||
|
||||
PICout & PICout::operator<<(float v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
PIFLOATCOUT(v)
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(double v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
PIFLOATCOUT(v)
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(ldouble v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
PIFLOATCOUT(v)
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(const void * v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
write("0x" + PIString::fromNumber(ullong(v), 16));
|
||||
return *this;
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(const PIObject * v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
if (v == 0)
|
||||
write("PIObject*(0x0)");
|
||||
@@ -443,74 +527,38 @@ PICout & PICout::operator<<(const PIObject * v) {
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(PICoutSpecialChar v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
switch (v) {
|
||||
case Null:
|
||||
if (buffer_) {
|
||||
(*buffer_) += PIChar();
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << char(0);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar();
|
||||
}
|
||||
break;
|
||||
case Null: writeChar(char(0)); break;
|
||||
case NewLine:
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\n";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\n';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n";
|
||||
}
|
||||
fo_ = true;
|
||||
break;
|
||||
case Tab:
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\t";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\t';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\t";
|
||||
}
|
||||
first_out_ = true;
|
||||
writeChar('\n');
|
||||
break;
|
||||
case Tab: writeChar('\t'); break;
|
||||
case Esc:
|
||||
#ifdef CC_VC
|
||||
if (buffer_) {
|
||||
(*buffer_) += PIChar(27);
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << char(27);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar(27);
|
||||
}
|
||||
writeChar(char(27));
|
||||
#else
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\e";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\e';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\e";
|
||||
}
|
||||
writeChar('\e');
|
||||
#endif
|
||||
break;
|
||||
case Quote:
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\"";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\"";
|
||||
}
|
||||
break;
|
||||
case Quote: writeChar('"'); break;
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::saveControls() {
|
||||
if (!act_) return *this;
|
||||
PRIVATE->cos_.push(co_);
|
||||
if (!actve_) return *this;
|
||||
PRIVATE->cos_.push(ctrl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::restoreControls() {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
if (!PRIVATE->cos_.isEmpty()) {
|
||||
co_ = PRIVATE->cos_.top();
|
||||
ctrl_ = PRIVATE->cos_.top();
|
||||
PRIVATE->cos_.pop();
|
||||
}
|
||||
return *this;
|
||||
@@ -524,16 +572,11 @@ PICout & PICout::restoreControls() {
|
||||
//! Добавляет пробел если это не первый вывод и установлен флаг \a AddSpaces
|
||||
//! \~\sa \a quote(), \a newLine()
|
||||
PICout & PICout::space() {
|
||||
if (!act_) return *this;
|
||||
if (!fo_ && co_[AddSpaces]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) += " ";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << ' ';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += " ";
|
||||
}
|
||||
if (!actve_) return *this;
|
||||
if (!first_out_ && ctrl_[AddSpaces]) {
|
||||
writeChar(' ');
|
||||
}
|
||||
fo_ = false;
|
||||
first_out_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -544,16 +587,11 @@ PICout & PICout::space() {
|
||||
//! Добавляет кавычки если установлен флаг \a AddQuotes
|
||||
//! \~\sa \a space(), \a newLine()
|
||||
PICout & PICout::quote() {
|
||||
if (!act_) return *this;
|
||||
if (co_[AddQuotes]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\"";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\"";
|
||||
}
|
||||
if (!actve_) return *this;
|
||||
if (ctrl_[AddQuotes]) {
|
||||
writeChar('"');
|
||||
}
|
||||
fo_ = false;
|
||||
first_out_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -564,74 +602,28 @@ PICout & PICout::quote() {
|
||||
//! Добавляет новую строку если установлен флаг \a AddNewLine
|
||||
//! \~\sa \a space(), \a quote()
|
||||
PICout & PICout::newLine() {
|
||||
if (!act_) return *this;
|
||||
if (co_[AddNewLine]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\n";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << std::endl;
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n";
|
||||
}
|
||||
if (!actve_) return *this;
|
||||
if (ctrl_[AddNewLine]) {
|
||||
writeChar('\n');
|
||||
}
|
||||
fo_ = false;
|
||||
first_out_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(char c) {
|
||||
if (!act_) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(c);
|
||||
} else {
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << c;
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(c);
|
||||
}
|
||||
if (!actve_) return *this;
|
||||
writeChar(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const char * str) {
|
||||
if (!act_ || !str) return *this;
|
||||
if (!actve_ || !str) return *this;
|
||||
return write(str, strlen(str));
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const char * str, int len) {
|
||||
if (!act_ || !str) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(PIString(str, len));
|
||||
} else {
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout.write(str, len);
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(PIString(str, len));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const PIString & s) {
|
||||
if (!act_) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(s);
|
||||
} else {
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) stdoutPIString(s);
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(s);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void PICout::stdoutPIString(const PIString & s) {
|
||||
#ifdef HAS_LOCALE
|
||||
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8conv;
|
||||
std::cout << utf8conv.to_bytes((char16_t *)&(const_cast<PIString &>(s).front()),
|
||||
(char16_t *)&(const_cast<PIString &>(s).front()) + s.size());
|
||||
#else
|
||||
for (PIChar c: s)
|
||||
std::wcout.put(c.toWChar());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PICout::init() {
|
||||
#ifdef WINDOWS
|
||||
if (__Private__::hOut == 0) {
|
||||
@@ -640,19 +632,18 @@ void PICout::init() {
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
__Private__::dattr = sbi.wAttributes;
|
||||
}
|
||||
attr_ = __Private__::dattr;
|
||||
win_attr_ = __Private__::dattr;
|
||||
#endif
|
||||
id_ = 0;
|
||||
if ((co_ & NoLock) != NoLock) {
|
||||
if ((ctrl_ & NoLock) != NoLock) {
|
||||
PICout::__mutex__().lock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PICout::applyFormat(PICoutFormat f) {
|
||||
if (!act_) return;
|
||||
if (buffer_ || !isOutputDeviceActive(StdOut)) return;
|
||||
fc_ = true;
|
||||
if (!actve_) return;
|
||||
if (buffer_ || !isOutputDeviceActive(Console)) return;
|
||||
format_changed_ = true;
|
||||
#ifdef WINDOWS
|
||||
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
@@ -661,28 +652,28 @@ void PICout::applyFormat(PICoutFormat f) {
|
||||
case Oct:
|
||||
case Dec:
|
||||
case Hex: break;
|
||||
case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break;
|
||||
case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break;
|
||||
case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break;
|
||||
case PICoutManipulators::Red: attr_ = (attr_ & mask_fore) | FOREGROUND_RED; break;
|
||||
case PICoutManipulators::Green: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Blue: attr_ = (attr_ & mask_fore) | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Yellow: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Magenta: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Cyan: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::White: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackBlack: attr_ = (attr_ & mask_back); break;
|
||||
case PICoutManipulators::BackRed: attr_ = (attr_ & mask_back) | BACKGROUND_RED; break;
|
||||
case PICoutManipulators::BackGreen: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackBlue: attr_ = (attr_ & mask_back) | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackYellow: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackMagenta: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackCyan: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackWhite: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::Default: attr_ = __Private__::dattr; break;
|
||||
case PICoutManipulators::Bold: win_attr_ |= FOREGROUND_INTENSITY; break;
|
||||
case PICoutManipulators::Underline: win_attr_ |= COMMON_LVB_UNDERSCORE; break;
|
||||
case PICoutManipulators::Black: win_attr_ = (win_attr_ & mask_fore); break;
|
||||
case PICoutManipulators::Red: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED; break;
|
||||
case PICoutManipulators::Green: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Blue: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Yellow: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Magenta: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Cyan: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::White: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackBlack: win_attr_ = (win_attr_ & mask_back); break;
|
||||
case PICoutManipulators::BackRed: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED; break;
|
||||
case PICoutManipulators::BackGreen: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackBlue: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackYellow: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackMagenta: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackCyan: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackWhite: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::Default: win_attr_ = __Private__::dattr; break;
|
||||
default: break;
|
||||
}
|
||||
SetConsoleTextAttribute(__Private__::hOut, attr_);
|
||||
SetConsoleTextAttribute(__Private__::hOut, win_attr_);
|
||||
#else
|
||||
switch (f) {
|
||||
case Bin:
|
||||
@@ -761,3 +752,8 @@ PICout PICout::withExternalBuffer(PIString * buffer, int id, PIFlags<PICoutManip
|
||||
c.id_ = id;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int PICout::registerExternalBufferID() {
|
||||
return Notifier::instance()->new_id.fetch_add(1);
|
||||
}
|
||||
|
||||
@@ -40,10 +40,14 @@
|
||||
# define piCoutObj
|
||||
|
||||
#else
|
||||
# define piCout PICout(piDebug)
|
||||
# define piCoutObj \
|
||||
PICout(piDebug && debug()) << (PIStringAscii("[") + className() + \
|
||||
(name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
||||
# define piCout PICout(piDebug, PICoutManipulators::StdOut)
|
||||
# define piCoutObj \
|
||||
PICout(piDebug && debug(), PICoutManipulators::StdOut) \
|
||||
<< (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
||||
# define piCerr PICout(piDebug, PICoutManipulators::StdErr)
|
||||
# define piCerrObj \
|
||||
PICout(piDebug && debug(), PICoutManipulators::StdErr) \
|
||||
<< (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
||||
#endif
|
||||
|
||||
|
||||
@@ -55,6 +59,7 @@ class PIObject;
|
||||
//! \~russian Пространство имен содержит перечисления для контроля PICout
|
||||
namespace PICoutManipulators {
|
||||
|
||||
|
||||
//! \~english Enum contains special characters
|
||||
//! \~russian Перечисление со спецсимволами
|
||||
enum PICoutSpecialChar {
|
||||
@@ -65,6 +70,7 @@ enum PICoutSpecialChar {
|
||||
Quote /*! \~english Quote character, '\"' \~russian Кавычки, '\"' */
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum contains immediate action
|
||||
//! \~russian Перечисление с немедленными действиями
|
||||
enum PICoutAction {
|
||||
@@ -79,6 +85,7 @@ enum PICoutAction {
|
||||
restoreControl() */
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum contains control of PICout
|
||||
//! \~russian Перечисление с управлением PICout
|
||||
enum PICoutControl {
|
||||
@@ -91,6 +98,7 @@ enum PICoutControl {
|
||||
NoLock /*! \~english Don`t use mutex for output \~russian Не использовать мьютекс при выводе */ = 0x100,
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum contains output format
|
||||
//! \~russian Перечисление с форматом вывода
|
||||
enum PICoutFormat {
|
||||
@@ -122,7 +130,17 @@ enum PICoutFormat {
|
||||
Default /*! \~english Default format \~russian Формат по умолчанию */ = 0x4000000
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum contains console streams
|
||||
//! \~russian Перечисление с потоками консоли
|
||||
enum PICoutStdStream {
|
||||
StdOut /*! \~english Standard output stream \~russian Стандартный поток вывода */ = 0,
|
||||
StdErr /*! \~english Standard error stream \~russian Стандартный поток ошибок */ = 1,
|
||||
};
|
||||
|
||||
|
||||
typedef PIFlags<PICoutControl> PICoutControls;
|
||||
|
||||
} // namespace PICoutManipulators
|
||||
|
||||
|
||||
@@ -134,11 +152,11 @@ class PIP_EXPORT PICout {
|
||||
public:
|
||||
//! \~english Default constructor with default features (AddSpaces and AddNewLine)
|
||||
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine)
|
||||
PICout(int controls = PICoutManipulators::DefaultControls);
|
||||
PICout(int controls = PICoutManipulators::DefaultControls, PICoutManipulators::PICoutStdStream stream = PICoutManipulators::StdOut);
|
||||
|
||||
//! \~english Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
|
||||
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным
|
||||
PICout(bool active);
|
||||
PICout(bool active, PICoutManipulators::PICoutStdStream stream = PICoutManipulators::StdOut);
|
||||
|
||||
PICout(const PICout & other);
|
||||
|
||||
@@ -146,6 +164,8 @@ public:
|
||||
|
||||
|
||||
class PIP_EXPORT Notifier {
|
||||
friend class PICout;
|
||||
|
||||
public:
|
||||
//! \~english Singleton access to %PICout::Notifier
|
||||
//! \~russian Синглтон класса %PICout::Notifier
|
||||
@@ -158,15 +178,17 @@ public:
|
||||
private:
|
||||
Notifier();
|
||||
PIObject * o;
|
||||
std::atomic_int new_id = {1};
|
||||
};
|
||||
|
||||
//! \~english Enum contains output devices of %PICout
|
||||
//! \~russian Перечисление с устройствами вывода для %PICout
|
||||
enum OutputDevice {
|
||||
NoDevices /** \~english %PICout is disabled \~russian %PICout неактивен */ = 0x0,
|
||||
StdOut /** \~english Standard console output \~russian Стандартный вывод в консоль */ = 0x1,
|
||||
Buffer /** \~english Internal buffer \~russian Внутренний буфер */ = 0x2,
|
||||
AllDevices /** \~english All \~russian Все */ = 0xFFFF,
|
||||
NoDevices /** \~english %PICout is disabled \~russian %PICout неактивен */ = 0x0,
|
||||
Console /** \~english Standard console output \~russian Стандартный вывод в консоль */ = 0x1,
|
||||
StdOut DEPRECATEDM("use PICout::Console") = Console,
|
||||
Buffer /** \~english Internal buffer \~russian Внутренний буфер */ = 0x2,
|
||||
AllDevices /** \~english All \~russian Все */ = 0xFFFF,
|
||||
};
|
||||
|
||||
typedef PIFlags<OutputDevice> OutputDevices;
|
||||
@@ -261,25 +283,15 @@ public:
|
||||
|
||||
//! \~english Set control flag "c" is "on" state
|
||||
//! \~russian Установить флаг "c" в "on" состояние
|
||||
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) {
|
||||
co_.setFlag(c, on);
|
||||
return *this;
|
||||
}
|
||||
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true);
|
||||
|
||||
//! \~english Set control flags "c"
|
||||
//! \~russian Установить флаги "c"
|
||||
PICout & setControls(PICoutManipulators::PICoutControls c) {
|
||||
co_ = c;
|
||||
return *this;
|
||||
}
|
||||
PICout & setControls(PICoutManipulators::PICoutControls c);
|
||||
|
||||
//! \~english Exec \a saveControls() and set control flags to "c"
|
||||
//! \~russian Иыполнить \a saveControls() и Установить флаги "c"
|
||||
PICout & saveAndSetControls(PICoutManipulators::PICoutControls c) {
|
||||
saveControls();
|
||||
co_ = c;
|
||||
return *this;
|
||||
}
|
||||
PICout & saveAndSetControls(PICoutManipulators::PICoutControls c);
|
||||
|
||||
//! \~english Save control flags to internal stack
|
||||
//! \~russian Сохраняет состояние флагов во внутренний стек
|
||||
@@ -321,7 +333,7 @@ public:
|
||||
|
||||
//! \~english Output \a PIString to stdout
|
||||
//! \~russian Вывод \a PIString в stdout
|
||||
static void stdoutPIString(const PIString & s);
|
||||
static void stdoutPIString(const PIString & str, PICoutManipulators::PICoutStdStream s = PICoutManipulators::StdOut);
|
||||
|
||||
//! \~english Returns internal PIString buffer
|
||||
//! \~russian Возвращает внутренний PIString буфер
|
||||
@@ -368,19 +380,25 @@ public:
|
||||
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces |
|
||||
PICoutManipulators::AddNewLine);
|
||||
|
||||
//! \~english Returns unique external buffer ID for later use in \a withExternalBuffer()
|
||||
//! \~russian Возвращает уникальный ID для внешнего буфера для дальнейшего использования в \a withExternalBuffer()
|
||||
static int registerExternalBufferID();
|
||||
|
||||
static PIMutex & __mutex__();
|
||||
static PIString & __string__();
|
||||
|
||||
private:
|
||||
void init();
|
||||
void applyFormat(PICoutManipulators::PICoutFormat f);
|
||||
void writeChar(char c);
|
||||
|
||||
static OutputDevices devs;
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
bool fo_, cc_, fc_, act_;
|
||||
int cnb_, attr_, id_;
|
||||
PIString * buffer_;
|
||||
PICoutManipulators::PICoutControls co_;
|
||||
bool first_out_ = true, is_copy_ = false, format_changed_ = false, actve_ = true;
|
||||
int int_base_ = 10, win_attr_ = 0, id_ = 0;
|
||||
PIString * buffer_ = nullptr;
|
||||
PICoutManipulators::PICoutControls ctrl_ = PICoutManipulators::DefaultControls;
|
||||
PICoutManipulators::PICoutStdStream stream_ = PICoutManipulators::StdOut;
|
||||
};
|
||||
|
||||
#endif // PICOUT_H
|
||||
|
||||
@@ -763,7 +763,7 @@ void dumpApplication(bool with_objects) {
|
||||
|
||||
bool dumpApplicationToFile(const PIString & path, bool with_objects) {
|
||||
PIFile f(path + "_tmp");
|
||||
f.setName("__S__DumpFile");
|
||||
f.setName("_S.DumpFile");
|
||||
f.clear();
|
||||
if (!f.open(PIIODevice::WriteOnly)) return false;
|
||||
auto out_devs = PICout::currentOutputDevices();
|
||||
|
||||
@@ -33,15 +33,11 @@ PRIVATE_DEFINITION_END(PIIntrospectionServer)
|
||||
|
||||
PIIntrospectionServer::PIIntrospectionServer(): PIPeer(genName()) {
|
||||
PRIVATE->process_info = PIIntrospection::getInfo();
|
||||
sysmon = 0;
|
||||
}
|
||||
|
||||
|
||||
PIIntrospectionServer::~PIIntrospectionServer() {
|
||||
PIPeer::stop();
|
||||
if (sysmon)
|
||||
if (sysmon->property("__iserver__").toBool()) delete sysmon;
|
||||
sysmon = 0;
|
||||
// stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +65,15 @@ void PIIntrospectionServer::start(const PIString & server_name) {
|
||||
}
|
||||
|
||||
|
||||
void PIIntrospectionServer::stop() {
|
||||
PIPeer::stopAndWait();
|
||||
PIPeer::destroy();
|
||||
if (sysmon)
|
||||
if (sysmon->property("__iserver__").toBool()) delete sysmon;
|
||||
sysmon = nullptr;
|
||||
}
|
||||
|
||||
|
||||
PIString PIIntrospectionServer::genName() {
|
||||
randomize();
|
||||
return "__introspection__server_" + PIString::fromNumber(randomi() % 1000);
|
||||
@@ -102,7 +107,7 @@ void PIIntrospectionServer::dataReceived(const PIString & from, const PIByteArra
|
||||
|
||||
void PIIntrospectionServer::sysmonDeleted() {
|
||||
PIMutexLocker _ml(sysmon_mutex);
|
||||
sysmon = 0;
|
||||
sysmon = nullptr;
|
||||
}
|
||||
|
||||
#endif // PIP_INTROSPECTION
|
||||
|
||||
@@ -33,6 +33,11 @@
|
||||
//! \~russian Запускает сервер интроспекции с именем "name"
|
||||
# define PIINTROSPECTION_START(name)
|
||||
|
||||
//! \ingroup Introspection
|
||||
//! \~english Stop introspection server
|
||||
//! \~russian Останавливает сервер интроспекции
|
||||
# define PIINTROSPECTION_STOP
|
||||
|
||||
#else
|
||||
|
||||
# if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
||||
@@ -44,6 +49,7 @@ class PISystemMonitor;
|
||||
|
||||
# define PIINTROSPECTION_SERVER (PIIntrospectionServer::instance())
|
||||
# define PIINTROSPECTION_START(name) PIINTROSPECTION_SERVER->start(#name);
|
||||
# define PIINTROSPECTION_STOP PIINTROSPECTION_SERVER->stop();
|
||||
|
||||
class PIP_EXPORT PIIntrospectionServer: public PIPeer {
|
||||
PIOBJECT_SUBCLASS(PIIntrospectionServer, PIPeer);
|
||||
@@ -52,6 +58,7 @@ public:
|
||||
static PIIntrospectionServer * instance();
|
||||
|
||||
void start(const PIString & server_name);
|
||||
void stop();
|
||||
|
||||
private:
|
||||
PIIntrospectionServer();
|
||||
@@ -59,17 +66,17 @@ private:
|
||||
NO_COPY_CLASS(PIIntrospectionServer);
|
||||
|
||||
PIString genName();
|
||||
virtual void dataReceived(const PIString & from, const PIByteArray & data);
|
||||
void dataReceived(const PIString & from, const PIByteArray & data) override;
|
||||
EVENT_HANDLER(void, sysmonDeleted);
|
||||
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
PITimer itimer;
|
||||
PISystemMonitor * sysmon;
|
||||
PISystemMonitor * sysmon = nullptr;
|
||||
PIMutex sysmon_mutex;
|
||||
};
|
||||
|
||||
# else
|
||||
# define PIINTROSPECTION_START(name)
|
||||
# define PIINTROSPECTION_STOP
|
||||
# endif
|
||||
|
||||
#endif // DOXYGEN
|
||||
|
||||
@@ -139,8 +139,10 @@ PIByteArray PIIntrospection::packThreads() {
|
||||
PIMap<PIThread *, PIIntrospectionThreads::ThreadInfo> & tm(p->threads);
|
||||
auto it = tm.makeIterator();
|
||||
while (it.next()) {
|
||||
it.value().classname = PIStringAscii(it.key()->className());
|
||||
it.value().name = it.key()->name();
|
||||
if (it.key()->isPIObject()) {
|
||||
it.value().classname = PIStringAscii(it.key()->className());
|
||||
it.value().name = it.key()->name();
|
||||
}
|
||||
}
|
||||
ret << tm.values();
|
||||
p->mutex.unlock();
|
||||
|
||||
@@ -79,7 +79,7 @@ PIBinaryLog::PIBinaryLog() {
|
||||
setLogDir(PIString());
|
||||
setFilePrefix(PIString());
|
||||
setRapidStart(false);
|
||||
file.setName("__S__PIBinaryLog::file");
|
||||
file.setName("_S.PIBinLog.file");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -459,7 +459,7 @@ PIDir PIDir::current() {
|
||||
|
||||
PIDir PIDir::home() {
|
||||
#ifndef ESP_PLATFORM
|
||||
char * rc = 0;
|
||||
char * rc = nullptr;
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
rc = new char[1024];
|
||||
@@ -482,7 +482,7 @@ PIDir PIDir::home() {
|
||||
#else
|
||||
# ifndef ESP_PLATFORM
|
||||
rc = getenv("HOME");
|
||||
if (rc == 0) return PIDir();
|
||||
if (!rc) return PIDir();
|
||||
return PIDir(rc);
|
||||
# else
|
||||
return PIDir();
|
||||
@@ -492,7 +492,7 @@ PIDir PIDir::home() {
|
||||
|
||||
|
||||
PIDir PIDir::temporary() {
|
||||
char * rc = 0;
|
||||
char * rc = nullptr;
|
||||
#ifdef WINDOWS
|
||||
rc = new char[1024];
|
||||
memset(rc, 0, 1024);
|
||||
@@ -507,8 +507,9 @@ PIDir PIDir::temporary() {
|
||||
s.prepend(separator);
|
||||
return PIDir(s);
|
||||
#else
|
||||
rc = tmpnam(0);
|
||||
if (rc == 0) return PIDir();
|
||||
char template_rc[] = "/tmp/pidir_tmp_XXXXXX";
|
||||
rc = mkdtemp(template_rc);
|
||||
if (!rc) return PIDir();
|
||||
PIString s(rc);
|
||||
return PIDir(s.left(s.findLast(PIDir::separator)));
|
||||
#endif
|
||||
|
||||
@@ -119,7 +119,8 @@ PRIVATE_DEFINITION_END(PIEthernet)
|
||||
|
||||
PIEthernet::PIEthernet(): PIIODevice("", ReadWrite) {
|
||||
construct();
|
||||
setType(UDP);
|
||||
eth_type = UDP;
|
||||
setProperty("type", (int)UDP);
|
||||
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop | PIEthernet::KeepConnection);
|
||||
}
|
||||
|
||||
@@ -128,7 +129,8 @@ PIEthernet::PIEthernet(PIEthernet::Type type_, const PIString & ip_port, const P
|
||||
: PIIODevice(ip_port, ReadWrite) {
|
||||
construct();
|
||||
addr_r.set(ip_port);
|
||||
setType(type_);
|
||||
eth_type = type_;
|
||||
setProperty("type", (int)type_);
|
||||
setParameters(params_);
|
||||
if (type_ != UDP) init();
|
||||
}
|
||||
@@ -139,9 +141,11 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) {
|
||||
addr_s.set(ip_port);
|
||||
sock = sock_;
|
||||
opened_ = connected_ = true;
|
||||
is_server_client = true;
|
||||
eth_type = TCP_Client;
|
||||
setProperty("type", (int)TCP_Client);
|
||||
init();
|
||||
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop);
|
||||
setType(TCP_Client, false);
|
||||
setPath(ip_port);
|
||||
ethNonblocking(sock);
|
||||
PRIVATE->event.create();
|
||||
@@ -161,14 +165,12 @@ PIEthernet::~PIEthernet() {
|
||||
void PIEthernet::construct() {
|
||||
// piCout << " PIEthernet" << uint(this);
|
||||
setOption(BlockingWrite);
|
||||
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
||||
sock = sock_s = -1;
|
||||
setReadTimeout(10_s);
|
||||
setWriteTimeout(10_s);
|
||||
setTTL(64);
|
||||
setMulticastTTL(1);
|
||||
server_thread_.setData(this);
|
||||
server_thread_.setName("__S__server_thread"_a);
|
||||
server_thread_.setName("_S.tcpserver"_a);
|
||||
#ifdef MICRO_PIP
|
||||
setThreadedReadBufferSize(512);
|
||||
#else
|
||||
@@ -178,9 +180,9 @@ void PIEthernet::construct() {
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::init() {
|
||||
if (isOpened()) return true;
|
||||
if (sock != -1) return true;
|
||||
void PIEthernet::init() {
|
||||
if (isOpened() || is_server_client) return;
|
||||
if (sock != -1) return;
|
||||
// piCout << "init " << type();
|
||||
PRIVATE->event.destroy();
|
||||
if (sock_s == sock) sock_s = -1;
|
||||
@@ -203,13 +205,13 @@ bool PIEthernet::init() {
|
||||
sock_s = sock;
|
||||
if (sock == -1 || sock_s == -1) {
|
||||
piCoutObj << "Can`t create socket," << ethErrorString();
|
||||
return false;
|
||||
connected_ = connecting_ = opened_ = false;
|
||||
return;
|
||||
}
|
||||
applyParameters();
|
||||
applyTimeouts();
|
||||
applyOptInt(IPPROTO_IP, IP_TTL, TTL());
|
||||
// piCoutObj << "inited" << path();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -303,18 +305,12 @@ bool PIEthernet::closeDevice() {
|
||||
// piCoutObj << "close";
|
||||
bool ned = connected_;
|
||||
connected_ = connecting_ = false;
|
||||
server_thread_.stop();
|
||||
PRIVATE->event.interrupt();
|
||||
if (server_thread_.isRunning()) {
|
||||
if (!server_thread_.waitForFinish(1_s)) server_thread_.terminate();
|
||||
}
|
||||
PRIVATE->event.destroy();
|
||||
if (sock_s == sock) sock_s = -1;
|
||||
closeSocket(sock);
|
||||
closeSocket(sock_s);
|
||||
stopThreadedListen();
|
||||
clients_mutex.lock();
|
||||
piDeleteAllAndClear(clients_);
|
||||
auto cl = clients_;
|
||||
clients_.clear();
|
||||
clients_mutex.unlock();
|
||||
piDeleteAll(cl);
|
||||
if (ned) {
|
||||
// piCoutObj << "Disconnect on close";
|
||||
disconnected(false);
|
||||
@@ -528,16 +524,32 @@ bool PIEthernet::listen(const PINetworkAddress & addr, bool threaded) {
|
||||
return listen(threaded);
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::stopThreadedListen() {
|
||||
server_thread_.stop();
|
||||
PRIVATE->event.interrupt();
|
||||
if (server_thread_.isRunning()) {
|
||||
if (!server_thread_.waitForFinish(1_s)) server_thread_.terminate();
|
||||
}
|
||||
PRIVATE->event.destroy();
|
||||
if (sock_s == sock) sock_s = -1;
|
||||
closeSocket(sock);
|
||||
closeSocket(sock_s);
|
||||
}
|
||||
|
||||
|
||||
PIEthernet * PIEthernet::client(int index) {
|
||||
PIMutexLocker locker(clients_mutex);
|
||||
return clients_[index];
|
||||
}
|
||||
|
||||
|
||||
int PIEthernet::clientsCount() const {
|
||||
PIMutexLocker locker(clients_mutex);
|
||||
return clients_.size_s();
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIEthernet *> PIEthernet::clients() const {
|
||||
PIMutexLocker locker(clients_mutex);
|
||||
return clients_;
|
||||
@@ -777,6 +789,9 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
||||
closeSocket(sock);
|
||||
init();
|
||||
disconnected(true);
|
||||
if (params[KeepConnection]) {
|
||||
connect();
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!isOptionSet(BlockingWrite)) {
|
||||
@@ -883,7 +898,7 @@ void PIEthernet::server_func(void * eth) {
|
||||
return;
|
||||
}
|
||||
if (ce->debug()) piCout << "[PIEthernet] Can`t accept new connection," << ethErrorString();
|
||||
piMSleep(10);
|
||||
piMSleep(50);
|
||||
return;
|
||||
}
|
||||
PIString ip = PIStringAscii(inet_ntoa(client_addr.sin_addr));
|
||||
|
||||
@@ -251,6 +251,8 @@ public:
|
||||
//! Start listen for incoming TCP connections on address "addr". Use only for TCP_Server
|
||||
bool listen(const PINetworkAddress & addr, bool threaded = false);
|
||||
|
||||
void stopThreadedListen();
|
||||
|
||||
PIEthernet * client(int index);
|
||||
int clientsCount() const;
|
||||
PIVector<PIEthernet *> clients() const;
|
||||
@@ -470,7 +472,7 @@ protected:
|
||||
virtual void received(const void * data, int size) { ; }
|
||||
|
||||
void construct();
|
||||
bool init();
|
||||
void init();
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
void closeSocket(int & sd);
|
||||
@@ -479,8 +481,9 @@ protected:
|
||||
void applyOptInt(int level, int opt, int val);
|
||||
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
int sock, sock_s;
|
||||
std::atomic_bool connected_, connecting_, listen_threaded, server_bounded;
|
||||
int sock = -1, sock_s = -1;
|
||||
std::atomic_bool connected_ = {false}, connecting_ = {false}, listen_threaded = {false}, server_bounded = {false};
|
||||
bool is_server_client = false;
|
||||
mutable PINetworkAddress addr_r, addr_s, addr_lr;
|
||||
Type eth_type;
|
||||
PIThread server_thread_;
|
||||
|
||||
@@ -337,8 +337,8 @@ void PIIODevice::_init() {
|
||||
#else
|
||||
threaded_read_buffer_size = 4_KiB;
|
||||
#endif
|
||||
read_thread.setName("__S__.PIIODevice.read_thread");
|
||||
write_thread.setName("__S__.PIIODevice.write_thread");
|
||||
read_thread.setName("_S.PIIODev.read");
|
||||
write_thread.setName("_S.PIIODev.write");
|
||||
CONNECT(void, &write_thread, started, this, write_func);
|
||||
CONNECTL(&read_thread, started, [this]() {
|
||||
if (!isOpened()) open();
|
||||
@@ -384,9 +384,10 @@ void PIIODevice::read_func() {
|
||||
ok = open();
|
||||
}
|
||||
}
|
||||
if (!ok) return;
|
||||
if (!ok || read_thread.isStopping()) return;
|
||||
}
|
||||
ssize_t readed_ = read(buffer_tr.data(), buffer_tr.size_s());
|
||||
if (read_thread.isStopping()) return;
|
||||
if (readed_ <= 0) {
|
||||
piMSleep(10);
|
||||
// cout << readed_ << ", " << errno << ", " << errorString() << endl;
|
||||
|
||||
@@ -243,6 +243,10 @@ public:
|
||||
//! \~russian Возвращает запущен ли поток чтения
|
||||
bool isThreadedRead() const;
|
||||
|
||||
//! \~english Returns if threaded read is stopping
|
||||
//! \~russian Возвращает останавливается ли поток чтения
|
||||
bool isThreadedReadStopping() const { return read_thread.isStopping(); }
|
||||
|
||||
//! \~english Start threaded read
|
||||
//! \~russian Запускает потоковое чтение
|
||||
void startThreadedRead();
|
||||
@@ -565,8 +569,6 @@ protected:
|
||||
|
||||
static PIIODevice * newDeviceByPrefix(const char * prefix);
|
||||
|
||||
bool isThreadedReadStopping() const { return read_thread.isStopping(); }
|
||||
|
||||
DeviceMode mode_ = ReadOnly;
|
||||
DeviceOptions options_;
|
||||
ReadRetFunc func_read = nullptr;
|
||||
|
||||
@@ -175,7 +175,7 @@ PIPeer::PIPeer(const PIString & n)
|
||||
, eth_tcp_cli(PIEthernet::TCP_Client)
|
||||
, diag_s(false)
|
||||
, diag_d(false) {
|
||||
sync_timer.setName("__S__.PIPeer.sync_timer");
|
||||
sync_timer.setName("_S.PIPeer.sync");
|
||||
// piCout << " PIPeer" << uint(this);
|
||||
destroyed = false;
|
||||
setDebug(false);
|
||||
@@ -201,33 +201,7 @@ PIPeer::~PIPeer() {
|
||||
stop();
|
||||
if (destroyed) return;
|
||||
destroyed = true;
|
||||
sync_timer.stopAndWait();
|
||||
diag_s.stopAndWait();
|
||||
diag_d.stopAndWait();
|
||||
PIMutexLocker ml(peers_mutex);
|
||||
piForeach(PeerInfo & p, peers)
|
||||
if (p._data) {
|
||||
p._data->dt_in.stop();
|
||||
p._data->dt_out.stop();
|
||||
p._data->t.stopAndWait();
|
||||
}
|
||||
destroyEths();
|
||||
piForeach(PIEthernet * i, eths_mcast) {
|
||||
if (!i) continue;
|
||||
i->stopAndWait();
|
||||
}
|
||||
piForeach(PIEthernet * i, eths_bcast) {
|
||||
if (!i) continue;
|
||||
i->stopAndWait();
|
||||
}
|
||||
eth_lo.stopAndWait();
|
||||
eth_tcp_srv.stopAndWait();
|
||||
eth_tcp_cli.stopAndWait();
|
||||
sendSelfRemove();
|
||||
destroyMBcasts();
|
||||
eth_send.close();
|
||||
piForeach(PeerInfo & p, peers)
|
||||
p.destroy();
|
||||
destroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -255,7 +229,7 @@ void PIPeer::initEths(PIStringList al) {
|
||||
piForeachC(PIString & a, al) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_traffic_eth_rec_" + a);
|
||||
ce->setName("_S.PIPeer.traf_rec_" + a);
|
||||
ce->setParameters(0);
|
||||
bool ok = false;
|
||||
for (int p = _PIPEER_TRAFFIC_PORT_S; p < _PIPEER_TRAFFIC_PORT_E; ++p) {
|
||||
@@ -275,7 +249,7 @@ void PIPeer::initEths(PIStringList al) {
|
||||
if (!ok) delete ce;
|
||||
}
|
||||
eth_send.setDebug(false);
|
||||
eth_send.setName("__S__PIPeer_traffic_eth_send");
|
||||
eth_send.setName("_S.PIPeer.traf_send");
|
||||
eth_send.setParameters(0);
|
||||
// piCoutObj << "initEths ok";
|
||||
}
|
||||
@@ -291,7 +265,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
// piCout << "mcast try" << a;
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_mcast_eth_" + a);
|
||||
ce->setName("_S.PIPeer.mcast_" + a);
|
||||
ce->setParameters(0);
|
||||
ce->setSendAddress(_PIPEER_MULTICAST_IP, _PIPEER_MULTICAST_PORT);
|
||||
ce->setReadAddress(a, _PIPEER_MULTICAST_PORT);
|
||||
@@ -311,7 +285,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
piForeachC(PIString & a, al) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_bcast_eth_" + a);
|
||||
ce->setName("_S.PIPeer.bcast_" + a);
|
||||
ce->setParameters(PIEthernet::Broadcast);
|
||||
cint = prev_ifaces.getByAddress(a);
|
||||
nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
|
||||
@@ -328,7 +302,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
// piCoutObj << "invalid address for bcast" << a;
|
||||
}
|
||||
}
|
||||
eth_lo.setName("__S__PIPeer_eth_loopback");
|
||||
eth_lo.setName("_S.PIPeer.lo");
|
||||
eth_lo.setParameters(PIEthernet::SeparateSockets);
|
||||
eth_lo.init();
|
||||
cint = prev_ifaces.getByAddress("127.0.0.1");
|
||||
@@ -343,13 +317,13 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
eth_tcp_srv.setName("__S__PIPeer_eth_TCP_Server");
|
||||
eth_tcp_srv.setName("_S.PIPeer.TCP_Server");
|
||||
eth_tcp_srv.init();
|
||||
eth_tcp_srv.listen("0.0.0.0", _PIPEER_TCP_PORT, true);
|
||||
eth_tcp_srv.setDebug(false);
|
||||
CONNECT1(void, PIEthernet *, ð_tcp_srv, newConnection, this, newTcpClient);
|
||||
eth_tcp_srv.startThreadedRead();
|
||||
eth_tcp_cli.setName("__S__PIPeer_eth_TCP_Client");
|
||||
eth_tcp_cli.setName("_S.PIPeer.TCP_Client");
|
||||
eth_tcp_cli.init();
|
||||
eth_tcp_cli.setDebug(false);
|
||||
tcpClientReconnect();
|
||||
@@ -363,6 +337,42 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::destroy() {
|
||||
sync_timer.stopAndWait();
|
||||
diag_s.stopAndWait();
|
||||
diag_d.stopAndWait();
|
||||
PIMutexLocker ml(peers_mutex);
|
||||
for (auto & p: peers)
|
||||
if (p._data) {
|
||||
p._data->dt_in.stop();
|
||||
p._data->dt_out.stop();
|
||||
p._data->t.stopAndWait();
|
||||
}
|
||||
destroyEths();
|
||||
for (auto * i: eths_mcast) {
|
||||
if (!i) continue;
|
||||
i->stopAndWait();
|
||||
}
|
||||
for (auto * i: eths_bcast) {
|
||||
if (!i) continue;
|
||||
i->stopAndWait();
|
||||
}
|
||||
eth_lo.stopAndWait();
|
||||
eth_tcp_srv.stopAndWait();
|
||||
eth_tcp_cli.stopAndWait();
|
||||
sendSelfRemove();
|
||||
eth_lo.close();
|
||||
eth_tcp_srv.close();
|
||||
eth_tcp_cli.close();
|
||||
destroyMBcasts();
|
||||
eth_send.close();
|
||||
for (auto & p: peers)
|
||||
p.destroy();
|
||||
peers.clear();
|
||||
destroyed = true;
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::destroyEths() {
|
||||
for (auto * i: eths_traffic) {
|
||||
if (!i) continue;
|
||||
@@ -930,6 +940,7 @@ ssize_t PIPeer::bytesAvailable() const {
|
||||
|
||||
|
||||
ssize_t PIPeer::readDevice(void * read_to, ssize_t max_size) {
|
||||
iterrupted = false;
|
||||
read_buffer_mutex.lock();
|
||||
bool empty = read_buffer.isEmpty();
|
||||
read_buffer_mutex.unlock();
|
||||
@@ -937,6 +948,9 @@ ssize_t PIPeer::readDevice(void * read_to, ssize_t max_size) {
|
||||
read_buffer_mutex.lock();
|
||||
empty = read_buffer.isEmpty();
|
||||
read_buffer_mutex.unlock();
|
||||
if (iterrupted) {
|
||||
return 0;
|
||||
}
|
||||
piMSleep(10);
|
||||
}
|
||||
read_buffer_mutex.lock();
|
||||
@@ -945,6 +959,9 @@ ssize_t PIPeer::readDevice(void * read_to, ssize_t max_size) {
|
||||
read_buffer_mutex.unlock();
|
||||
ssize_t sz = piMini(ba.size_s(), max_size);
|
||||
memcpy(read_to, ba.data(), sz);
|
||||
if (iterrupted) {
|
||||
return 0;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
read_buffer_mutex.unlock();
|
||||
@@ -964,8 +981,13 @@ ssize_t PIPeer::writeDevice(const void * data, ssize_t size) {
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::interrupt() {
|
||||
iterrupted = true;
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::newTcpClient(PIEthernet * client) {
|
||||
client->setName("__S__PIPeer_eth_TCP_ServerClient" + client->path());
|
||||
client->setName("_S.PIPeer.TCP_ServerClient" + client->path());
|
||||
piCoutObj << "client" << client->path();
|
||||
CONNECT2(void, const uchar *, ssize_t, client, threadedReadEvent, this, mbcastRead);
|
||||
client->startThreadedRead();
|
||||
|
||||
@@ -171,6 +171,8 @@ protected:
|
||||
EVENT_HANDLER2(bool, dataRead, const uchar *, readed, ssize_t, size);
|
||||
EVENT_HANDLER2(bool, mbcastRead, const uchar *, readed, ssize_t, size);
|
||||
|
||||
void destroy();
|
||||
|
||||
private:
|
||||
EVENT_HANDLER1(void, timerEvent, int, delim);
|
||||
EVENT_HANDLER2(bool, sendInternal, const PIString &, to, const PIByteArray &, data);
|
||||
@@ -212,6 +214,7 @@ private:
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||
void interrupt() override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
||||
|
||||
PeerInfo * quickestPeer(const PIString & to);
|
||||
@@ -243,6 +246,7 @@ private:
|
||||
mutable PIMutex read_buffer_mutex;
|
||||
PIQueue<PIByteArray> read_buffer;
|
||||
int read_buffer_size;
|
||||
std::atomic_bool iterrupted = {false};
|
||||
PIMutex mc_mutex, eth_mutex, peers_mutex, send_mutex, send_mc_mutex;
|
||||
};
|
||||
|
||||
|
||||
@@ -998,7 +998,7 @@ PIIODevice * PIConnection::DevicePool::addDevice(PIConnection * parent, const PI
|
||||
dd->started = false;
|
||||
}
|
||||
dd->rthread = new PIThread(dd, __DevicePool_threadReadDP);
|
||||
dd->rthread->setName("__S__connection_" + fp + "_read_thread");
|
||||
dd->rthread->setName("_S.Conn." + fp + ".read");
|
||||
need_start = true;
|
||||
pmode |= PIIODevice::ReadOnly;
|
||||
}
|
||||
@@ -1211,7 +1211,7 @@ PIConnection::Extractor::~Extractor() {
|
||||
|
||||
|
||||
PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_) {
|
||||
setName("__S__.PIConnection.Sender");
|
||||
setName("_S.PIConn.Sender");
|
||||
needLockRun(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#ifndef PIP_H
|
||||
#define PIP_H
|
||||
|
||||
#include "piapplicationmodule.h"
|
||||
#include "picloudmodule.h"
|
||||
#include "piconsolemodule.h"
|
||||
#include "picontainersmodule.h"
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
bool binaryStreamAppend(const void * d, size_t s) {
|
||||
if (!static_cast<P *>(this)->binaryStreamAppendImp(d, s)) {
|
||||
return false;
|
||||
printf("[PIBinaryStream] binaryStreamAppend() error\n");
|
||||
fprintf(stderr, "[PIBinaryStream] binaryStreamAppend() error\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
if (!static_cast<P *>(this)->binaryStreamTakeImp(d, s)) {
|
||||
_was_read_error_ = true;
|
||||
return false;
|
||||
printf("[PIBinaryStream] binaryStreamTake() error\n");
|
||||
fprintf(stderr, "[PIBinaryStream] binaryStreamTake() error\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -323,7 +323,7 @@ template<typename P,
|
||||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStreamTrivialRef<P> operator>>(PIBinaryStream<P> & s, T & v) {
|
||||
if (!s.binaryStreamTake(&v, sizeof(v))) {
|
||||
printf("error with %s\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with %s\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -341,13 +341,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
// piCout << ">> vector trivial default";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v._resizeRaw(sz);
|
||||
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
@@ -362,7 +362,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
// piCout << ">> vector trivial custom";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -370,7 +370,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
s >> v[i];
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -391,13 +391,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
// piCout << ">> deque trivial default";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v._resizeRaw(sz);
|
||||
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
@@ -412,7 +412,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
// piCout << ">> deque trivial custom";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -420,7 +420,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
s >> v[i];
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -443,13 +443,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
r = s.binaryStreamTakeInt();
|
||||
c = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v._resizeRaw(r, c);
|
||||
if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
@@ -468,7 +468,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
c = s.binaryStreamTakeInt();
|
||||
s >> tmp;
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -543,7 +543,7 @@ template<typename P, typename T, typename std::enable_if<!std::is_trivially_copy
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -551,7 +551,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s >> v[i];
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -566,7 +566,7 @@ template<typename P, typename T, typename std::enable_if<!std::is_trivially_copy
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -574,7 +574,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s >> v[i];
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -593,7 +593,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
c = s.binaryStreamTakeInt();
|
||||
s >> tmp;
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -625,7 +625,7 @@ template<typename P, typename Key, typename T>
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -635,7 +635,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v)
|
||||
ind = s.binaryStreamTakeInt();
|
||||
s >> v.pim_index[i].key;
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -643,7 +643,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v)
|
||||
}
|
||||
s >> v.pim_content;
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,33 @@ void PISignals::grabSignals(PIFlags<PISignals::Signal> signals_) {
|
||||
}
|
||||
|
||||
|
||||
void PISignals::releaseSignals(PIFlags<Signal> signals_) {
|
||||
if (signals_[PISignals::Interrupt]) signal(signalCode(PISignals::Interrupt), SIG_DFL);
|
||||
if (signals_[PISignals::Illegal]) signal(signalCode(PISignals::Illegal), SIG_DFL);
|
||||
if (signals_[PISignals::Abort]) signal(signalCode(PISignals::Abort), SIG_DFL);
|
||||
if (signals_[PISignals::FPE]) signal(signalCode(PISignals::FPE), SIG_DFL);
|
||||
if (signals_[PISignals::SegFault]) signal(signalCode(PISignals::SegFault), SIG_DFL);
|
||||
if (signals_[PISignals::Termination]) signal(signalCode(PISignals::Termination), SIG_DFL);
|
||||
#ifndef CC_VC
|
||||
if (signals_[PISignals::UserDefined1]) signal(signalCode(PISignals::UserDefined1), SIG_DFL);
|
||||
if (signals_[PISignals::UserDefined2]) signal(signalCode(PISignals::UserDefined2), SIG_DFL);
|
||||
#endif
|
||||
#ifndef WINDOWS
|
||||
if (signals_[PISignals::Hangup]) signal(signalCode(PISignals::Hangup), SIG_DFL);
|
||||
if (signals_[PISignals::Quit]) signal(signalCode(PISignals::Quit), SIG_DFL);
|
||||
if (signals_[PISignals::Kill]) signal(signalCode(PISignals::Kill), SIG_DFL);
|
||||
if (signals_[PISignals::BrokenPipe]) signal(signalCode(PISignals::BrokenPipe), SIG_DFL);
|
||||
if (signals_[PISignals::Timer]) signal(signalCode(PISignals::Timer), SIG_DFL);
|
||||
if (signals_[PISignals::ChildStopped]) signal(signalCode(PISignals::ChildStopped), SIG_DFL);
|
||||
if (signals_[PISignals::Continue]) signal(signalCode(PISignals::Continue), SIG_DFL);
|
||||
if (signals_[PISignals::StopProcess]) signal(signalCode(PISignals::StopProcess), SIG_DFL);
|
||||
if (signals_[PISignals::StopTTY]) signal(signalCode(PISignals::StopTTY), SIG_DFL);
|
||||
if (signals_[PISignals::StopTTYInput]) signal(signalCode(PISignals::StopTTYInput), SIG_DFL);
|
||||
if (signals_[PISignals::StopTTYOutput]) signal(signalCode(PISignals::StopTTYOutput), SIG_DFL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PISignals::raiseSignal(PISignals::Signal signal) {
|
||||
raise(signalCode(signal));
|
||||
}
|
||||
@@ -90,7 +117,7 @@ int PISignals::signalCode(PISignals::Signal signal) {
|
||||
case PISignals::StopTTYInput: return SIGTTIN;
|
||||
case PISignals::StopTTYOutput: return SIGTTOU;
|
||||
#endif
|
||||
default:;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -121,13 +148,13 @@ PISignals::Signal PISignals::signalFromCode(int signal) {
|
||||
case SIGTTIN: return PISignals::StopTTYInput;
|
||||
case SIGTTOU: return PISignals::StopTTYOutput;
|
||||
#endif
|
||||
default:;
|
||||
default: break;
|
||||
}
|
||||
return PISignals::Termination;
|
||||
}
|
||||
|
||||
|
||||
void PISignals::signal_event(int signal) {
|
||||
if (PISignals::ret_func == 0) return;
|
||||
if (!PISignals::ret_func) return;
|
||||
PISignals::ret_func(PISignals::signalFromCode(signal));
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
// slot is any function format "void(PISignals::Signal)"
|
||||
static void setSlot(SignalEvent slot) { ret_func = slot; }
|
||||
static void grabSignals(PIFlags<PISignals::Signal> signals_);
|
||||
static void releaseSignals(PIFlags<PISignals::Signal> signals_);
|
||||
static void raiseSignal(PISignals::Signal signal);
|
||||
|
||||
private:
|
||||
|
||||
@@ -54,10 +54,10 @@
|
||||
#define PISYSTEMMODULE_H
|
||||
|
||||
#include "pilibrary.h"
|
||||
#include "piplugin.h"
|
||||
#include "piprocess.h"
|
||||
#include "pisignals.h"
|
||||
#include "pisingleapplication.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "pisystemmonitor.h"
|
||||
#include "pisystemtests.h"
|
||||
|
||||
#endif // PISYSTEMMODULE_H
|
||||
|
||||
@@ -568,6 +568,7 @@ PIThread::PIThread(bool startNow, PISystemTime loop_delay): PIObject() {
|
||||
PIThread::~PIThread() {
|
||||
PIINTROSPECTION_THREAD_DELETE(this);
|
||||
if (!running_ || PRIVATE->thread == 0) return;
|
||||
piCout << "[PIThread \"" << name() << "\"] Warning, terminate on destructor!";
|
||||
#ifdef FREERTOS
|
||||
// void * ret(0);
|
||||
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
|
||||
@@ -587,6 +588,8 @@ PIThread::~PIThread() {
|
||||
CloseHandle(PRIVATE->thread);
|
||||
# endif
|
||||
#endif
|
||||
UNREGISTER_THREAD(this);
|
||||
PIINTROSPECTION_THREAD_STOP(this);
|
||||
terminating = running_ = false;
|
||||
}
|
||||
|
||||
@@ -916,6 +919,10 @@ void PIThread::_runThread() {
|
||||
|
||||
|
||||
void PIThread::_endThread() {
|
||||
PIScopeExitCall ec([this] {
|
||||
terminating = running_ = false;
|
||||
tid_ = -1;
|
||||
});
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
|
||||
stopped();
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
||||
@@ -924,14 +931,13 @@ void PIThread::_endThread() {
|
||||
end();
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
||||
if (lockRun) thread_mutex.unlock();
|
||||
terminating = running_ = false;
|
||||
tid_ = -1;
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
|
||||
// cout << "thread " << t << " exiting ... " << endl;
|
||||
// PICout(PICoutManipulators::DefaultControls) << "pthread_exit" << (__privateinitializer__.p)->thread;
|
||||
UNREGISTER_THREAD(this);
|
||||
PIINTROSPECTION_THREAD_STOP(this);
|
||||
#if defined(WINDOWS)
|
||||
ec.callAndCancel();
|
||||
# ifdef CC_GCC
|
||||
_endthreadex(0);
|
||||
# else
|
||||
@@ -940,7 +946,7 @@ void PIThread::_endThread() {
|
||||
#elif defined(FREERTOS)
|
||||
PRIVATE->thread = 0;
|
||||
#else
|
||||
pthread_detach(PRIVATE->thread);
|
||||
// pthread_detach(PRIVATE->thread);
|
||||
PRIVATE->thread = 0;
|
||||
pthread_exit(0);
|
||||
#endif
|
||||
|
||||
@@ -72,9 +72,9 @@
|
||||
//! w->startOnce();
|
||||
//!
|
||||
//! piMSleep(500);
|
||||
//! notifier.notifyOnce(); // notify one of them after 500 ms
|
||||
//! notifier.notify(); // notify one of them after 500 ms
|
||||
//! piMSleep(500);
|
||||
//! notifier.notifyOnce(); // notify one of them after 1000 ms
|
||||
//! notifier.notify(); // notify one of them after 1000 ms
|
||||
//!
|
||||
//! for (auto * w: workers)
|
||||
//! w->waitForFinish();
|
||||
@@ -93,17 +93,17 @@ PIThreadNotifier::PIThreadNotifier(): cnt(0) {}
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! If \a notifyOnce() has been called before, then returns immediately.\n
|
||||
//! If \a notifyOnce() has been called "n" times, then returns immediately "n" times,
|
||||
//! If \a notify() has been called before, then returns immediately.\n
|
||||
//! If \a notify() has been called "n" times, then returns immediately "n" times,
|
||||
//! but only if wait in one thread.\n
|
||||
//! If many threads waiting, then if \a notifyOnce() has been called "n" times,
|
||||
//! If many threads waiting, then if \a notify() has been called "n" times,
|
||||
//! all threads total returns "n" times in undefined sequence.
|
||||
//!
|
||||
//! \~russian
|
||||
//! Если ранее был вызван \a notifyOnce(), то возвращает управление немедленно.\n
|
||||
//! Если ранее был вызван \a notifyOnce() "n" раз, то возвращает управление немедленно "n" раз,
|
||||
//! Если ранее был вызван \a notify(), то возвращает управление немедленно.\n
|
||||
//! Если ранее был вызван \a notify() "n" раз, то возвращает управление немедленно "n" раз,
|
||||
//! но только если ожидать одним потоком.\n
|
||||
//! Если ожидают несколько потоков, и \a notifyOnce() был вызван "n" раз,
|
||||
//! Если ожидают несколько потоков, и \a notify() был вызван "n" раз,
|
||||
//! то все потоки суммарно вернут управление "n" раз в неопределенной последовательности.
|
||||
//!
|
||||
void PIThreadNotifier::wait() {
|
||||
|
||||
@@ -33,8 +33,8 @@ class PIP_EXPORT PIThreadNotifier {
|
||||
public:
|
||||
PIThreadNotifier();
|
||||
|
||||
//! \~english Start waiting, return if other thread call \a notifyOnce()
|
||||
//! \~russian Начать ожидание, продолжает когда другой поток вызовет \a notifyOnce()
|
||||
//! \~english Start waiting, return if other thread call \a notify()
|
||||
//! \~russian Начать ожидание, продолжает когда другой поток вызовет \a notify()
|
||||
void wait();
|
||||
|
||||
//! \~english Notify one waiting thread, which waiting on \a wait() function
|
||||
|
||||
@@ -171,7 +171,7 @@ bool PITimer::waitForFinish(PISystemTime timeout) {
|
||||
|
||||
void PITimer::initFirst() {
|
||||
thread = new PIThread([this] { threadFunc(); });
|
||||
thread->setName("__S__.PITimer.thread");
|
||||
thread->setName("_S.PITimer.thread");
|
||||
setProperty("interval", PISystemTime());
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,11 @@ void PISystemTime::toTimespec(void * ts) {
|
||||
}
|
||||
|
||||
|
||||
PISystemTime::Frequency PISystemTime::toFrequency() {
|
||||
return PISystemTime::Frequency::fromSystemTime(*this);
|
||||
}
|
||||
|
||||
|
||||
PIString PISystemTime::toString() const {
|
||||
static const PISystemTime is_abs_thr = 3650._d; // 10 years
|
||||
if ((*this) >= is_abs_thr) return PIDateTime::fromSystemTime((*this)).toString("yyyy-MM-dd hh:mm:ss.zzz");
|
||||
|
||||
@@ -260,6 +260,10 @@ public:
|
||||
//! \~russian На *nix системах присваивает время к timespec структуре
|
||||
void toTimespec(void * ts);
|
||||
|
||||
//! \~english Returns \a Frequency that corresponds this time interval
|
||||
//! \~russian Возвращает \a Frequency соответствующую этому временному интервалу
|
||||
PISystemTime::Frequency toFrequency();
|
||||
|
||||
//! \~english Returns "yyyy-MM-dd hh:mm:ss.zzz" for absolute time and "<V> <d|h|m|s|ms|us|ns> ..." for relative
|
||||
//! \~russian Возвращает "yyyy-MM-dd hh:mm:ss.zzz" для абсолютного времени и "<V> <d|h|m|s|ms|us|ns> ..." для относительного
|
||||
PIString toString() const;
|
||||
|
||||
152
main.cpp
152
main.cpp
@@ -1,7 +1,11 @@
|
||||
#include "pibytearray.h"
|
||||
#include "piclientserver_client.h"
|
||||
#include "piclientserver_server.h"
|
||||
#include "picodeparser.h"
|
||||
#include "piintrospection_server.h"
|
||||
#include "piiostream.h"
|
||||
#include "pijson.h"
|
||||
#include "pilog.h"
|
||||
#include "pimathbase.h"
|
||||
#include "pip.h"
|
||||
#include "pivaluetree_conversions.h"
|
||||
@@ -16,22 +20,146 @@ enum MyEvent {
|
||||
meIntString,
|
||||
};
|
||||
|
||||
PITimeMeasurer tm;
|
||||
std::atomic_int cnt = {0};
|
||||
void tfunc(int delim) {
|
||||
// piCout << "tick with delimiter" << delim;
|
||||
++cnt;
|
||||
};
|
||||
void tfunc4(int delim) {
|
||||
piCout << "tick4 with delimiter" << delim;
|
||||
PIKbdListener kbd;
|
||||
|
||||
|
||||
class MyServerClient: public PIClientServer::ServerClient {
|
||||
public:
|
||||
~MyServerClient() { send_thread.stopAndWait(); }
|
||||
|
||||
protected:
|
||||
void readed(PIByteArray data) override { piCout << "readed" << (data.size()); }
|
||||
// void aboutDelete() override { piCout << "aboutDelete"; }
|
||||
// void disconnected() override { piCout << "disconnected"; }
|
||||
void connected() override {
|
||||
// piCout << "connected";
|
||||
send_thread.start(
|
||||
[this] {
|
||||
// write((PIString::fromNumber(++counter)).toUTF8());
|
||||
PIByteArray ba(64_KiB);
|
||||
write(ba);
|
||||
},
|
||||
2_Hz);
|
||||
}
|
||||
PIThread send_thread;
|
||||
int counter = 0;
|
||||
};
|
||||
|
||||
|
||||
class MyClient: public PIClientServer::Client {
|
||||
public:
|
||||
~MyClient() { send_thread.stopAndWait(); }
|
||||
|
||||
protected:
|
||||
void readed(PIByteArray data) override { piCout << "readed" << (data.size()); }
|
||||
void disconnected() override { piCout << "disconnected"; }
|
||||
void connected() override {
|
||||
piCout << "connected";
|
||||
send_thread.start(
|
||||
[this] {
|
||||
// write((PIString::fromNumber(++counter)).toUTF8());
|
||||
write(PIByteArray(64_KiB));
|
||||
},
|
||||
2_Hz);
|
||||
}
|
||||
PIThread send_thread;
|
||||
int counter = 0;
|
||||
};
|
||||
|
||||
#include <iostream>
|
||||
int main(int argc, char * argv[]) {
|
||||
uint v = 0xaabbccdd;
|
||||
piCout << Hex << v << piChangedEndian(v);
|
||||
piChangeEndianBinary(&v, sizeof(v));
|
||||
piCout << Hex << v << piChangedEndian(v);
|
||||
PILog log;
|
||||
log.setColorConsole(false);
|
||||
log.setOutput(PILog::File, false);
|
||||
log.setLogName("test");
|
||||
log.setDir("logs");
|
||||
// log.setTimestampFormat("hh-mm-ss");
|
||||
// log.setLineFormat("[c] m (t)");
|
||||
log.start();
|
||||
|
||||
// log.enqueue("debug msg");
|
||||
// log.enqueue("warn msg with ${c}", PILog::Category::Warning);
|
||||
// log.enqueue("ERROR${m}${t}", PILog::Category::Error);
|
||||
log.setLevel(PILog::Level::Info);
|
||||
|
||||
log.debug() << "some msg";
|
||||
piMSleep(50);
|
||||
log.info() << "information";
|
||||
piMSleep(50);
|
||||
log.warning() << "another!";
|
||||
piMSleep(50);
|
||||
log.error(&log) << "critical!";
|
||||
|
||||
// log.stop();
|
||||
return 0;
|
||||
/*PIPeer p("123");
|
||||
|
||||
piCout << "start ...";
|
||||
p.start();
|
||||
piCout << "start ok";
|
||||
|
||||
piSleep(1.);
|
||||
|
||||
piCout << "stop ...";
|
||||
p.stopAndWait();
|
||||
piCout << "stop ok";
|
||||
|
||||
piSleep(1.);
|
||||
|
||||
piCout << "exit";
|
||||
return 0;*/
|
||||
|
||||
if (argc > 1) {
|
||||
PIINTROSPECTION_START(server);
|
||||
} else {
|
||||
PIINTROSPECTION_START(client);
|
||||
}
|
||||
|
||||
kbd.enableExitCapture();
|
||||
|
||||
|
||||
PIClientServer::Server * s = nullptr;
|
||||
PIThread * s_thread = new PIThread();
|
||||
PIVector<PIClientServer::Client *> cv;
|
||||
|
||||
if (argc > 1) {
|
||||
piCout << "Server";
|
||||
s = new PIClientServer::Server();
|
||||
s->setClientFactory([] { return new MyServerClient(); });
|
||||
s->configuration().enableSymmetricEncryption("1122334455667788"_hex);
|
||||
s->listenAll(12345);
|
||||
s_thread->start(
|
||||
[s] {
|
||||
piCout << "*** clients" << s->clientsCount();
|
||||
int i = 0;
|
||||
s->forEachClient([&i](PIClientServer::ServerClient * c) {
|
||||
// piCout << "client" << ++i << c;
|
||||
c->write(PIByteArray(1_KiB));
|
||||
// c->close();
|
||||
// piMSleep(200);
|
||||
});
|
||||
},
|
||||
1._Hz);
|
||||
} else {
|
||||
piCout << "Client";
|
||||
piForTimes(2) {
|
||||
piMSleep(25);
|
||||
auto c = new MyClient();
|
||||
c->configuration().enableSymmetricEncryption("1122334455667788"_hex);
|
||||
c->connect(PINetworkAddress::resolve("127.0.0.1", 12345));
|
||||
cv << c;
|
||||
}
|
||||
}
|
||||
|
||||
WAIT_FOR_EXIT;
|
||||
|
||||
s_thread->stopAndWait();
|
||||
|
||||
piDeleteSafety(s);
|
||||
piDeleteAllAndClear(cv);
|
||||
|
||||
PIINTROSPECTION_STOP
|
||||
|
||||
return 0;
|
||||
/*PIPackedTCP * tcp_s =
|
||||
PIIODevice::createFromFullPath("ptcp://s::8000")->cast<PIPackedTCP>(); // new PIPackedTCP(PIPackedTCP::Server, {"0.0.0.0:8000"});
|
||||
|
||||
@@ -34,3 +34,4 @@ endmacro()
|
||||
pip_test(math)
|
||||
pip_test(core)
|
||||
pip_test(piobject)
|
||||
pip_test(client_server pip_client_server)
|
||||
|
||||
222
tests/client_server/client_server_test.cpp
Normal file
222
tests/client_server/client_server_test.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include "pitime.h"
|
||||
#include "test_client_helper.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
template<bool WithConnectPing = false, bool WithPong = false, ullong WriteSize = 64_KiB>
|
||||
PIClientServer::Server * createServer() {
|
||||
auto s = new PIClientServer::Server();
|
||||
s->setClientFactory([] { return new TestServerClient<WithConnectPing, WithPong, WriteSize>(); });
|
||||
s->listenAll(12345);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool waitLoop(std::function<bool()> exit_loop, const PISystemTime & timeout) {
|
||||
PITimeMeasurer tm;
|
||||
while (tm.elapsed() < timeout) {
|
||||
if (exit_loop()) {
|
||||
return true;
|
||||
}
|
||||
piMinSleep();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Client>
|
||||
Client * createAndConnectClient() {
|
||||
auto c = new Client();
|
||||
c->connect(PINetworkAddress::resolve("127.0.0.1", 12345));
|
||||
return c;
|
||||
}
|
||||
|
||||
TEST(ClientServer, OneClient) {
|
||||
auto const loop_timeout = 1000_ms;
|
||||
auto s = createServer<false, true>();
|
||||
auto c = createAndConnectClient<TestClient<false, false>>();
|
||||
|
||||
waitLoop([s]() { return s->clientsCount() > 0; }, loop_timeout);
|
||||
EXPECT_EQ(1, s->clientsCount());
|
||||
|
||||
c->ping();
|
||||
waitLoop([c]() { return c->pongCnt() > 0; }, loop_timeout);
|
||||
EXPECT_EQ(1, c->pongCnt());
|
||||
|
||||
s->forEachClient([](PIClientServer::ServerClient * sc) { static_cast<TestServerClient<> *>(sc)->ping(); });
|
||||
waitLoop([c]() { return c->pongCnt() > 1; }, loop_timeout);
|
||||
EXPECT_EQ(2, c->pongCnt());
|
||||
|
||||
EXPECT_TRUE(c->getTCP()->isConnected());
|
||||
|
||||
delete c;
|
||||
waitLoop([s]() { return s->clientsCount() == 0; }, loop_timeout);
|
||||
EXPECT_EQ(0, s->clientsCount());
|
||||
delete s;
|
||||
}
|
||||
|
||||
|
||||
class ClientSendThread {
|
||||
using ClientType = TestClient<false, false, 10_KiB>;
|
||||
|
||||
public:
|
||||
ClientSendThread() {
|
||||
client = createAndConnectClient<ClientType>();
|
||||
sendThread.setName("clSend");
|
||||
}
|
||||
|
||||
~ClientSendThread() {
|
||||
sendThread.stopAndWait();
|
||||
delete client;
|
||||
}
|
||||
|
||||
void startSend() {
|
||||
sendThread.start([this] { client->ping(); }, 100._Hz);
|
||||
}
|
||||
|
||||
void sendOnce() { client->ping(); }
|
||||
|
||||
ClientType * client = nullptr;
|
||||
PIThread sendThread;
|
||||
};
|
||||
|
||||
|
||||
int getServerPongs(PIClientServer::Server * s) {
|
||||
int pongs = 0;
|
||||
s->forEachClient([&pongs](PIClientServer::ServerClient * sc) {
|
||||
const auto c = static_cast<TestServerClient<> *>(sc);
|
||||
pongs += c->pongCnt();
|
||||
});
|
||||
return pongs;
|
||||
}
|
||||
|
||||
int getClientsPongs(const PIVector<ClientSendThread *> & clients) {
|
||||
int pongs = 0;
|
||||
clients.forEach([&pongs](ClientSendThread * c) { pongs += c->client->pongCnt(); });
|
||||
return pongs;
|
||||
}
|
||||
|
||||
int getClientsPings(const PIVector<ClientSendThread *> & clients) {
|
||||
int pings = 0;
|
||||
clients.forEach([&pings](ClientSendThread * c) { pings += c->client->pingCnt(); });
|
||||
return pings;
|
||||
}
|
||||
|
||||
|
||||
TEST(ClientServer, ManyClients) {
|
||||
auto const loop_timeout = 1000_ms;
|
||||
constexpr int clients_count = 20;
|
||||
PIVector<ClientSendThread *> clients;
|
||||
auto s = createServer<false, false, 100_KiB>();
|
||||
|
||||
piForTimes(clients_count) {
|
||||
clients.append(new ClientSendThread());
|
||||
}
|
||||
EXPECT_EQ(clients_count, clients.size_s());
|
||||
|
||||
waitLoop([s]() { return s->clientsCount() == clients_count; }, loop_timeout);
|
||||
EXPECT_EQ(clients_count, s->clientsCount());
|
||||
|
||||
EXPECT_EQ(0, getServerPongs(s));
|
||||
|
||||
EXPECT_EQ(getClientsPings(clients), 0);
|
||||
|
||||
for (const auto c: clients) {
|
||||
c->sendOnce();
|
||||
}
|
||||
|
||||
EXPECT_EQ(getClientsPings(clients), clients_count);
|
||||
EXPECT_TRUE(clients.every([](ClientSendThread * c) { return c->client->pingCnt() == 1; }));
|
||||
EXPECT_TRUE(clients.every([](ClientSendThread * c) { return c->client->pongCnt() == 0; }));
|
||||
waitLoop([s]() { return getServerPongs(s) >= clients_count; }, loop_timeout);
|
||||
EXPECT_EQ(clients_count, getServerPongs(s));
|
||||
|
||||
s->forEachClient([](PIClientServer::ServerClient * sc) { static_cast<TestServerClient<> *>(sc)->ping(); });
|
||||
const auto clientCheckPong = [&clients]() { return clients.every([](ClientSendThread * c) { return c->client->pongCnt() == 1; }); };
|
||||
waitLoop([&clientCheckPong]() { return clientCheckPong(); }, loop_timeout);
|
||||
EXPECT_TRUE(clientCheckPong());
|
||||
|
||||
for (const auto c: clients) {
|
||||
c->startSend();
|
||||
}
|
||||
(100_ms).sleep();
|
||||
EXPECT_TRUE(getClientsPings(clients) > clients_count * 2);
|
||||
EXPECT_TRUE(getServerPongs(s) > clients_count * 2);
|
||||
piDeleteAllAndClear(clients);
|
||||
waitLoop([s]() { return s->clientsCount() == 0; }, loop_timeout);
|
||||
EXPECT_EQ(0, s->clientsCount());
|
||||
delete s;
|
||||
}
|
||||
|
||||
TEST(ClientServer, DynamicClients) {
|
||||
auto const loop_timeout = 1000_ms;
|
||||
constexpr int clients_count = 20;
|
||||
PIVector<ClientSendThread *> clients;
|
||||
PIMutex clients_mutex;
|
||||
auto s = createServer<true, true, 10_KiB>();
|
||||
|
||||
const auto spawnClient = [&clients, &clients_mutex]() {
|
||||
// if (clients.size() > 100) return;
|
||||
auto c = new ClientSendThread();
|
||||
c->startSend();
|
||||
clients_mutex.lock();
|
||||
clients << c;
|
||||
clients_mutex.unlock();
|
||||
piCout << "new client" << clients.size();
|
||||
};
|
||||
|
||||
piForTimes(clients_count) {
|
||||
spawnClient();
|
||||
}
|
||||
|
||||
PIThread spawnThread;
|
||||
PIThread deleteThread;
|
||||
spawnThread.setName("spawn");
|
||||
deleteThread.setName("delete");
|
||||
|
||||
spawnThread.start(
|
||||
[&spawnClient]() {
|
||||
const int new_cnt = 7;
|
||||
piForTimes(new_cnt) {
|
||||
spawnClient();
|
||||
}
|
||||
piCout << "+++++++";
|
||||
},
|
||||
12_Hz);
|
||||
|
||||
deleteThread.start(
|
||||
[&clients, &clients_mutex]() {
|
||||
const int rm_cnt = 8;
|
||||
piForTimes(rm_cnt) {
|
||||
ClientSendThread * c = nullptr;
|
||||
clients_mutex.lock();
|
||||
if (clients.size() > 10) {
|
||||
c = clients.take_front();
|
||||
}
|
||||
clients_mutex.unlock();
|
||||
if (c) {
|
||||
delete c;
|
||||
piCout << "remove client" << clients.size();
|
||||
}
|
||||
}
|
||||
piCout << "----------";
|
||||
},
|
||||
13_Hz);
|
||||
|
||||
(2_s).sleep();
|
||||
|
||||
EXPECT_GE(s->clientsCount(), 10);
|
||||
|
||||
piCout << "now clients" << clients.size();
|
||||
|
||||
|
||||
deleteThread.stopAndWait();
|
||||
spawnThread.stopAndWait();
|
||||
|
||||
|
||||
piCout << "total clients" << clients.size();
|
||||
|
||||
piDeleteAllAndClear(clients);
|
||||
waitLoop([s]() { return s->clientsCount() == 0; }, loop_timeout);
|
||||
EXPECT_EQ(0, s->clientsCount());
|
||||
|
||||
delete s;
|
||||
}
|
||||
89
tests/client_server/test_client_helper.h
Normal file
89
tests/client_server/test_client_helper.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef TEST_CLIENT_HELPER_H
|
||||
#define TEST_CLIENT_HELPER_H
|
||||
|
||||
#include "piclientserver_client.h"
|
||||
#include "piclientserver_server.h"
|
||||
#include "piethernet.h"
|
||||
#include "piliterals.h"
|
||||
#include "pithread.h"
|
||||
|
||||
|
||||
template<ullong WriteSize = 64_KiB, bool WithPong = false>
|
||||
class TestClientBase {
|
||||
public:
|
||||
int pongCnt() const { return pong_cnt; }
|
||||
|
||||
int pingCnt() const { return ping_cnt; }
|
||||
|
||||
void ping() {
|
||||
const auto data = PIByteArray(WriteSize);
|
||||
writeInternal(data);
|
||||
ping_cnt++;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void writeInternal(const PIByteArray & ba) = 0;
|
||||
|
||||
void readInternal(const PIByteArray & ba) {
|
||||
last_read_size = ba.size();
|
||||
pong_cnt++;
|
||||
if (WithPong) ping();
|
||||
}
|
||||
|
||||
private:
|
||||
int pong_cnt = 0;
|
||||
int ping_cnt = 0;
|
||||
ullong last_read_size = 0;
|
||||
};
|
||||
|
||||
|
||||
template<bool WithConnectPing = false, bool WithPong = false, ullong WriteSize = 64_KiB>
|
||||
class TestServerClient
|
||||
: public PIClientServer::ServerClient
|
||||
, public TestClientBase<WriteSize, WithPong> {
|
||||
using Base = TestClientBase<WriteSize, WithPong>;
|
||||
|
||||
public:
|
||||
~TestServerClient() {
|
||||
close();
|
||||
stopAndWait();
|
||||
}
|
||||
|
||||
private:
|
||||
void readed(PIByteArray data) override { Base::readInternal(data); }
|
||||
|
||||
void connected() override {
|
||||
if (WithConnectPing) {
|
||||
Base::ping();
|
||||
}
|
||||
}
|
||||
|
||||
void writeInternal(const PIByteArray & ba) override { write(ba); }
|
||||
};
|
||||
|
||||
|
||||
template<bool WithConnectPing = false, bool WithPong = false, ullong WriteSize = 64_KiB>
|
||||
class TestClient
|
||||
: public PIClientServer::Client
|
||||
, public TestClientBase<WriteSize, WithPong> {
|
||||
using Base = TestClientBase<WriteSize, WithPong>;
|
||||
|
||||
public:
|
||||
~TestClient() {
|
||||
close();
|
||||
stopAndWait();
|
||||
}
|
||||
|
||||
private:
|
||||
void readed(PIByteArray data) override { Base::readInternal(data); }
|
||||
|
||||
void connected() override {
|
||||
if (WithConnectPing) {
|
||||
Base::ping();
|
||||
}
|
||||
}
|
||||
|
||||
void writeInternal(const PIByteArray & ba) override { write(ba); }
|
||||
};
|
||||
|
||||
#endif // TEST_CLIENT_HELPER_H
|
||||
@@ -31,23 +31,23 @@ private:
|
||||
TEST(PiobjectConnections, CONNECT0) {
|
||||
Object a;
|
||||
Object b;
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
CONNECT0(void, &a, event_test, &b, handler_test);
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
// piCout << "================";
|
||||
}
|
||||
|
||||
@@ -57,105 +57,105 @@ TEST(PiobjectConnections, CONNECT0_DISCONNECT) {
|
||||
Object b;
|
||||
a.setName("A");
|
||||
b.setName("B");
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
CONNECT0(void, &a, event_test, &b, handler_test);
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
PIObject::piDisconnect(&a, "event_test");
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
// piCout << "================";
|
||||
}
|
||||
|
||||
TEST(PiobjectConnections, CONNECTU) {
|
||||
Object a;
|
||||
Object b;
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
CONNECTU(&a, event_test, &b, handler_test);
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
// piCout << "================";
|
||||
}
|
||||
|
||||
TEST(PiobjectConnections, CONNECTU_DISCONNECT) {
|
||||
Object a;
|
||||
Object b;
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
CONNECTU(&a, event_test, &b, handler_test);
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 0);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 0);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
PIObject::piDisconnect(&a, "event_test");
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
a.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
b.test();
|
||||
ASSERT_EQ(a.getX(), 0);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 0);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
a.handler_val(99);
|
||||
ASSERT_EQ(a.getX(), 99);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 99);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
CONNECTU(&a, event_val, &b, handler_val);
|
||||
ASSERT_EQ(a.getX(), 99);
|
||||
ASSERT_EQ(b.getX(), 1);
|
||||
EXPECT_EQ(a.getX(), 99);
|
||||
EXPECT_EQ(b.getX(), 1);
|
||||
a.test_val();
|
||||
ASSERT_EQ(a.getX(), 99);
|
||||
ASSERT_EQ(b.getX(), 99);
|
||||
EXPECT_EQ(a.getX(), 99);
|
||||
EXPECT_EQ(b.getX(), 99);
|
||||
a.handler_val(-1);
|
||||
ASSERT_EQ(a.getX(), -1);
|
||||
ASSERT_EQ(b.getX(), 99);
|
||||
EXPECT_EQ(a.getX(), -1);
|
||||
EXPECT_EQ(b.getX(), 99);
|
||||
PIObject::piDisconnect(&a, "event_val", &b);
|
||||
ASSERT_EQ(a.getX(), -1);
|
||||
ASSERT_EQ(b.getX(), 99);
|
||||
EXPECT_EQ(a.getX(), -1);
|
||||
EXPECT_EQ(b.getX(), 99);
|
||||
a.test_val();
|
||||
ASSERT_EQ(a.getX(), -1);
|
||||
ASSERT_EQ(b.getX(), 99);
|
||||
EXPECT_EQ(a.getX(), -1);
|
||||
EXPECT_EQ(b.getX(), 99);
|
||||
// piCout << "================";
|
||||
}
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ void Daemon::TileFileProgress::tileEvent(PIScreenTile * t, TileEvent e) {
|
||||
|
||||
Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_" + PIString::fromNumber(randomi() % 100)) {
|
||||
// setName("Daemon");
|
||||
dtimer.setName("__S__Daemon_timer");
|
||||
dtimer.setName("_S.Daemon.timer");
|
||||
mode = rmNone;
|
||||
offset = cur = height = 0;
|
||||
CONNECTU(screen, keyPressed, this, keyEvent)
|
||||
|
||||
@@ -420,7 +420,7 @@ int main(int argc, char * argv[]) {
|
||||
MainMenu * menu = new MainMenu(*daemon);
|
||||
if (sapp) CONNECTU(sapp, messageReceived, menu, messageFromApp);
|
||||
if (cli.hasArgument("silent")) {
|
||||
PICout::setOutputDevices(PICout::StdOut);
|
||||
PICout::setOutputDevices(PICout::Console);
|
||||
PIKbdListener ls;
|
||||
ls.enableExitCapture(PIKbdListener::F10);
|
||||
ls.start();
|
||||
|
||||
Reference in New Issue
Block a user