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
|
/doc/rtf
|
||||||
_unsused
|
_unsused
|
||||||
CMakeLists.txt.user*
|
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(TESTS "Build tests and perform their before install step" ${PIP_BUILD_DEBUG})
|
||||||
option(COVERAGE "Build project with coverage info" OFF)
|
option(COVERAGE "Build project with coverage info" OFF)
|
||||||
set(PIP_UTILS 1)
|
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_REQUIRED TRUE)
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
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
|
# Basic
|
||||||
set(PIP_MODULES)
|
set(PIP_MODULES)
|
||||||
@@ -92,7 +96,7 @@ set(PIP_UTILS_LIST)
|
|||||||
set(PIP_TESTS_LIST)
|
set(PIP_TESTS_LIST)
|
||||||
set(PIP_EXPORTS)
|
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})
|
foreach(_m ${PIP_SRC_MODULES})
|
||||||
set(PIP_MSG_${_m} "no")
|
set(PIP_MSG_${_m} "no")
|
||||||
endforeach()
|
endforeach()
|
||||||
@@ -392,6 +396,7 @@ if (NOT CROSSTOOLS)
|
|||||||
pip_find_lib(sodium)
|
pip_find_lib(sodium)
|
||||||
if(sodium_FOUND)
|
if(sodium_FOUND)
|
||||||
pip_module(crypt "sodium" "PIP crypt support" "" "" "")
|
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" "" "" "")
|
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -480,7 +485,7 @@ if (NOT CROSSTOOLS)
|
|||||||
#target_link_libraries(pip_plugin pip)
|
#target_link_libraries(pip_plugin pip)
|
||||||
|
|
||||||
add_executable(pip_test "main.cpp")
|
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)
|
if(sodium_FOUND)
|
||||||
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
||||||
target_link_libraries(pip_cloud_test pip_cloud)
|
target_link_libraries(pip_cloud_test pip_cloud)
|
||||||
@@ -585,7 +590,7 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
|
|||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
if(DOXYGEN_FOUND)
|
if(DOXYGEN_FOUND)
|
||||||
set(DOXY_DEFINES "${PIP_EXPORTS}")
|
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)
|
string(TOUPPER "${_m}" _mdef)
|
||||||
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
|
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ Create imported targets:
|
|||||||
* PIP::FFTW
|
* PIP::FFTW
|
||||||
* PIP::OpenCL
|
* PIP::OpenCL
|
||||||
* PIP::IOUtils
|
* PIP::IOUtils
|
||||||
|
* PIP::ClientServer
|
||||||
* PIP::Cloud
|
* PIP::Cloud
|
||||||
* PIP::Lua
|
* PIP::Lua
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ include(SHSTKMacros)
|
|||||||
|
|
||||||
shstk_set_find_dirs(PIP)
|
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)
|
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")
|
#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!")
|
message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(__module_usb USB )
|
set(__module_usb USB )
|
||||||
set(__module_console Console )
|
set(__module_console Console )
|
||||||
set(__module_crypt Crypt )
|
set(__module_crypt Crypt )
|
||||||
set(__module_fftw FFTW )
|
set(__module_fftw FFTW )
|
||||||
set(__module_compress Compress )
|
set(__module_compress Compress )
|
||||||
set(__module_opencl OpenCL )
|
set(__module_opencl OpenCL )
|
||||||
set(__module_io_utils IOUtils )
|
set(__module_io_utils IOUtils )
|
||||||
set(__module_cloud Cloud )
|
set(__module_client_server ClientServer)
|
||||||
set(__module_lua Lua )
|
set(__module_cloud Cloud )
|
||||||
|
set(__module_lua Lua )
|
||||||
|
|
||||||
foreach (_l ${__libs})
|
foreach (_l ${__libs})
|
||||||
set( __inc_${_l} "")
|
set( __inc_${_l} "")
|
||||||
@@ -99,8 +101,9 @@ foreach (_l ${__libs})
|
|||||||
set(__libs_${_l} "")
|
set(__libs_${_l} "")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set(__deps_io_utils "PIP::Crypt")
|
set(__deps_io_utils "PIP::Crypt" )
|
||||||
set(__deps_cloud "PIP::IOUtils")
|
set(__deps_client_server "PIP::IOUtils")
|
||||||
|
set(__deps_cloud "PIP::IOUtils")
|
||||||
|
|
||||||
|
|
||||||
if (BUILDING_PIP)
|
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) {
|
void PIStreamPacker::received(const uchar * readed, ssize_t size) {
|
||||||
|
if (size <= 0) return;
|
||||||
received(PIByteArray(readed, size));
|
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[]) {
|
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)
|
for (int i = 0; i < argc; ++i)
|
||||||
_args_raw << argv[i];
|
_args_raw << argv[i];
|
||||||
if (argc > 0) PISystemInfo::instance()->execCommand = argv[0];
|
if (argc > 0) PISystemInfo::instance()->execCommand = argv[0];
|
||||||
@@ -89,7 +84,7 @@ void PICLI::parse() {
|
|||||||
if (cra.left(2) == _prefix_full) {
|
if (cra.left(2) == _prefix_full) {
|
||||||
last = 0;
|
last = 0;
|
||||||
full = cra.right(cra.length() - 2);
|
full = cra.right(cra.length() - 2);
|
||||||
piForeach(Argument & a, _args) {
|
for (auto & a: _args) {
|
||||||
if (a.full_key == full) {
|
if (a.full_key == full) {
|
||||||
a.found = true;
|
a.found = true;
|
||||||
last = &a;
|
last = &a;
|
||||||
@@ -101,7 +96,7 @@ void PICLI::parse() {
|
|||||||
last = 0;
|
last = 0;
|
||||||
for (int j = 1; j < cra.length(); ++j) {
|
for (int j = 1; j < cra.length(); ++j) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
piForeach(Argument & a, _args) {
|
for (auto & a: _args) {
|
||||||
if ((a.short_key != '\0') && (a.short_key == cra[j])) {
|
if ((a.short_key != '\0') && (a.short_key == cra[j])) {
|
||||||
a.found = true;
|
a.found = true;
|
||||||
last = &a;
|
last = &a;
|
||||||
@@ -121,7 +116,7 @@ void PICLI::parse() {
|
|||||||
_args_opt << cra;
|
_args_opt << cra;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
piCoutObj << "[PICli] Arguments overflow, \"" << cra << "\" ignored";
|
piCoutObj << "Arguments overflow, \"" << cra << "\" ignored";
|
||||||
}
|
}
|
||||||
if (last == 0 ? false : last->has_value) {
|
if (last == 0 ? false : last->has_value) {
|
||||||
last->value = cra;
|
last->value = cra;
|
||||||
@@ -132,3 +127,129 @@ void PICLI::parse() {
|
|||||||
}
|
}
|
||||||
needParse = false;
|
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
|
/*! \file picli.h
|
||||||
* \ingroup Core
|
* \ingroup Application
|
||||||
* \~\brief
|
* \~\brief
|
||||||
* \~english Command-Line parser
|
* \~english Command-Line parser
|
||||||
* \~russian Парсер командной строки
|
* \~russian Парсер командной строки
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
#include "piset.h"
|
#include "piset.h"
|
||||||
#include "pistringlist.h"
|
#include "pistringlist.h"
|
||||||
|
|
||||||
//! \ingroup Core
|
//! \ingroup Application
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Command-Line parser.
|
//! \~english Command-Line parser.
|
||||||
//! \~russian Парсер командной строки.
|
//! \~russian Парсер командной строки.
|
||||||
@@ -42,131 +42,65 @@ public:
|
|||||||
|
|
||||||
//! \~english Add argument with name "name", short key = name first letter and full key = name.
|
//! \~english Add argument with name "name", short key = name first letter and full key = name.
|
||||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени.
|
//! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени.
|
||||||
void addArgument(const PIString & name, bool value = false) {
|
void addArgument(const PIString & name, bool value = false);
|
||||||
_args << Argument(name, name[0], name, value);
|
|
||||||
needParse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
|
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
|
||||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
|
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
|
||||||
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {
|
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false);
|
||||||
_args << Argument(name, shortKey, name, value);
|
|
||||||
needParse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
|
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
|
||||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
|
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
|
||||||
void addArgument(const PIString & name, const char * shortKey, bool value = false) {
|
void addArgument(const PIString & name, const char * shortKey, bool value = false);
|
||||||
_args << Argument(name, PIChar::fromUTF8(shortKey), name, value);
|
|
||||||
needParse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
|
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
|
||||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
|
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
|
||||||
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {
|
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false);
|
||||||
_args << Argument(name, shortKey, fullKey, value);
|
|
||||||
needParse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
|
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
|
||||||
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
|
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
|
||||||
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {
|
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false);
|
||||||
_args << Argument(name, PIChar::fromUTF8(shortKey), fullKey, value);
|
|
||||||
needParse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command.
|
//! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command.
|
||||||
//! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы.
|
//! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы.
|
||||||
PIString rawArgument(int index) {
|
PIString rawArgument(int index);
|
||||||
parse();
|
PIString mandatoryArgument(int index);
|
||||||
return _args_raw[index];
|
PIString optionalArgument(int index);
|
||||||
}
|
|
||||||
PIString mandatoryArgument(int index) {
|
|
||||||
parse();
|
|
||||||
return _args_mand[index];
|
|
||||||
}
|
|
||||||
PIString optionalArgument(int index) {
|
|
||||||
parse();
|
|
||||||
return _args_opt[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Returns unparsed command-line arguments.
|
//! \~english Returns unparsed command-line arguments.
|
||||||
//! \~russian Возвращает исходные аргументы командной строки.
|
//! \~russian Возвращает исходные аргументы командной строки.
|
||||||
const PIStringList & rawArguments() {
|
const PIStringList & rawArguments();
|
||||||
parse();
|
const PIStringList & mandatoryArguments();
|
||||||
return _args_raw;
|
const PIStringList & optionalArguments();
|
||||||
}
|
|
||||||
const PIStringList & mandatoryArguments() {
|
|
||||||
parse();
|
|
||||||
return _args_mand;
|
|
||||||
}
|
|
||||||
const PIStringList & optionalArguments() {
|
|
||||||
parse();
|
|
||||||
return _args_opt;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Returns program execute command without arguments.
|
//! \~english Returns program execute command without arguments.
|
||||||
//! \~russian Возвращает команду вызова программы без аргументов.
|
//! \~russian Возвращает команду вызова программы без аргументов.
|
||||||
PIString programCommand() {
|
PIString programCommand();
|
||||||
parse();
|
|
||||||
return _args_raw.size() > 0 ? _args_raw.front() : PIString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Returns if argument "name" found.
|
//! \~english Returns if argument "name" found.
|
||||||
//! \~russian Возвращает найден ли аргумент "name".
|
//! \~russian Возвращает найден ли аргумент "name".
|
||||||
bool hasArgument(const PIString & name) {
|
bool hasArgument(const PIString & name);
|
||||||
parse();
|
|
||||||
piForeach(Argument & i, _args)
|
|
||||||
if (i.name == name && i.found) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Returns argument "name" value, or empty string if this is no value.
|
//! \~english Returns argument "name" value, or empty string if this is no value.
|
||||||
//! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет.
|
//! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет.
|
||||||
PIString argumentValue(const PIString & name) {
|
PIString argumentValue(const PIString & name);
|
||||||
parse();
|
|
||||||
piForeach(Argument & i, _args)
|
|
||||||
if (i.name == name && i.found) return i.value;
|
|
||||||
return PIString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Returns short key of argument "name", or empty string if this is no argument.
|
//! \~english Returns short key of argument "name", or empty string if this is no argument.
|
||||||
//! \~russian Возвращает короткий ключ аргумента "name" или пустую строку, если аргумента нет.
|
//! \~russian Возвращает короткий ключ аргумента "name" или пустую строку, если аргумента нет.
|
||||||
PIString argumentShortKey(const PIString & name) {
|
PIString argumentShortKey(const PIString & name);
|
||||||
piForeach(Argument & i, _args)
|
|
||||||
if (i.name == name) return PIString(i.short_key);
|
|
||||||
return PIString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Returns full key of argument "name", or empty string if this is no argument.
|
//! \~english Returns full key of argument "name", or empty string if this is no argument.
|
||||||
//! \~russian Возвращает полный ключ аргумента "name" или пустую строку, если аргумента нет.
|
//! \~russian Возвращает полный ключ аргумента "name" или пустую строку, если аргумента нет.
|
||||||
PIString argumentFullKey(const PIString & name) {
|
PIString argumentFullKey(const PIString & name);
|
||||||
piForeach(Argument & i, _args)
|
|
||||||
if (i.name == name) return i.full_key;
|
|
||||||
return PIString();
|
|
||||||
}
|
|
||||||
|
|
||||||
const PIString & shortKeyPrefix() const { return _prefix_short; }
|
const PIString & shortKeyPrefix() const { return _prefix_short; }
|
||||||
const PIString & fullKeyPrefix() const { return _prefix_full; }
|
const PIString & fullKeyPrefix() const { return _prefix_full; }
|
||||||
int mandatoryArgumentsCount() const { return _count_mand; }
|
int mandatoryArgumentsCount() const { return _count_mand; }
|
||||||
int optionalArgumentsCount() const { return _count_opt; }
|
int optionalArgumentsCount() const { return _count_opt; }
|
||||||
void setShortKeyPrefix(const PIString & prefix) {
|
void setShortKeyPrefix(const PIString & prefix);
|
||||||
_prefix_short = prefix;
|
void setFullKeyPrefix(const PIString & prefix);
|
||||||
needParse = true;
|
void setMandatoryArgumentsCount(const int count);
|
||||||
}
|
void setOptionalArgumentsCount(const int count);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool debug() const { return debug_; }
|
bool debug() const { return debug_; }
|
||||||
void setDebug(bool debug) { debug_ = debug; }
|
void setDebug(bool debug) { debug_ = debug; }
|
||||||
@@ -175,29 +109,28 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct Argument {
|
struct Argument {
|
||||||
Argument() { has_value = found = false; }
|
Argument() {}
|
||||||
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {
|
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {
|
||||||
name = n;
|
name = n;
|
||||||
short_key = s;
|
short_key = s;
|
||||||
full_key = f;
|
full_key = f;
|
||||||
has_value = v;
|
has_value = v;
|
||||||
found = false;
|
|
||||||
}
|
}
|
||||||
PIString name;
|
PIString name;
|
||||||
PIChar short_key;
|
PIChar short_key;
|
||||||
PIString full_key;
|
PIString full_key;
|
||||||
PIString value;
|
PIString value;
|
||||||
bool has_value, found;
|
bool has_value = false, found = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
|
|
||||||
PIString _prefix_short, _prefix_full;
|
PIString _prefix_short = "-", _prefix_full = "--";
|
||||||
PIStringList _args_raw, _args_mand, _args_opt;
|
PIStringList _args_raw, _args_mand, _args_opt;
|
||||||
PISet<PIString> keys_full, keys_short;
|
PISet<PIString> keys_full, keys_short;
|
||||||
PIVector<Argument> _args;
|
PIVector<Argument> _args;
|
||||||
int _count_mand, _count_opt;
|
int _count_mand = 0, _count_opt = 0;
|
||||||
bool needParse, debug_;
|
bool needParse = true, debug_ = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PICLI_H
|
#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);
|
shm->read(readed.data(), readed.size(), hdr_sz);
|
||||||
PIByteArray msg;
|
PIByteArray msg;
|
||||||
readed >> msg;
|
readed >> msg;
|
||||||
if (!msg.isEmpty()) {
|
if (msg.isNotEmpty()) {
|
||||||
messageReceived(msg);
|
messageReceived(msg);
|
||||||
// piCoutObj << "message" << msg;
|
// piCoutObj << "message" << msg;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*! \file pisingleapplication.h
|
/*! \file pisingleapplication.h
|
||||||
* \ingroup System
|
* \ingroup Application
|
||||||
* \~\brief
|
* \~\brief
|
||||||
* \~english Single-instance application control
|
* \~english Single-instance application control
|
||||||
* \~russian Контроль одного экземпляра приложения
|
* \~russian Контроль одного экземпляра приложения
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
class PISharedMemory;
|
class PISharedMemory;
|
||||||
|
|
||||||
//! \ingroup System
|
//! \ingroup Application
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Single-instance application control.
|
//! \~english Single-instance application control.
|
||||||
//! \~russian Контроль одного экземпляра приложения.
|
//! \~russian Контроль одного экземпляра приложения.
|
||||||
@@ -19,9 +19,10 @@
|
|||||||
|
|
||||||
#include "pisystemmonitor.h"
|
#include "pisystemmonitor.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "pidir.h"
|
#include "pidir.h"
|
||||||
#include "piincludes_p.h"
|
#include "piliterals_string.h"
|
||||||
#include "piliterals.h"
|
|
||||||
#include "piprocess.h"
|
#include "piprocess.h"
|
||||||
#include "pisysteminfo.h"
|
#include "pisysteminfo.h"
|
||||||
#include "pitime_win.h"
|
#include "pitime_win.h"
|
||||||
@@ -150,7 +151,7 @@ void PISystemMonitor::setStatistic(const PISystemMonitor::ProcessStats & s) {
|
|||||||
|
|
||||||
|
|
||||||
void PISystemMonitor::stop() {
|
void PISystemMonitor::stop() {
|
||||||
PIThread::stop();
|
PIThread::stopAndWait();
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
if (PRIVATE->hProc != 0) {
|
if (PRIVATE->hProc != 0) {
|
||||||
CloseHandle(PRIVATE->hProc);
|
CloseHandle(PRIVATE->hProc);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*! \file pisystemmonitor.h
|
/*! \file pisystemmonitor.h
|
||||||
* \ingroup System
|
* \ingroup Application
|
||||||
* \~\brief
|
* \~\brief
|
||||||
* \~english System resources monitoring
|
* \~english System resources monitoring
|
||||||
* \~russian Мониторинг ресурсов системы
|
* \~russian Мониторинг ресурсов системы
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
#include "pithread.h"
|
#include "pithread.h"
|
||||||
|
|
||||||
|
|
||||||
//! \ingroup System
|
//! \ingroup Application
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Process monitoring.
|
//! \~english Process monitoring.
|
||||||
//! \~russian Мониторинг процесса.
|
//! \~russian Мониторинг процесса.
|
||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
~PISystemMonitor();
|
~PISystemMonitor();
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
//! \ingroup System
|
//! \ingroup Application
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Process statistics (fixed-size fields).
|
//! \~english Process statistics (fixed-size fields).
|
||||||
//! \~russian Статистика процесса (фиксированные поля).
|
//! \~russian Статистика процесса (фиксированные поля).
|
||||||
@@ -116,7 +116,7 @@ public:
|
|||||||
float cpu_load_user = 0.f;
|
float cpu_load_user = 0.f;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \ingroup System
|
//! \ingroup Application
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Thread statistics (fixed-size fields).
|
//! \~english Thread statistics (fixed-size fields).
|
||||||
//! \~russian Статистика потока (фиксированные поля).
|
//! \~russian Статистика потока (фиксированные поля).
|
||||||
@@ -151,7 +151,7 @@ public:
|
|||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
//! \ingroup System
|
//! \ingroup Application
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Process statistics.
|
//! \~english Process statistics.
|
||||||
//! \~russian Статистика процесса.
|
//! \~russian Статистика процесса.
|
||||||
@@ -189,7 +189,7 @@ public:
|
|||||||
PIString data_memsize_readable;
|
PIString data_memsize_readable;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \ingroup System
|
//! \ingroup Application
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Thread statistics.
|
//! \~english Thread statistics.
|
||||||
//! \~russian Статистика потока.
|
//! \~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
|
#ifdef WINDOWS
|
||||||
INPUT_RECORD ir;
|
INPUT_RECORD ir;
|
||||||
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
|
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
|
||||||
// piCout << ir.EventType;
|
|
||||||
switch (ir.EventType) {
|
switch (ir.EventType) {
|
||||||
case KEY_EVENT: {
|
case KEY_EVENT: {
|
||||||
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
|
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
|
||||||
@@ -542,6 +541,11 @@ void PIKbdListener::readKeyboard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIKbdListener::stop() {
|
||||||
|
PIThread::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIKbdListener::end() {
|
void PIKbdListener::end() {
|
||||||
// cout << "list end" << endl;
|
// cout << "list end" << endl;
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
|
|||||||
@@ -29,9 +29,10 @@
|
|||||||
#include "pithread.h"
|
#include "pithread.h"
|
||||||
#include "pitime.h"
|
#include "pitime.h"
|
||||||
|
|
||||||
#define WAIT_FOR_EXIT \
|
#define WAIT_FOR_EXIT \
|
||||||
while (!PIKbdListener::exiting) \
|
while (!PIKbdListener::exiting) \
|
||||||
piMSleep(PIP_MIN_MSLEEP * 5); // TODO: rewrite with condvar
|
piMSleep(PIP_MIN_MSLEEP * 5); \
|
||||||
|
if (PIKbdListener::instance()) PIKbdListener::instance()->stopAndWait();
|
||||||
|
|
||||||
|
|
||||||
class PIP_EXPORT PIKbdListener: public PIThread {
|
class PIP_EXPORT PIKbdListener: public PIThread {
|
||||||
@@ -179,6 +180,8 @@ public:
|
|||||||
|
|
||||||
void readKeyboard();
|
void readKeyboard();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
//! Returns if keyboard listening is active (not running!)
|
//! Returns if keyboard listening is active (not running!)
|
||||||
bool isActive() { return is_active; }
|
bool isActive() { return is_active; }
|
||||||
|
|
||||||
|
|||||||
@@ -1383,7 +1383,7 @@ public:
|
|||||||
if (v.isEmpty()) return *this;
|
if (v.isEmpty()) return *this;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (&v == this) {
|
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
|
#endif
|
||||||
assert(&v != this);
|
assert(&v != this);
|
||||||
@@ -1738,7 +1738,7 @@ public:
|
|||||||
if (v.isEmpty()) return *this;
|
if (v.isEmpty()) return *this;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (&v == this) {
|
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
|
#endif
|
||||||
assert(&v != this);
|
assert(&v != this);
|
||||||
@@ -2400,7 +2400,7 @@ public:
|
|||||||
if (isEmpty()) return ret;
|
if (isEmpty()) return ret;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (rows * cols != pid_size) {
|
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
|
#endif
|
||||||
assert(rows * cols == pid_size);
|
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)));
|
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(pid_data), as * sizeof(T)));
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (!p_d) {
|
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
|
#endif
|
||||||
assert(p_d);
|
assert(p_d);
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ public:
|
|||||||
inline PIMap<Key, T> & operator<<(const PIMap<Key, T> & other) {
|
inline PIMap<Key, T> & operator<<(const PIMap<Key, T> & other) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (&other == this) {
|
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
|
#endif
|
||||||
assert(&other != this);
|
assert(&other != this);
|
||||||
|
|||||||
@@ -1341,7 +1341,7 @@ public:
|
|||||||
if (v.isEmpty()) return *this;
|
if (v.isEmpty()) return *this;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (&v == this) {
|
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
|
#endif
|
||||||
assert(&v != this);
|
assert(&v != this);
|
||||||
@@ -1663,7 +1663,7 @@ public:
|
|||||||
if (v.isEmpty()) return *this;
|
if (v.isEmpty()) return *this;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (&v == this) {
|
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
|
#endif
|
||||||
assert(&v != this);
|
assert(&v != this);
|
||||||
@@ -2296,7 +2296,7 @@ public:
|
|||||||
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
|
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (rows * cols != piv_size) {
|
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
|
#endif
|
||||||
assert(rows * cols == piv_size);
|
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)));
|
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), as * sizeof(T)));
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (!p_d) {
|
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
|
#endif
|
||||||
assert(p_d);
|
assert(p_d);
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
inline Row & operator=(const PIVector<T> & other) {
|
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);
|
p_->_copyRaw(p_->data(st_), other.data(), sz);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -677,15 +677,28 @@ public:
|
|||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Destructor that executes the function if it exists
|
//! \~english Destructor that executes the function if it exists
|
||||||
//! \~russian Деструктор, который выполняет функцию, если она существует
|
//! \~russian Деструктор, который выполняет функцию, если она существует
|
||||||
~PIScopeExitCall() {
|
~PIScopeExitCall() { call(); }
|
||||||
if (func) func();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Method for canceling the function
|
//! \~english Method for canceling the function
|
||||||
//! \~russian Метод для отмены функции
|
//! \~russian Метод для отмены функции
|
||||||
void cancel() { func = nullptr; }
|
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:
|
private:
|
||||||
NO_COPY_CLASS(PIScopeExitCall)
|
NO_COPY_CLASS(PIScopeExitCall)
|
||||||
|
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ typedef long long ssize_t;
|
|||||||
__PrivateInitializer__(const __PrivateInitializer__ & o); \
|
__PrivateInitializer__(const __PrivateInitializer__ & o); \
|
||||||
~__PrivateInitializer__(); \
|
~__PrivateInitializer__(); \
|
||||||
__PrivateInitializer__ & operator=(const __PrivateInitializer__ & o); \
|
__PrivateInitializer__ & operator=(const __PrivateInitializer__ & o); \
|
||||||
__Private__ * p; \
|
__Private__ * p = nullptr; \
|
||||||
}; \
|
}; \
|
||||||
__PrivateInitializer__ __privateinitializer__;
|
__PrivateInitializer__ __privateinitializer__;
|
||||||
|
|
||||||
@@ -343,11 +343,10 @@ typedef long long ssize_t;
|
|||||||
p = new c::__Private__(); \
|
p = new c::__Private__(); \
|
||||||
} \
|
} \
|
||||||
c::__PrivateInitializer__::~__PrivateInitializer__() { \
|
c::__PrivateInitializer__::~__PrivateInitializer__() { \
|
||||||
delete p; \
|
piDeleteSafety(p); \
|
||||||
p = 0; \
|
|
||||||
} \
|
} \
|
||||||
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator=(const c::__PrivateInitializer__ &) { \
|
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator=(const c::__PrivateInitializer__ &) { \
|
||||||
if (p) delete p; \
|
piDeleteSafety(p); \
|
||||||
p = new c::__Private__(); \
|
p = new c::__Private__(); \
|
||||||
return *this; \
|
return *this; \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,6 @@
|
|||||||
#define PICOREMODULE_H
|
#define PICOREMODULE_H
|
||||||
|
|
||||||
#include "pichunkstream.h"
|
#include "pichunkstream.h"
|
||||||
#include "picli.h"
|
|
||||||
#include "picollection.h"
|
#include "picollection.h"
|
||||||
#include "pijson.h"
|
#include "pijson.h"
|
||||||
#include "piobject.h"
|
#include "piobject.h"
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ PIString & PICout::__string__() {
|
|||||||
return *ret;
|
return *ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
PICout::OutputDevices PICout::devs = PICout::StdOut;
|
PICout::OutputDevices PICout::devs = PICout::Console;
|
||||||
|
|
||||||
PRIVATE_DEFINITION_START(PICout)
|
PRIVATE_DEFINITION_START(PICout)
|
||||||
PIStack<PICoutControls> cos_;
|
PIStack<PICoutControls> cos_;
|
||||||
@@ -158,35 +158,53 @@ WORD PICout::__Private__::dattr = 0;
|
|||||||
DWORD PICout::__Private__::smode = 0;
|
DWORD PICout::__Private__::smode = 0;
|
||||||
#endif
|
#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();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) {
|
PICout::PICout(bool active, PICoutStdStream stream): actve_(active), stream_(stream) {
|
||||||
buffer_ = nullptr;
|
if (actve_) init();
|
||||||
if (act_) init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PICout::PICout(const PICout & other)
|
PICout::PICout(const PICout & other)
|
||||||
: fo_(other.fo_)
|
: first_out_(other.first_out_)
|
||||||
, cc_(true)
|
, is_copy_(true)
|
||||||
, fc_(false)
|
, actve_(other.actve_)
|
||||||
, act_(other.act_)
|
, int_base_(other.int_base_)
|
||||||
, cnb_(other.cnb_)
|
, win_attr_(other.win_attr_)
|
||||||
, attr_(other.attr_)
|
|
||||||
, id_(other.id_)
|
, id_(other.id_)
|
||||||
, buffer_(other.buffer_)
|
, buffer_(other.buffer_)
|
||||||
, co_(other.co_) {}
|
, ctrl_(other.ctrl_)
|
||||||
|
, stream_(other.stream_) {}
|
||||||
|
|
||||||
|
|
||||||
PICout::~PICout() {
|
PICout::~PICout() {
|
||||||
if (!act_) return;
|
if (!actve_) return;
|
||||||
if (fc_) applyFormat(PICoutManipulators::Default);
|
if (format_changed_) applyFormat(PICoutManipulators::Default);
|
||||||
if (cc_) return;
|
if (is_copy_) return;
|
||||||
newLine();
|
newLine();
|
||||||
if ((co_ & NoLock) != NoLock) {
|
if ((ctrl_ & NoLock) != NoLock) {
|
||||||
PICout::__mutex__().unlock();
|
PICout::__mutex__().unlock();
|
||||||
}
|
}
|
||||||
if (buffer_) {
|
if (buffer_) {
|
||||||
@@ -196,7 +214,7 @@ PICout::~PICout() {
|
|||||||
|
|
||||||
|
|
||||||
PICout & PICout::operator<<(PICoutAction v) {
|
PICout & PICout::operator<<(PICoutAction v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||||
COORD coord;
|
COORD coord;
|
||||||
@@ -204,12 +222,12 @@ PICout & PICout::operator<<(PICoutAction v) {
|
|||||||
#endif
|
#endif
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case PICoutManipulators::Flush:
|
case PICoutManipulators::Flush:
|
||||||
if (!buffer_ && isOutputDeviceActive(StdOut)) {
|
if (!buffer_ && isOutputDeviceActive(Console)) {
|
||||||
std::cout << std::flush;
|
getStdStream(stream_) << std::flush;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PICoutManipulators::Backspace:
|
case PICoutManipulators::Backspace:
|
||||||
if (isOutputDeviceActive(StdOut)) {
|
if (isOutputDeviceActive(Console)) {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||||
coord = sbi.dwCursorPosition;
|
coord = sbi.dwCursorPosition;
|
||||||
@@ -223,7 +241,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PICoutManipulators::ShowCursor:
|
case PICoutManipulators::ShowCursor:
|
||||||
if (isOutputDeviceActive(StdOut)) {
|
if (isOutputDeviceActive(Console)) {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||||
curinfo.bVisible = true;
|
curinfo.bVisible = true;
|
||||||
@@ -234,7 +252,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PICoutManipulators::HideCursor:
|
case PICoutManipulators::HideCursor:
|
||||||
if (isOutputDeviceActive(StdOut)) {
|
if (isOutputDeviceActive(Console)) {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||||
curinfo.bVisible = false;
|
curinfo.bVisible = false;
|
||||||
@@ -245,7 +263,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PICoutManipulators::ClearLine:
|
case PICoutManipulators::ClearLine:
|
||||||
if (isOutputDeviceActive(StdOut)) {
|
if (isOutputDeviceActive(Console)) {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||||
coord = sbi.dwCursorPosition;
|
coord = sbi.dwCursorPosition;
|
||||||
@@ -266,7 +284,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PICoutManipulators::ClearScreen:
|
case PICoutManipulators::ClearScreen:
|
||||||
if (isOutputDeviceActive(StdOut)) {
|
if (isOutputDeviceActive(Console)) {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
/// TODO : wondows ClearScreen !!!
|
/// TODO : wondows ClearScreen !!!
|
||||||
#else
|
#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) {
|
PICout & PICout::operator<<(PICoutManipulators::PICoutFormat v) {
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case PICoutManipulators::Bin: cnb_ = 2; break;
|
case PICoutManipulators::Bin: int_base_ = 2; break;
|
||||||
case PICoutManipulators::Oct: cnb_ = 8; break;
|
case PICoutManipulators::Oct: int_base_ = 8; break;
|
||||||
case PICoutManipulators::Dec: cnb_ = 10; break;
|
case PICoutManipulators::Dec: int_base_ = 10; break;
|
||||||
case PICoutManipulators::Hex: cnb_ = 16; break;
|
case PICoutManipulators::Hex: int_base_ = 16; break;
|
||||||
default: applyFormat(v);
|
default: applyFormat(v);
|
||||||
};
|
};
|
||||||
return *this;
|
return *this;
|
||||||
@@ -295,10 +332,10 @@ PICout & PICout::operator<<(PICoutManipulators::PICoutFormat v) {
|
|||||||
|
|
||||||
|
|
||||||
PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) {
|
PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) {
|
||||||
if (v[PICoutManipulators::Bin]) cnb_ = 2;
|
if (v[PICoutManipulators::Bin]) int_base_ = 2;
|
||||||
if (v[PICoutManipulators::Oct]) cnb_ = 8;
|
if (v[PICoutManipulators::Oct]) int_base_ = 8;
|
||||||
if (v[PICoutManipulators::Dec]) cnb_ = 10;
|
if (v[PICoutManipulators::Dec]) int_base_ = 10;
|
||||||
if (v[PICoutManipulators::Hex]) cnb_ = 16;
|
if (v[PICoutManipulators::Hex]) int_base_ = 16;
|
||||||
if (v[PICoutManipulators::Bold]) applyFormat(PICoutManipulators::Bold);
|
if (v[PICoutManipulators::Bold]) applyFormat(PICoutManipulators::Bold);
|
||||||
if (v[PICoutManipulators::Faint]) applyFormat(PICoutManipulators::Faint);
|
if (v[PICoutManipulators::Faint]) applyFormat(PICoutManipulators::Faint);
|
||||||
if (v[PICoutManipulators::Italic]) applyFormat(PICoutManipulators::Italic);
|
if (v[PICoutManipulators::Italic]) applyFormat(PICoutManipulators::Italic);
|
||||||
@@ -324,31 +361,78 @@ PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PIINTCOUT(v) \
|
|
||||||
{ \
|
void PICout::stdoutPIString(const PIString & str, PICoutStdStream s) {
|
||||||
if (!act_) return *this; \
|
#ifdef HAS_LOCALE
|
||||||
space(); \
|
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8conv;
|
||||||
if (cnb_ == 10) { \
|
getStdStream(s) << utf8conv.to_bytes((char16_t *)&(const_cast<PIString &>(str).front()),
|
||||||
if (buffer_) { \
|
(char16_t *)&(const_cast<PIString &>(str).front()) + str.size());
|
||||||
(*buffer_) += PIString::fromNumber(v); \
|
#else
|
||||||
} else { \
|
for (PIChar c: str)
|
||||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v); \
|
getStdWStream(s).put(c.toWChar());
|
||||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v); \
|
#endif
|
||||||
} \
|
}
|
||||||
} else \
|
|
||||||
write(PIString::fromNumber(v, cnb_)); \
|
|
||||||
return *this; \
|
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) \
|
#define PIFLOATCOUT(v) \
|
||||||
{ \
|
{ \
|
||||||
if (buffer_) { \
|
if (buffer_) { \
|
||||||
(*buffer_) += PIString::fromNumber(v, 'g'); \
|
(*buffer_) += PIString::fromNumber(v, 'g'); \
|
||||||
} else { \
|
} else { \
|
||||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v); \
|
if (isOutputDeviceActive(Console)) getStdStream(stream_) << (v); \
|
||||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v, 'g'); \
|
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIString::fromNumber(v, 'g'); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
|
|
||||||
@@ -361,7 +445,7 @@ PICout & PICout::operator<<(const PIString & v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PICout & PICout::operator<<(const char * v) {
|
PICout & PICout::operator<<(const char * v) {
|
||||||
if (!act_ || !v) return *this;
|
if (!actve_ || !v) return *this;
|
||||||
if (v[0] == '\0') return *this;
|
if (v[0] == '\0') return *this;
|
||||||
space();
|
space();
|
||||||
quote();
|
quote();
|
||||||
@@ -371,7 +455,7 @@ PICout & PICout::operator<<(const char * v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PICout & PICout::operator<<(bool v) {
|
PICout & PICout::operator<<(bool v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
space();
|
space();
|
||||||
if (v)
|
if (v)
|
||||||
write("true");
|
write("true");
|
||||||
@@ -381,7 +465,7 @@ PICout & PICout::operator<<(bool v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PICout & PICout::operator<<(char v) {
|
PICout & PICout::operator<<(char v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
space();
|
space();
|
||||||
write(v);
|
write(v);
|
||||||
return *this;
|
return *this;
|
||||||
@@ -406,32 +490,32 @@ PICout & PICout::operator<<(llong v){PIINTCOUT(v)}
|
|||||||
PICout & PICout::operator<<(ullong v){PIINTCOUT(v)}
|
PICout & PICout::operator<<(ullong v){PIINTCOUT(v)}
|
||||||
|
|
||||||
PICout & PICout::operator<<(float v) {
|
PICout & PICout::operator<<(float v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
space();
|
space();
|
||||||
PIFLOATCOUT(v)
|
PIFLOATCOUT(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
PICout & PICout::operator<<(double v) {
|
PICout & PICout::operator<<(double v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
space();
|
space();
|
||||||
PIFLOATCOUT(v)
|
PIFLOATCOUT(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
PICout & PICout::operator<<(ldouble v) {
|
PICout & PICout::operator<<(ldouble v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
space();
|
space();
|
||||||
PIFLOATCOUT(v)
|
PIFLOATCOUT(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
PICout & PICout::operator<<(const void * v) {
|
PICout & PICout::operator<<(const void * v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
space();
|
space();
|
||||||
write("0x" + PIString::fromNumber(ullong(v), 16));
|
write("0x" + PIString::fromNumber(ullong(v), 16));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
PICout & PICout::operator<<(const PIObject * v) {
|
PICout & PICout::operator<<(const PIObject * v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
space();
|
space();
|
||||||
if (v == 0)
|
if (v == 0)
|
||||||
write("PIObject*(0x0)");
|
write("PIObject*(0x0)");
|
||||||
@@ -443,74 +527,38 @@ PICout & PICout::operator<<(const PIObject * v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PICout & PICout::operator<<(PICoutSpecialChar v) {
|
PICout & PICout::operator<<(PICoutSpecialChar v) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case Null:
|
case Null: writeChar(char(0)); break;
|
||||||
if (buffer_) {
|
|
||||||
(*buffer_) += PIChar();
|
|
||||||
} else {
|
|
||||||
if (isOutputDeviceActive(StdOut)) std::cout << char(0);
|
|
||||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NewLine:
|
case NewLine:
|
||||||
if (buffer_) {
|
first_out_ = true;
|
||||||
(*buffer_) += "\n";
|
writeChar('\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";
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
case Tab: writeChar('\t'); break;
|
||||||
case Esc:
|
case Esc:
|
||||||
#ifdef CC_VC
|
#ifdef CC_VC
|
||||||
if (buffer_) {
|
writeChar(char(27));
|
||||||
(*buffer_) += PIChar(27);
|
|
||||||
} else {
|
|
||||||
if (isOutputDeviceActive(StdOut)) std::cout << char(27);
|
|
||||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar(27);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (buffer_) {
|
writeChar('\e');
|
||||||
(*buffer_) += "\e";
|
|
||||||
} else {
|
|
||||||
if (isOutputDeviceActive(StdOut)) std::cout << '\e';
|
|
||||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\e";
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case Quote:
|
case Quote: writeChar('"'); break;
|
||||||
if (buffer_) {
|
|
||||||
(*buffer_) += "\"";
|
|
||||||
} else {
|
|
||||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
|
||||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\"";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
};
|
};
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PICout & PICout::saveControls() {
|
PICout & PICout::saveControls() {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
PRIVATE->cos_.push(co_);
|
PRIVATE->cos_.push(ctrl_);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PICout & PICout::restoreControls() {
|
PICout & PICout::restoreControls() {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
if (!PRIVATE->cos_.isEmpty()) {
|
if (!PRIVATE->cos_.isEmpty()) {
|
||||||
co_ = PRIVATE->cos_.top();
|
ctrl_ = PRIVATE->cos_.top();
|
||||||
PRIVATE->cos_.pop();
|
PRIVATE->cos_.pop();
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@@ -524,16 +572,11 @@ PICout & PICout::restoreControls() {
|
|||||||
//! Добавляет пробел если это не первый вывод и установлен флаг \a AddSpaces
|
//! Добавляет пробел если это не первый вывод и установлен флаг \a AddSpaces
|
||||||
//! \~\sa \a quote(), \a newLine()
|
//! \~\sa \a quote(), \a newLine()
|
||||||
PICout & PICout::space() {
|
PICout & PICout::space() {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
if (!fo_ && co_[AddSpaces]) {
|
if (!first_out_ && ctrl_[AddSpaces]) {
|
||||||
if (buffer_) {
|
writeChar(' ');
|
||||||
(*buffer_) += " ";
|
|
||||||
} else {
|
|
||||||
if (isOutputDeviceActive(StdOut)) std::cout << ' ';
|
|
||||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += " ";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fo_ = false;
|
first_out_ = false;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,16 +587,11 @@ PICout & PICout::space() {
|
|||||||
//! Добавляет кавычки если установлен флаг \a AddQuotes
|
//! Добавляет кавычки если установлен флаг \a AddQuotes
|
||||||
//! \~\sa \a space(), \a newLine()
|
//! \~\sa \a space(), \a newLine()
|
||||||
PICout & PICout::quote() {
|
PICout & PICout::quote() {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
if (co_[AddQuotes]) {
|
if (ctrl_[AddQuotes]) {
|
||||||
if (buffer_) {
|
writeChar('"');
|
||||||
(*buffer_) += "\"";
|
|
||||||
} else {
|
|
||||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
|
||||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\"";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fo_ = false;
|
first_out_ = false;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,74 +602,28 @@ PICout & PICout::quote() {
|
|||||||
//! Добавляет новую строку если установлен флаг \a AddNewLine
|
//! Добавляет новую строку если установлен флаг \a AddNewLine
|
||||||
//! \~\sa \a space(), \a quote()
|
//! \~\sa \a space(), \a quote()
|
||||||
PICout & PICout::newLine() {
|
PICout & PICout::newLine() {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
if (co_[AddNewLine]) {
|
if (ctrl_[AddNewLine]) {
|
||||||
if (buffer_) {
|
writeChar('\n');
|
||||||
(*buffer_) += "\n";
|
|
||||||
} else {
|
|
||||||
if (isOutputDeviceActive(StdOut)) std::cout << std::endl;
|
|
||||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fo_ = false;
|
first_out_ = false;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PICout & PICout::write(char c) {
|
PICout & PICout::write(char c) {
|
||||||
if (!act_) return *this;
|
if (!actve_) return *this;
|
||||||
if (buffer_) {
|
writeChar(c);
|
||||||
buffer_->append(c);
|
|
||||||
} else {
|
|
||||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << c;
|
|
||||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(c);
|
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PICout & PICout::write(const char * str) {
|
PICout & PICout::write(const char * str) {
|
||||||
if (!act_ || !str) return *this;
|
if (!actve_ || !str) return *this;
|
||||||
return write(str, strlen(str));
|
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() {
|
void PICout::init() {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
if (__Private__::hOut == 0) {
|
if (__Private__::hOut == 0) {
|
||||||
@@ -640,19 +632,18 @@ void PICout::init() {
|
|||||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||||
__Private__::dattr = sbi.wAttributes;
|
__Private__::dattr = sbi.wAttributes;
|
||||||
}
|
}
|
||||||
attr_ = __Private__::dattr;
|
win_attr_ = __Private__::dattr;
|
||||||
#endif
|
#endif
|
||||||
id_ = 0;
|
if ((ctrl_ & NoLock) != NoLock) {
|
||||||
if ((co_ & NoLock) != NoLock) {
|
|
||||||
PICout::__mutex__().lock();
|
PICout::__mutex__().lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PICout::applyFormat(PICoutFormat f) {
|
void PICout::applyFormat(PICoutFormat f) {
|
||||||
if (!act_) return;
|
if (!actve_) return;
|
||||||
if (buffer_ || !isOutputDeviceActive(StdOut)) return;
|
if (buffer_ || !isOutputDeviceActive(Console)) return;
|
||||||
fc_ = true;
|
format_changed_ = true;
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||||
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||||
@@ -661,28 +652,28 @@ void PICout::applyFormat(PICoutFormat f) {
|
|||||||
case Oct:
|
case Oct:
|
||||||
case Dec:
|
case Dec:
|
||||||
case Hex: break;
|
case Hex: break;
|
||||||
case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break;
|
case PICoutManipulators::Bold: win_attr_ |= FOREGROUND_INTENSITY; break;
|
||||||
case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break;
|
case PICoutManipulators::Underline: win_attr_ |= COMMON_LVB_UNDERSCORE; break;
|
||||||
case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break;
|
case PICoutManipulators::Black: win_attr_ = (win_attr_ & mask_fore); break;
|
||||||
case PICoutManipulators::Red: attr_ = (attr_ & mask_fore) | FOREGROUND_RED; break;
|
case PICoutManipulators::Red: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED; break;
|
||||||
case PICoutManipulators::Green: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN; break;
|
case PICoutManipulators::Green: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_GREEN; break;
|
||||||
case PICoutManipulators::Blue: attr_ = (attr_ & mask_fore) | FOREGROUND_BLUE; break;
|
case PICoutManipulators::Blue: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_BLUE; break;
|
||||||
case PICoutManipulators::Yellow: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
|
case PICoutManipulators::Yellow: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
|
||||||
case PICoutManipulators::Magenta: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
|
case PICoutManipulators::Magenta: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
|
||||||
case PICoutManipulators::Cyan: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
case PICoutManipulators::Cyan: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||||
case PICoutManipulators::White: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
case PICoutManipulators::White: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||||
case PICoutManipulators::BackBlack: attr_ = (attr_ & mask_back); break;
|
case PICoutManipulators::BackBlack: win_attr_ = (win_attr_ & mask_back); break;
|
||||||
case PICoutManipulators::BackRed: attr_ = (attr_ & mask_back) | BACKGROUND_RED; break;
|
case PICoutManipulators::BackRed: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED; break;
|
||||||
case PICoutManipulators::BackGreen: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN; break;
|
case PICoutManipulators::BackGreen: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_GREEN; break;
|
||||||
case PICoutManipulators::BackBlue: attr_ = (attr_ & mask_back) | BACKGROUND_BLUE; break;
|
case PICoutManipulators::BackBlue: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_BLUE; break;
|
||||||
case PICoutManipulators::BackYellow: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
|
case PICoutManipulators::BackYellow: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
|
||||||
case PICoutManipulators::BackMagenta: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
|
case PICoutManipulators::BackMagenta: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
|
||||||
case PICoutManipulators::BackCyan: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
case PICoutManipulators::BackCyan: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||||
case PICoutManipulators::BackWhite: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
case PICoutManipulators::BackWhite: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||||
case PICoutManipulators::Default: attr_ = __Private__::dattr; break;
|
case PICoutManipulators::Default: win_attr_ = __Private__::dattr; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
SetConsoleTextAttribute(__Private__::hOut, attr_);
|
SetConsoleTextAttribute(__Private__::hOut, win_attr_);
|
||||||
#else
|
#else
|
||||||
switch (f) {
|
switch (f) {
|
||||||
case Bin:
|
case Bin:
|
||||||
@@ -761,3 +752,8 @@ PICout PICout::withExternalBuffer(PIString * buffer, int id, PIFlags<PICoutManip
|
|||||||
c.id_ = id;
|
c.id_ = id;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PICout::registerExternalBufferID() {
|
||||||
|
return Notifier::instance()->new_id.fetch_add(1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,10 +40,14 @@
|
|||||||
# define piCoutObj
|
# define piCoutObj
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define piCout PICout(piDebug)
|
# define piCout PICout(piDebug, PICoutManipulators::StdOut)
|
||||||
# define piCoutObj \
|
# define piCoutObj \
|
||||||
PICout(piDebug && debug()) << (PIStringAscii("[") + className() + \
|
PICout(piDebug && debug(), PICoutManipulators::StdOut) \
|
||||||
(name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
<< (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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -55,6 +59,7 @@ class PIObject;
|
|||||||
//! \~russian Пространство имен содержит перечисления для контроля PICout
|
//! \~russian Пространство имен содержит перечисления для контроля PICout
|
||||||
namespace PICoutManipulators {
|
namespace PICoutManipulators {
|
||||||
|
|
||||||
|
|
||||||
//! \~english Enum contains special characters
|
//! \~english Enum contains special characters
|
||||||
//! \~russian Перечисление со спецсимволами
|
//! \~russian Перечисление со спецсимволами
|
||||||
enum PICoutSpecialChar {
|
enum PICoutSpecialChar {
|
||||||
@@ -65,6 +70,7 @@ enum PICoutSpecialChar {
|
|||||||
Quote /*! \~english Quote character, '\"' \~russian Кавычки, '\"' */
|
Quote /*! \~english Quote character, '\"' \~russian Кавычки, '\"' */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//! \~english Enum contains immediate action
|
//! \~english Enum contains immediate action
|
||||||
//! \~russian Перечисление с немедленными действиями
|
//! \~russian Перечисление с немедленными действиями
|
||||||
enum PICoutAction {
|
enum PICoutAction {
|
||||||
@@ -79,6 +85,7 @@ enum PICoutAction {
|
|||||||
restoreControl() */
|
restoreControl() */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//! \~english Enum contains control of PICout
|
//! \~english Enum contains control of PICout
|
||||||
//! \~russian Перечисление с управлением PICout
|
//! \~russian Перечисление с управлением PICout
|
||||||
enum PICoutControl {
|
enum PICoutControl {
|
||||||
@@ -91,6 +98,7 @@ enum PICoutControl {
|
|||||||
NoLock /*! \~english Don`t use mutex for output \~russian Не использовать мьютекс при выводе */ = 0x100,
|
NoLock /*! \~english Don`t use mutex for output \~russian Не использовать мьютекс при выводе */ = 0x100,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//! \~english Enum contains output format
|
//! \~english Enum contains output format
|
||||||
//! \~russian Перечисление с форматом вывода
|
//! \~russian Перечисление с форматом вывода
|
||||||
enum PICoutFormat {
|
enum PICoutFormat {
|
||||||
@@ -122,7 +130,17 @@ enum PICoutFormat {
|
|||||||
Default /*! \~english Default format \~russian Формат по умолчанию */ = 0x4000000
|
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;
|
typedef PIFlags<PICoutControl> PICoutControls;
|
||||||
|
|
||||||
} // namespace PICoutManipulators
|
} // namespace PICoutManipulators
|
||||||
|
|
||||||
|
|
||||||
@@ -134,11 +152,11 @@ class PIP_EXPORT PICout {
|
|||||||
public:
|
public:
|
||||||
//! \~english Default constructor with default features (AddSpaces and AddNewLine)
|
//! \~english Default constructor with default features (AddSpaces and AddNewLine)
|
||||||
//! \~russian Конструктор по умолчанию (AddSpaces и 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
|
//! \~english Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
|
||||||
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным
|
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным
|
||||||
PICout(bool active);
|
PICout(bool active, PICoutManipulators::PICoutStdStream stream = PICoutManipulators::StdOut);
|
||||||
|
|
||||||
PICout(const PICout & other);
|
PICout(const PICout & other);
|
||||||
|
|
||||||
@@ -146,6 +164,8 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
class PIP_EXPORT Notifier {
|
class PIP_EXPORT Notifier {
|
||||||
|
friend class PICout;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! \~english Singleton access to %PICout::Notifier
|
//! \~english Singleton access to %PICout::Notifier
|
||||||
//! \~russian Синглтон класса %PICout::Notifier
|
//! \~russian Синглтон класса %PICout::Notifier
|
||||||
@@ -158,15 +178,17 @@ public:
|
|||||||
private:
|
private:
|
||||||
Notifier();
|
Notifier();
|
||||||
PIObject * o;
|
PIObject * o;
|
||||||
|
std::atomic_int new_id = {1};
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \~english Enum contains output devices of %PICout
|
//! \~english Enum contains output devices of %PICout
|
||||||
//! \~russian Перечисление с устройствами вывода для %PICout
|
//! \~russian Перечисление с устройствами вывода для %PICout
|
||||||
enum OutputDevice {
|
enum OutputDevice {
|
||||||
NoDevices /** \~english %PICout is disabled \~russian %PICout неактивен */ = 0x0,
|
NoDevices /** \~english %PICout is disabled \~russian %PICout неактивен */ = 0x0,
|
||||||
StdOut /** \~english Standard console output \~russian Стандартный вывод в консоль */ = 0x1,
|
Console /** \~english Standard console output \~russian Стандартный вывод в консоль */ = 0x1,
|
||||||
Buffer /** \~english Internal buffer \~russian Внутренний буфер */ = 0x2,
|
StdOut DEPRECATEDM("use PICout::Console") = Console,
|
||||||
AllDevices /** \~english All \~russian Все */ = 0xFFFF,
|
Buffer /** \~english Internal buffer \~russian Внутренний буфер */ = 0x2,
|
||||||
|
AllDevices /** \~english All \~russian Все */ = 0xFFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef PIFlags<OutputDevice> OutputDevices;
|
typedef PIFlags<OutputDevice> OutputDevices;
|
||||||
@@ -261,25 +283,15 @@ public:
|
|||||||
|
|
||||||
//! \~english Set control flag "c" is "on" state
|
//! \~english Set control flag "c" is "on" state
|
||||||
//! \~russian Установить флаг "c" в "on" состояние
|
//! \~russian Установить флаг "c" в "on" состояние
|
||||||
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) {
|
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true);
|
||||||
co_.setFlag(c, on);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Set control flags "c"
|
//! \~english Set control flags "c"
|
||||||
//! \~russian Установить флаги "c"
|
//! \~russian Установить флаги "c"
|
||||||
PICout & setControls(PICoutManipulators::PICoutControls c) {
|
PICout & setControls(PICoutManipulators::PICoutControls c);
|
||||||
co_ = c;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Exec \a saveControls() and set control flags to "c"
|
//! \~english Exec \a saveControls() and set control flags to "c"
|
||||||
//! \~russian Иыполнить \a saveControls() и Установить флаги "c"
|
//! \~russian Иыполнить \a saveControls() и Установить флаги "c"
|
||||||
PICout & saveAndSetControls(PICoutManipulators::PICoutControls c) {
|
PICout & saveAndSetControls(PICoutManipulators::PICoutControls c);
|
||||||
saveControls();
|
|
||||||
co_ = c;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Save control flags to internal stack
|
//! \~english Save control flags to internal stack
|
||||||
//! \~russian Сохраняет состояние флагов во внутренний стек
|
//! \~russian Сохраняет состояние флагов во внутренний стек
|
||||||
@@ -321,7 +333,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Output \a PIString to stdout
|
//! \~english Output \a PIString to stdout
|
||||||
//! \~russian Вывод \a PIString в 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
|
//! \~english Returns internal PIString buffer
|
||||||
//! \~russian Возвращает внутренний PIString буфер
|
//! \~russian Возвращает внутренний PIString буфер
|
||||||
@@ -368,19 +380,25 @@ public:
|
|||||||
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces |
|
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces |
|
||||||
PICoutManipulators::AddNewLine);
|
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 PIMutex & __mutex__();
|
||||||
static PIString & __string__();
|
static PIString & __string__();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
void applyFormat(PICoutManipulators::PICoutFormat f);
|
void applyFormat(PICoutManipulators::PICoutFormat f);
|
||||||
|
void writeChar(char c);
|
||||||
|
|
||||||
static OutputDevices devs;
|
static OutputDevices devs;
|
||||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||||
bool fo_, cc_, fc_, act_;
|
bool first_out_ = true, is_copy_ = false, format_changed_ = false, actve_ = true;
|
||||||
int cnb_, attr_, id_;
|
int int_base_ = 10, win_attr_ = 0, id_ = 0;
|
||||||
PIString * buffer_;
|
PIString * buffer_ = nullptr;
|
||||||
PICoutManipulators::PICoutControls co_;
|
PICoutManipulators::PICoutControls ctrl_ = PICoutManipulators::DefaultControls;
|
||||||
|
PICoutManipulators::PICoutStdStream stream_ = PICoutManipulators::StdOut;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PICOUT_H
|
#endif // PICOUT_H
|
||||||
|
|||||||
@@ -763,7 +763,7 @@ void dumpApplication(bool with_objects) {
|
|||||||
|
|
||||||
bool dumpApplicationToFile(const PIString & path, bool with_objects) {
|
bool dumpApplicationToFile(const PIString & path, bool with_objects) {
|
||||||
PIFile f(path + "_tmp");
|
PIFile f(path + "_tmp");
|
||||||
f.setName("__S__DumpFile");
|
f.setName("_S.DumpFile");
|
||||||
f.clear();
|
f.clear();
|
||||||
if (!f.open(PIIODevice::WriteOnly)) return false;
|
if (!f.open(PIIODevice::WriteOnly)) return false;
|
||||||
auto out_devs = PICout::currentOutputDevices();
|
auto out_devs = PICout::currentOutputDevices();
|
||||||
|
|||||||
@@ -33,15 +33,11 @@ PRIVATE_DEFINITION_END(PIIntrospectionServer)
|
|||||||
|
|
||||||
PIIntrospectionServer::PIIntrospectionServer(): PIPeer(genName()) {
|
PIIntrospectionServer::PIIntrospectionServer(): PIPeer(genName()) {
|
||||||
PRIVATE->process_info = PIIntrospection::getInfo();
|
PRIVATE->process_info = PIIntrospection::getInfo();
|
||||||
sysmon = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIIntrospectionServer::~PIIntrospectionServer() {
|
PIIntrospectionServer::~PIIntrospectionServer() {
|
||||||
PIPeer::stop();
|
// stop();
|
||||||
if (sysmon)
|
|
||||||
if (sysmon->property("__iserver__").toBool()) delete sysmon;
|
|
||||||
sysmon = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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() {
|
PIString PIIntrospectionServer::genName() {
|
||||||
randomize();
|
randomize();
|
||||||
return "__introspection__server_" + PIString::fromNumber(randomi() % 1000);
|
return "__introspection__server_" + PIString::fromNumber(randomi() % 1000);
|
||||||
@@ -102,7 +107,7 @@ void PIIntrospectionServer::dataReceived(const PIString & from, const PIByteArra
|
|||||||
|
|
||||||
void PIIntrospectionServer::sysmonDeleted() {
|
void PIIntrospectionServer::sysmonDeleted() {
|
||||||
PIMutexLocker _ml(sysmon_mutex);
|
PIMutexLocker _ml(sysmon_mutex);
|
||||||
sysmon = 0;
|
sysmon = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // PIP_INTROSPECTION
|
#endif // PIP_INTROSPECTION
|
||||||
|
|||||||
@@ -33,6 +33,11 @@
|
|||||||
//! \~russian Запускает сервер интроспекции с именем "name"
|
//! \~russian Запускает сервер интроспекции с именем "name"
|
||||||
# define PIINTROSPECTION_START(name)
|
# define PIINTROSPECTION_START(name)
|
||||||
|
|
||||||
|
//! \ingroup Introspection
|
||||||
|
//! \~english Stop introspection server
|
||||||
|
//! \~russian Останавливает сервер интроспекции
|
||||||
|
# define PIINTROSPECTION_STOP
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
# if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
# if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
||||||
@@ -44,6 +49,7 @@ class PISystemMonitor;
|
|||||||
|
|
||||||
# define PIINTROSPECTION_SERVER (PIIntrospectionServer::instance())
|
# define PIINTROSPECTION_SERVER (PIIntrospectionServer::instance())
|
||||||
# define PIINTROSPECTION_START(name) PIINTROSPECTION_SERVER->start(#name);
|
# define PIINTROSPECTION_START(name) PIINTROSPECTION_SERVER->start(#name);
|
||||||
|
# define PIINTROSPECTION_STOP PIINTROSPECTION_SERVER->stop();
|
||||||
|
|
||||||
class PIP_EXPORT PIIntrospectionServer: public PIPeer {
|
class PIP_EXPORT PIIntrospectionServer: public PIPeer {
|
||||||
PIOBJECT_SUBCLASS(PIIntrospectionServer, PIPeer);
|
PIOBJECT_SUBCLASS(PIIntrospectionServer, PIPeer);
|
||||||
@@ -52,6 +58,7 @@ public:
|
|||||||
static PIIntrospectionServer * instance();
|
static PIIntrospectionServer * instance();
|
||||||
|
|
||||||
void start(const PIString & server_name);
|
void start(const PIString & server_name);
|
||||||
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PIIntrospectionServer();
|
PIIntrospectionServer();
|
||||||
@@ -59,17 +66,17 @@ private:
|
|||||||
NO_COPY_CLASS(PIIntrospectionServer);
|
NO_COPY_CLASS(PIIntrospectionServer);
|
||||||
|
|
||||||
PIString genName();
|
PIString genName();
|
||||||
virtual void dataReceived(const PIString & from, const PIByteArray & data);
|
void dataReceived(const PIString & from, const PIByteArray & data) override;
|
||||||
EVENT_HANDLER(void, sysmonDeleted);
|
EVENT_HANDLER(void, sysmonDeleted);
|
||||||
|
|
||||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||||
PITimer itimer;
|
PISystemMonitor * sysmon = nullptr;
|
||||||
PISystemMonitor * sysmon;
|
|
||||||
PIMutex sysmon_mutex;
|
PIMutex sysmon_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
# else
|
# else
|
||||||
# define PIINTROSPECTION_START(name)
|
# define PIINTROSPECTION_START(name)
|
||||||
|
# define PIINTROSPECTION_STOP
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif // DOXYGEN
|
#endif // DOXYGEN
|
||||||
|
|||||||
@@ -139,8 +139,10 @@ PIByteArray PIIntrospection::packThreads() {
|
|||||||
PIMap<PIThread *, PIIntrospectionThreads::ThreadInfo> & tm(p->threads);
|
PIMap<PIThread *, PIIntrospectionThreads::ThreadInfo> & tm(p->threads);
|
||||||
auto it = tm.makeIterator();
|
auto it = tm.makeIterator();
|
||||||
while (it.next()) {
|
while (it.next()) {
|
||||||
it.value().classname = PIStringAscii(it.key()->className());
|
if (it.key()->isPIObject()) {
|
||||||
it.value().name = it.key()->name();
|
it.value().classname = PIStringAscii(it.key()->className());
|
||||||
|
it.value().name = it.key()->name();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret << tm.values();
|
ret << tm.values();
|
||||||
p->mutex.unlock();
|
p->mutex.unlock();
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ PIBinaryLog::PIBinaryLog() {
|
|||||||
setLogDir(PIString());
|
setLogDir(PIString());
|
||||||
setFilePrefix(PIString());
|
setFilePrefix(PIString());
|
||||||
setRapidStart(false);
|
setRapidStart(false);
|
||||||
file.setName("__S__PIBinaryLog::file");
|
file.setName("_S.PIBinLog.file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -459,7 +459,7 @@ PIDir PIDir::current() {
|
|||||||
|
|
||||||
PIDir PIDir::home() {
|
PIDir PIDir::home() {
|
||||||
#ifndef ESP_PLATFORM
|
#ifndef ESP_PLATFORM
|
||||||
char * rc = 0;
|
char * rc = nullptr;
|
||||||
#endif
|
#endif
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
rc = new char[1024];
|
rc = new char[1024];
|
||||||
@@ -482,7 +482,7 @@ PIDir PIDir::home() {
|
|||||||
#else
|
#else
|
||||||
# ifndef ESP_PLATFORM
|
# ifndef ESP_PLATFORM
|
||||||
rc = getenv("HOME");
|
rc = getenv("HOME");
|
||||||
if (rc == 0) return PIDir();
|
if (!rc) return PIDir();
|
||||||
return PIDir(rc);
|
return PIDir(rc);
|
||||||
# else
|
# else
|
||||||
return PIDir();
|
return PIDir();
|
||||||
@@ -492,7 +492,7 @@ PIDir PIDir::home() {
|
|||||||
|
|
||||||
|
|
||||||
PIDir PIDir::temporary() {
|
PIDir PIDir::temporary() {
|
||||||
char * rc = 0;
|
char * rc = nullptr;
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
rc = new char[1024];
|
rc = new char[1024];
|
||||||
memset(rc, 0, 1024);
|
memset(rc, 0, 1024);
|
||||||
@@ -507,8 +507,9 @@ PIDir PIDir::temporary() {
|
|||||||
s.prepend(separator);
|
s.prepend(separator);
|
||||||
return PIDir(s);
|
return PIDir(s);
|
||||||
#else
|
#else
|
||||||
rc = tmpnam(0);
|
char template_rc[] = "/tmp/pidir_tmp_XXXXXX";
|
||||||
if (rc == 0) return PIDir();
|
rc = mkdtemp(template_rc);
|
||||||
|
if (!rc) return PIDir();
|
||||||
PIString s(rc);
|
PIString s(rc);
|
||||||
return PIDir(s.left(s.findLast(PIDir::separator)));
|
return PIDir(s.left(s.findLast(PIDir::separator)));
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ PRIVATE_DEFINITION_END(PIEthernet)
|
|||||||
|
|
||||||
PIEthernet::PIEthernet(): PIIODevice("", ReadWrite) {
|
PIEthernet::PIEthernet(): PIIODevice("", ReadWrite) {
|
||||||
construct();
|
construct();
|
||||||
setType(UDP);
|
eth_type = UDP;
|
||||||
|
setProperty("type", (int)UDP);
|
||||||
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop | PIEthernet::KeepConnection);
|
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) {
|
: PIIODevice(ip_port, ReadWrite) {
|
||||||
construct();
|
construct();
|
||||||
addr_r.set(ip_port);
|
addr_r.set(ip_port);
|
||||||
setType(type_);
|
eth_type = type_;
|
||||||
|
setProperty("type", (int)type_);
|
||||||
setParameters(params_);
|
setParameters(params_);
|
||||||
if (type_ != UDP) init();
|
if (type_ != UDP) init();
|
||||||
}
|
}
|
||||||
@@ -139,9 +141,11 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) {
|
|||||||
addr_s.set(ip_port);
|
addr_s.set(ip_port);
|
||||||
sock = sock_;
|
sock = sock_;
|
||||||
opened_ = connected_ = true;
|
opened_ = connected_ = true;
|
||||||
|
is_server_client = true;
|
||||||
|
eth_type = TCP_Client;
|
||||||
|
setProperty("type", (int)TCP_Client);
|
||||||
init();
|
init();
|
||||||
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop);
|
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop);
|
||||||
setType(TCP_Client, false);
|
|
||||||
setPath(ip_port);
|
setPath(ip_port);
|
||||||
ethNonblocking(sock);
|
ethNonblocking(sock);
|
||||||
PRIVATE->event.create();
|
PRIVATE->event.create();
|
||||||
@@ -161,14 +165,12 @@ PIEthernet::~PIEthernet() {
|
|||||||
void PIEthernet::construct() {
|
void PIEthernet::construct() {
|
||||||
// piCout << " PIEthernet" << uint(this);
|
// piCout << " PIEthernet" << uint(this);
|
||||||
setOption(BlockingWrite);
|
setOption(BlockingWrite);
|
||||||
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
|
||||||
sock = sock_s = -1;
|
|
||||||
setReadTimeout(10_s);
|
setReadTimeout(10_s);
|
||||||
setWriteTimeout(10_s);
|
setWriteTimeout(10_s);
|
||||||
setTTL(64);
|
setTTL(64);
|
||||||
setMulticastTTL(1);
|
setMulticastTTL(1);
|
||||||
server_thread_.setData(this);
|
server_thread_.setData(this);
|
||||||
server_thread_.setName("__S__server_thread"_a);
|
server_thread_.setName("_S.tcpserver"_a);
|
||||||
#ifdef MICRO_PIP
|
#ifdef MICRO_PIP
|
||||||
setThreadedReadBufferSize(512);
|
setThreadedReadBufferSize(512);
|
||||||
#else
|
#else
|
||||||
@@ -178,9 +180,9 @@ void PIEthernet::construct() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIEthernet::init() {
|
void PIEthernet::init() {
|
||||||
if (isOpened()) return true;
|
if (isOpened() || is_server_client) return;
|
||||||
if (sock != -1) return true;
|
if (sock != -1) return;
|
||||||
// piCout << "init " << type();
|
// piCout << "init " << type();
|
||||||
PRIVATE->event.destroy();
|
PRIVATE->event.destroy();
|
||||||
if (sock_s == sock) sock_s = -1;
|
if (sock_s == sock) sock_s = -1;
|
||||||
@@ -203,13 +205,13 @@ bool PIEthernet::init() {
|
|||||||
sock_s = sock;
|
sock_s = sock;
|
||||||
if (sock == -1 || sock_s == -1) {
|
if (sock == -1 || sock_s == -1) {
|
||||||
piCoutObj << "Can`t create socket," << ethErrorString();
|
piCoutObj << "Can`t create socket," << ethErrorString();
|
||||||
return false;
|
connected_ = connecting_ = opened_ = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
applyParameters();
|
applyParameters();
|
||||||
applyTimeouts();
|
applyTimeouts();
|
||||||
applyOptInt(IPPROTO_IP, IP_TTL, TTL());
|
applyOptInt(IPPROTO_IP, IP_TTL, TTL());
|
||||||
// piCoutObj << "inited" << path();
|
// piCoutObj << "inited" << path();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -303,18 +305,12 @@ bool PIEthernet::closeDevice() {
|
|||||||
// piCoutObj << "close";
|
// piCoutObj << "close";
|
||||||
bool ned = connected_;
|
bool ned = connected_;
|
||||||
connected_ = connecting_ = false;
|
connected_ = connecting_ = false;
|
||||||
server_thread_.stop();
|
stopThreadedListen();
|
||||||
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);
|
|
||||||
clients_mutex.lock();
|
clients_mutex.lock();
|
||||||
piDeleteAllAndClear(clients_);
|
auto cl = clients_;
|
||||||
|
clients_.clear();
|
||||||
clients_mutex.unlock();
|
clients_mutex.unlock();
|
||||||
|
piDeleteAll(cl);
|
||||||
if (ned) {
|
if (ned) {
|
||||||
// piCoutObj << "Disconnect on close";
|
// piCoutObj << "Disconnect on close";
|
||||||
disconnected(false);
|
disconnected(false);
|
||||||
@@ -528,16 +524,32 @@ bool PIEthernet::listen(const PINetworkAddress & addr, bool threaded) {
|
|||||||
return listen(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) {
|
PIEthernet * PIEthernet::client(int index) {
|
||||||
PIMutexLocker locker(clients_mutex);
|
PIMutexLocker locker(clients_mutex);
|
||||||
return clients_[index];
|
return clients_[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int PIEthernet::clientsCount() const {
|
int PIEthernet::clientsCount() const {
|
||||||
PIMutexLocker locker(clients_mutex);
|
PIMutexLocker locker(clients_mutex);
|
||||||
return clients_.size_s();
|
return clients_.size_s();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIVector<PIEthernet *> PIEthernet::clients() const {
|
PIVector<PIEthernet *> PIEthernet::clients() const {
|
||||||
PIMutexLocker locker(clients_mutex);
|
PIMutexLocker locker(clients_mutex);
|
||||||
return clients_;
|
return clients_;
|
||||||
@@ -777,6 +789,9 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
|||||||
closeSocket(sock);
|
closeSocket(sock);
|
||||||
init();
|
init();
|
||||||
disconnected(true);
|
disconnected(true);
|
||||||
|
if (params[KeepConnection]) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!isOptionSet(BlockingWrite)) {
|
if (!isOptionSet(BlockingWrite)) {
|
||||||
@@ -883,7 +898,7 @@ void PIEthernet::server_func(void * eth) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ce->debug()) piCout << "[PIEthernet] Can`t accept new connection," << ethErrorString();
|
if (ce->debug()) piCout << "[PIEthernet] Can`t accept new connection," << ethErrorString();
|
||||||
piMSleep(10);
|
piMSleep(50);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PIString ip = PIStringAscii(inet_ntoa(client_addr.sin_addr));
|
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
|
//! Start listen for incoming TCP connections on address "addr". Use only for TCP_Server
|
||||||
bool listen(const PINetworkAddress & addr, bool threaded = false);
|
bool listen(const PINetworkAddress & addr, bool threaded = false);
|
||||||
|
|
||||||
|
void stopThreadedListen();
|
||||||
|
|
||||||
PIEthernet * client(int index);
|
PIEthernet * client(int index);
|
||||||
int clientsCount() const;
|
int clientsCount() const;
|
||||||
PIVector<PIEthernet *> clients() const;
|
PIVector<PIEthernet *> clients() const;
|
||||||
@@ -470,7 +472,7 @@ protected:
|
|||||||
virtual void received(const void * data, int size) { ; }
|
virtual void received(const void * data, int size) { ; }
|
||||||
|
|
||||||
void construct();
|
void construct();
|
||||||
bool init();
|
void init();
|
||||||
bool openDevice() override;
|
bool openDevice() override;
|
||||||
bool closeDevice() override;
|
bool closeDevice() override;
|
||||||
void closeSocket(int & sd);
|
void closeSocket(int & sd);
|
||||||
@@ -479,8 +481,9 @@ protected:
|
|||||||
void applyOptInt(int level, int opt, int val);
|
void applyOptInt(int level, int opt, int val);
|
||||||
|
|
||||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||||
int sock, sock_s;
|
int sock = -1, sock_s = -1;
|
||||||
std::atomic_bool connected_, connecting_, listen_threaded, server_bounded;
|
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;
|
mutable PINetworkAddress addr_r, addr_s, addr_lr;
|
||||||
Type eth_type;
|
Type eth_type;
|
||||||
PIThread server_thread_;
|
PIThread server_thread_;
|
||||||
|
|||||||
@@ -337,8 +337,8 @@ void PIIODevice::_init() {
|
|||||||
#else
|
#else
|
||||||
threaded_read_buffer_size = 4_KiB;
|
threaded_read_buffer_size = 4_KiB;
|
||||||
#endif
|
#endif
|
||||||
read_thread.setName("__S__.PIIODevice.read_thread");
|
read_thread.setName("_S.PIIODev.read");
|
||||||
write_thread.setName("__S__.PIIODevice.write_thread");
|
write_thread.setName("_S.PIIODev.write");
|
||||||
CONNECT(void, &write_thread, started, this, write_func);
|
CONNECT(void, &write_thread, started, this, write_func);
|
||||||
CONNECTL(&read_thread, started, [this]() {
|
CONNECTL(&read_thread, started, [this]() {
|
||||||
if (!isOpened()) open();
|
if (!isOpened()) open();
|
||||||
@@ -384,9 +384,10 @@ void PIIODevice::read_func() {
|
|||||||
ok = open();
|
ok = open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ok) return;
|
if (!ok || read_thread.isStopping()) return;
|
||||||
}
|
}
|
||||||
ssize_t readed_ = read(buffer_tr.data(), buffer_tr.size_s());
|
ssize_t readed_ = read(buffer_tr.data(), buffer_tr.size_s());
|
||||||
|
if (read_thread.isStopping()) return;
|
||||||
if (readed_ <= 0) {
|
if (readed_ <= 0) {
|
||||||
piMSleep(10);
|
piMSleep(10);
|
||||||
// cout << readed_ << ", " << errno << ", " << errorString() << endl;
|
// cout << readed_ << ", " << errno << ", " << errorString() << endl;
|
||||||
|
|||||||
@@ -243,6 +243,10 @@ public:
|
|||||||
//! \~russian Возвращает запущен ли поток чтения
|
//! \~russian Возвращает запущен ли поток чтения
|
||||||
bool isThreadedRead() const;
|
bool isThreadedRead() const;
|
||||||
|
|
||||||
|
//! \~english Returns if threaded read is stopping
|
||||||
|
//! \~russian Возвращает останавливается ли поток чтения
|
||||||
|
bool isThreadedReadStopping() const { return read_thread.isStopping(); }
|
||||||
|
|
||||||
//! \~english Start threaded read
|
//! \~english Start threaded read
|
||||||
//! \~russian Запускает потоковое чтение
|
//! \~russian Запускает потоковое чтение
|
||||||
void startThreadedRead();
|
void startThreadedRead();
|
||||||
@@ -565,8 +569,6 @@ protected:
|
|||||||
|
|
||||||
static PIIODevice * newDeviceByPrefix(const char * prefix);
|
static PIIODevice * newDeviceByPrefix(const char * prefix);
|
||||||
|
|
||||||
bool isThreadedReadStopping() const { return read_thread.isStopping(); }
|
|
||||||
|
|
||||||
DeviceMode mode_ = ReadOnly;
|
DeviceMode mode_ = ReadOnly;
|
||||||
DeviceOptions options_;
|
DeviceOptions options_;
|
||||||
ReadRetFunc func_read = nullptr;
|
ReadRetFunc func_read = nullptr;
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ PIPeer::PIPeer(const PIString & n)
|
|||||||
, eth_tcp_cli(PIEthernet::TCP_Client)
|
, eth_tcp_cli(PIEthernet::TCP_Client)
|
||||||
, diag_s(false)
|
, diag_s(false)
|
||||||
, diag_d(false) {
|
, diag_d(false) {
|
||||||
sync_timer.setName("__S__.PIPeer.sync_timer");
|
sync_timer.setName("_S.PIPeer.sync");
|
||||||
// piCout << " PIPeer" << uint(this);
|
// piCout << " PIPeer" << uint(this);
|
||||||
destroyed = false;
|
destroyed = false;
|
||||||
setDebug(false);
|
setDebug(false);
|
||||||
@@ -201,33 +201,7 @@ PIPeer::~PIPeer() {
|
|||||||
stop();
|
stop();
|
||||||
if (destroyed) return;
|
if (destroyed) return;
|
||||||
destroyed = true;
|
destroyed = true;
|
||||||
sync_timer.stopAndWait();
|
destroy();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -255,7 +229,7 @@ void PIPeer::initEths(PIStringList al) {
|
|||||||
piForeachC(PIString & a, al) {
|
piForeachC(PIString & a, al) {
|
||||||
ce = new PIEthernet();
|
ce = new PIEthernet();
|
||||||
ce->setDebug(false);
|
ce->setDebug(false);
|
||||||
ce->setName("__S__PIPeer_traffic_eth_rec_" + a);
|
ce->setName("_S.PIPeer.traf_rec_" + a);
|
||||||
ce->setParameters(0);
|
ce->setParameters(0);
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
for (int p = _PIPEER_TRAFFIC_PORT_S; p < _PIPEER_TRAFFIC_PORT_E; ++p) {
|
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;
|
if (!ok) delete ce;
|
||||||
}
|
}
|
||||||
eth_send.setDebug(false);
|
eth_send.setDebug(false);
|
||||||
eth_send.setName("__S__PIPeer_traffic_eth_send");
|
eth_send.setName("_S.PIPeer.traf_send");
|
||||||
eth_send.setParameters(0);
|
eth_send.setParameters(0);
|
||||||
// piCoutObj << "initEths ok";
|
// piCoutObj << "initEths ok";
|
||||||
}
|
}
|
||||||
@@ -291,7 +265,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
|||||||
// piCout << "mcast try" << a;
|
// piCout << "mcast try" << a;
|
||||||
ce = new PIEthernet();
|
ce = new PIEthernet();
|
||||||
ce->setDebug(false);
|
ce->setDebug(false);
|
||||||
ce->setName("__S__PIPeer_mcast_eth_" + a);
|
ce->setName("_S.PIPeer.mcast_" + a);
|
||||||
ce->setParameters(0);
|
ce->setParameters(0);
|
||||||
ce->setSendAddress(_PIPEER_MULTICAST_IP, _PIPEER_MULTICAST_PORT);
|
ce->setSendAddress(_PIPEER_MULTICAST_IP, _PIPEER_MULTICAST_PORT);
|
||||||
ce->setReadAddress(a, _PIPEER_MULTICAST_PORT);
|
ce->setReadAddress(a, _PIPEER_MULTICAST_PORT);
|
||||||
@@ -311,7 +285,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
|||||||
piForeachC(PIString & a, al) {
|
piForeachC(PIString & a, al) {
|
||||||
ce = new PIEthernet();
|
ce = new PIEthernet();
|
||||||
ce->setDebug(false);
|
ce->setDebug(false);
|
||||||
ce->setName("__S__PIPeer_bcast_eth_" + a);
|
ce->setName("_S.PIPeer.bcast_" + a);
|
||||||
ce->setParameters(PIEthernet::Broadcast);
|
ce->setParameters(PIEthernet::Broadcast);
|
||||||
cint = prev_ifaces.getByAddress(a);
|
cint = prev_ifaces.getByAddress(a);
|
||||||
nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
|
nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
|
||||||
@@ -328,7 +302,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
|||||||
// piCoutObj << "invalid address for bcast" << a;
|
// 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.setParameters(PIEthernet::SeparateSockets);
|
||||||
eth_lo.init();
|
eth_lo.init();
|
||||||
cint = prev_ifaces.getByAddress("127.0.0.1");
|
cint = prev_ifaces.getByAddress("127.0.0.1");
|
||||||
@@ -343,13 +317,13 @@ void PIPeer::initMBcasts(PIStringList al) {
|
|||||||
break;
|
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.init();
|
||||||
eth_tcp_srv.listen("0.0.0.0", _PIPEER_TCP_PORT, true);
|
eth_tcp_srv.listen("0.0.0.0", _PIPEER_TCP_PORT, true);
|
||||||
eth_tcp_srv.setDebug(false);
|
eth_tcp_srv.setDebug(false);
|
||||||
CONNECT1(void, PIEthernet *, ð_tcp_srv, newConnection, this, newTcpClient);
|
CONNECT1(void, PIEthernet *, ð_tcp_srv, newConnection, this, newTcpClient);
|
||||||
eth_tcp_srv.startThreadedRead();
|
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.init();
|
||||||
eth_tcp_cli.setDebug(false);
|
eth_tcp_cli.setDebug(false);
|
||||||
tcpClientReconnect();
|
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() {
|
void PIPeer::destroyEths() {
|
||||||
for (auto * i: eths_traffic) {
|
for (auto * i: eths_traffic) {
|
||||||
if (!i) continue;
|
if (!i) continue;
|
||||||
@@ -930,6 +940,7 @@ ssize_t PIPeer::bytesAvailable() const {
|
|||||||
|
|
||||||
|
|
||||||
ssize_t PIPeer::readDevice(void * read_to, ssize_t max_size) {
|
ssize_t PIPeer::readDevice(void * read_to, ssize_t max_size) {
|
||||||
|
iterrupted = false;
|
||||||
read_buffer_mutex.lock();
|
read_buffer_mutex.lock();
|
||||||
bool empty = read_buffer.isEmpty();
|
bool empty = read_buffer.isEmpty();
|
||||||
read_buffer_mutex.unlock();
|
read_buffer_mutex.unlock();
|
||||||
@@ -937,6 +948,9 @@ ssize_t PIPeer::readDevice(void * read_to, ssize_t max_size) {
|
|||||||
read_buffer_mutex.lock();
|
read_buffer_mutex.lock();
|
||||||
empty = read_buffer.isEmpty();
|
empty = read_buffer.isEmpty();
|
||||||
read_buffer_mutex.unlock();
|
read_buffer_mutex.unlock();
|
||||||
|
if (iterrupted) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
piMSleep(10);
|
piMSleep(10);
|
||||||
}
|
}
|
||||||
read_buffer_mutex.lock();
|
read_buffer_mutex.lock();
|
||||||
@@ -945,6 +959,9 @@ ssize_t PIPeer::readDevice(void * read_to, ssize_t max_size) {
|
|||||||
read_buffer_mutex.unlock();
|
read_buffer_mutex.unlock();
|
||||||
ssize_t sz = piMini(ba.size_s(), max_size);
|
ssize_t sz = piMini(ba.size_s(), max_size);
|
||||||
memcpy(read_to, ba.data(), sz);
|
memcpy(read_to, ba.data(), sz);
|
||||||
|
if (iterrupted) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
read_buffer_mutex.unlock();
|
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) {
|
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();
|
piCoutObj << "client" << client->path();
|
||||||
CONNECT2(void, const uchar *, ssize_t, client, threadedReadEvent, this, mbcastRead);
|
CONNECT2(void, const uchar *, ssize_t, client, threadedReadEvent, this, mbcastRead);
|
||||||
client->startThreadedRead();
|
client->startThreadedRead();
|
||||||
|
|||||||
@@ -171,6 +171,8 @@ protected:
|
|||||||
EVENT_HANDLER2(bool, dataRead, const uchar *, readed, ssize_t, size);
|
EVENT_HANDLER2(bool, dataRead, const uchar *, readed, ssize_t, size);
|
||||||
EVENT_HANDLER2(bool, mbcastRead, const uchar *, readed, ssize_t, size);
|
EVENT_HANDLER2(bool, mbcastRead, const uchar *, readed, ssize_t, size);
|
||||||
|
|
||||||
|
void destroy();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EVENT_HANDLER1(void, timerEvent, int, delim);
|
EVENT_HANDLER1(void, timerEvent, int, delim);
|
||||||
EVENT_HANDLER2(bool, sendInternal, const PIString &, to, const PIByteArray &, data);
|
EVENT_HANDLER2(bool, sendInternal, const PIString &, to, const PIByteArray &, data);
|
||||||
@@ -212,6 +214,7 @@ private:
|
|||||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||||
ssize_t writeDevice(const void * data, ssize_t size) override;
|
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||||
|
void interrupt() override;
|
||||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
||||||
|
|
||||||
PeerInfo * quickestPeer(const PIString & to);
|
PeerInfo * quickestPeer(const PIString & to);
|
||||||
@@ -243,6 +246,7 @@ private:
|
|||||||
mutable PIMutex read_buffer_mutex;
|
mutable PIMutex read_buffer_mutex;
|
||||||
PIQueue<PIByteArray> read_buffer;
|
PIQueue<PIByteArray> read_buffer;
|
||||||
int read_buffer_size;
|
int read_buffer_size;
|
||||||
|
std::atomic_bool iterrupted = {false};
|
||||||
PIMutex mc_mutex, eth_mutex, peers_mutex, send_mutex, send_mc_mutex;
|
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->started = false;
|
||||||
}
|
}
|
||||||
dd->rthread = new PIThread(dd, __DevicePool_threadReadDP);
|
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;
|
need_start = true;
|
||||||
pmode |= PIIODevice::ReadOnly;
|
pmode |= PIIODevice::ReadOnly;
|
||||||
}
|
}
|
||||||
@@ -1211,7 +1211,7 @@ PIConnection::Extractor::~Extractor() {
|
|||||||
|
|
||||||
|
|
||||||
PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_) {
|
PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_) {
|
||||||
setName("__S__.PIConnection.Sender");
|
setName("_S.PIConn.Sender");
|
||||||
needLockRun(true);
|
needLockRun(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#ifndef PIP_H
|
#ifndef PIP_H
|
||||||
#define PIP_H
|
#define PIP_H
|
||||||
|
|
||||||
|
#include "piapplicationmodule.h"
|
||||||
#include "picloudmodule.h"
|
#include "picloudmodule.h"
|
||||||
#include "piconsolemodule.h"
|
#include "piconsolemodule.h"
|
||||||
#include "picontainersmodule.h"
|
#include "picontainersmodule.h"
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public:
|
|||||||
bool binaryStreamAppend(const void * d, size_t s) {
|
bool binaryStreamAppend(const void * d, size_t s) {
|
||||||
if (!static_cast<P *>(this)->binaryStreamAppendImp(d, s)) {
|
if (!static_cast<P *>(this)->binaryStreamAppendImp(d, s)) {
|
||||||
return false;
|
return false;
|
||||||
printf("[PIBinaryStream] binaryStreamAppend() error\n");
|
fprintf(stderr, "[PIBinaryStream] binaryStreamAppend() error\n");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ public:
|
|||||||
if (!static_cast<P *>(this)->binaryStreamTakeImp(d, s)) {
|
if (!static_cast<P *>(this)->binaryStreamTakeImp(d, s)) {
|
||||||
_was_read_error_ = true;
|
_was_read_error_ = true;
|
||||||
return false;
|
return false;
|
||||||
printf("[PIBinaryStream] binaryStreamTake() error\n");
|
fprintf(stderr, "[PIBinaryStream] binaryStreamTake() error\n");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -323,7 +323,7 @@ template<typename P,
|
|||||||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0>
|
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
inline PIBinaryStreamTrivialRef<P> operator>>(PIBinaryStream<P> & s, T & v) {
|
inline PIBinaryStreamTrivialRef<P> operator>>(PIBinaryStream<P> & s, T & v) {
|
||||||
if (!s.binaryStreamTake(&v, sizeof(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;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -341,13 +341,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
|||||||
// piCout << ">> vector trivial default";
|
// piCout << ">> vector trivial default";
|
||||||
int sz = s.binaryStreamTakeInt();
|
int sz = s.binaryStreamTakeInt();
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
v._resizeRaw(sz);
|
v._resizeRaw(sz);
|
||||||
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
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();
|
v.clear();
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
@@ -362,7 +362,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
|||||||
// piCout << ">> vector trivial custom";
|
// piCout << ">> vector trivial custom";
|
||||||
int sz = s.binaryStreamTakeInt();
|
int sz = s.binaryStreamTakeInt();
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -370,7 +370,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
|||||||
for (int i = 0; i < sz; ++i) {
|
for (int i = 0; i < sz; ++i) {
|
||||||
s >> v[i];
|
s >> v[i];
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -391,13 +391,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
|||||||
// piCout << ">> deque trivial default";
|
// piCout << ">> deque trivial default";
|
||||||
int sz = s.binaryStreamTakeInt();
|
int sz = s.binaryStreamTakeInt();
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
v._resizeRaw(sz);
|
v._resizeRaw(sz);
|
||||||
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
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();
|
v.clear();
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
@@ -412,7 +412,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
|||||||
// piCout << ">> deque trivial custom";
|
// piCout << ">> deque trivial custom";
|
||||||
int sz = s.binaryStreamTakeInt();
|
int sz = s.binaryStreamTakeInt();
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -420,7 +420,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
|||||||
for (int i = 0; i < sz; ++i) {
|
for (int i = 0; i < sz; ++i) {
|
||||||
s >> v[i];
|
s >> v[i];
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -443,13 +443,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
|||||||
r = s.binaryStreamTakeInt();
|
r = s.binaryStreamTakeInt();
|
||||||
c = s.binaryStreamTakeInt();
|
c = s.binaryStreamTakeInt();
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
v._resizeRaw(r, c);
|
v._resizeRaw(r, c);
|
||||||
if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) {
|
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();
|
v.clear();
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
@@ -468,7 +468,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
|||||||
c = s.binaryStreamTakeInt();
|
c = s.binaryStreamTakeInt();
|
||||||
s >> tmp;
|
s >> tmp;
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
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) {
|
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||||
int sz = s.binaryStreamTakeInt();
|
int sz = s.binaryStreamTakeInt();
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
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) {
|
for (size_t i = 0; i < v.size(); ++i) {
|
||||||
s >> v[i];
|
s >> v[i];
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
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) {
|
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||||
int sz = s.binaryStreamTakeInt();
|
int sz = s.binaryStreamTakeInt();
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
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) {
|
for (size_t i = 0; i < v.size(); ++i) {
|
||||||
s >> v[i];
|
s >> v[i];
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -593,7 +593,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
|||||||
c = s.binaryStreamTakeInt();
|
c = s.binaryStreamTakeInt();
|
||||||
s >> tmp;
|
s >> tmp;
|
||||||
if (s.wasReadError()) {
|
if (s.wasReadError()) {
|
||||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||||
v.clear();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -625,7 +625,7 @@ template<typename P, typename Key, typename T>
|
|||||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
|
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
|
||||||
int sz = s.binaryStreamTakeInt();
|
int sz = s.binaryStreamTakeInt();
|
||||||
if (s.wasReadError()) {
|
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();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -635,7 +635,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v)
|
|||||||
ind = s.binaryStreamTakeInt();
|
ind = s.binaryStreamTakeInt();
|
||||||
s >> v.pim_index[i].key;
|
s >> v.pim_index[i].key;
|
||||||
if (s.wasReadError()) {
|
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();
|
v.clear();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -643,7 +643,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v)
|
|||||||
}
|
}
|
||||||
s >> v.pim_content;
|
s >> v.pim_content;
|
||||||
if (s.wasReadError()) {
|
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();
|
v.clear();
|
||||||
return s;
|
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) {
|
void PISignals::raiseSignal(PISignals::Signal signal) {
|
||||||
raise(signalCode(signal));
|
raise(signalCode(signal));
|
||||||
}
|
}
|
||||||
@@ -90,7 +117,7 @@ int PISignals::signalCode(PISignals::Signal signal) {
|
|||||||
case PISignals::StopTTYInput: return SIGTTIN;
|
case PISignals::StopTTYInput: return SIGTTIN;
|
||||||
case PISignals::StopTTYOutput: return SIGTTOU;
|
case PISignals::StopTTYOutput: return SIGTTOU;
|
||||||
#endif
|
#endif
|
||||||
default:;
|
default: break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -121,13 +148,13 @@ PISignals::Signal PISignals::signalFromCode(int signal) {
|
|||||||
case SIGTTIN: return PISignals::StopTTYInput;
|
case SIGTTIN: return PISignals::StopTTYInput;
|
||||||
case SIGTTOU: return PISignals::StopTTYOutput;
|
case SIGTTOU: return PISignals::StopTTYOutput;
|
||||||
#endif
|
#endif
|
||||||
default:;
|
default: break;
|
||||||
}
|
}
|
||||||
return PISignals::Termination;
|
return PISignals::Termination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PISignals::signal_event(int signal) {
|
void PISignals::signal_event(int signal) {
|
||||||
if (PISignals::ret_func == 0) return;
|
if (!PISignals::ret_func) return;
|
||||||
PISignals::ret_func(PISignals::signalFromCode(signal));
|
PISignals::ret_func(PISignals::signalFromCode(signal));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ public:
|
|||||||
// slot is any function format "void(PISignals::Signal)"
|
// slot is any function format "void(PISignals::Signal)"
|
||||||
static void setSlot(SignalEvent slot) { ret_func = slot; }
|
static void setSlot(SignalEvent slot) { ret_func = slot; }
|
||||||
static void grabSignals(PIFlags<PISignals::Signal> signals_);
|
static void grabSignals(PIFlags<PISignals::Signal> signals_);
|
||||||
|
static void releaseSignals(PIFlags<PISignals::Signal> signals_);
|
||||||
static void raiseSignal(PISignals::Signal signal);
|
static void raiseSignal(PISignals::Signal signal);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -54,10 +54,10 @@
|
|||||||
#define PISYSTEMMODULE_H
|
#define PISYSTEMMODULE_H
|
||||||
|
|
||||||
#include "pilibrary.h"
|
#include "pilibrary.h"
|
||||||
|
#include "piplugin.h"
|
||||||
|
#include "piprocess.h"
|
||||||
#include "pisignals.h"
|
#include "pisignals.h"
|
||||||
#include "pisingleapplication.h"
|
|
||||||
#include "pisysteminfo.h"
|
#include "pisysteminfo.h"
|
||||||
#include "pisystemmonitor.h"
|
|
||||||
#include "pisystemtests.h"
|
#include "pisystemtests.h"
|
||||||
|
|
||||||
#endif // PISYSTEMMODULE_H
|
#endif // PISYSTEMMODULE_H
|
||||||
|
|||||||
@@ -568,6 +568,7 @@ PIThread::PIThread(bool startNow, PISystemTime loop_delay): PIObject() {
|
|||||||
PIThread::~PIThread() {
|
PIThread::~PIThread() {
|
||||||
PIINTROSPECTION_THREAD_DELETE(this);
|
PIINTROSPECTION_THREAD_DELETE(this);
|
||||||
if (!running_ || PRIVATE->thread == 0) return;
|
if (!running_ || PRIVATE->thread == 0) return;
|
||||||
|
piCout << "[PIThread \"" << name() << "\"] Warning, terminate on destructor!";
|
||||||
#ifdef FREERTOS
|
#ifdef FREERTOS
|
||||||
// void * ret(0);
|
// void * ret(0);
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
|
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
|
||||||
@@ -587,6 +588,8 @@ PIThread::~PIThread() {
|
|||||||
CloseHandle(PRIVATE->thread);
|
CloseHandle(PRIVATE->thread);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
UNREGISTER_THREAD(this);
|
||||||
|
PIINTROSPECTION_THREAD_STOP(this);
|
||||||
terminating = running_ = false;
|
terminating = running_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -916,6 +919,10 @@ void PIThread::_runThread() {
|
|||||||
|
|
||||||
|
|
||||||
void PIThread::_endThread() {
|
void PIThread::_endThread() {
|
||||||
|
PIScopeExitCall ec([this] {
|
||||||
|
terminating = running_ = false;
|
||||||
|
tid_ = -1;
|
||||||
|
});
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
|
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
|
||||||
stopped();
|
stopped();
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
||||||
@@ -924,14 +931,13 @@ void PIThread::_endThread() {
|
|||||||
end();
|
end();
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
||||||
if (lockRun) thread_mutex.unlock();
|
if (lockRun) thread_mutex.unlock();
|
||||||
terminating = running_ = false;
|
|
||||||
tid_ = -1;
|
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
|
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
|
||||||
// cout << "thread " << t << " exiting ... " << endl;
|
// cout << "thread " << t << " exiting ... " << endl;
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "pthread_exit" << (__privateinitializer__.p)->thread;
|
// PICout(PICoutManipulators::DefaultControls) << "pthread_exit" << (__privateinitializer__.p)->thread;
|
||||||
UNREGISTER_THREAD(this);
|
UNREGISTER_THREAD(this);
|
||||||
PIINTROSPECTION_THREAD_STOP(this);
|
PIINTROSPECTION_THREAD_STOP(this);
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
ec.callAndCancel();
|
||||||
# ifdef CC_GCC
|
# ifdef CC_GCC
|
||||||
_endthreadex(0);
|
_endthreadex(0);
|
||||||
# else
|
# else
|
||||||
@@ -940,7 +946,7 @@ void PIThread::_endThread() {
|
|||||||
#elif defined(FREERTOS)
|
#elif defined(FREERTOS)
|
||||||
PRIVATE->thread = 0;
|
PRIVATE->thread = 0;
|
||||||
#else
|
#else
|
||||||
pthread_detach(PRIVATE->thread);
|
// pthread_detach(PRIVATE->thread);
|
||||||
PRIVATE->thread = 0;
|
PRIVATE->thread = 0;
|
||||||
pthread_exit(0);
|
pthread_exit(0);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -72,9 +72,9 @@
|
|||||||
//! w->startOnce();
|
//! w->startOnce();
|
||||||
//!
|
//!
|
||||||
//! piMSleep(500);
|
//! piMSleep(500);
|
||||||
//! notifier.notifyOnce(); // notify one of them after 500 ms
|
//! notifier.notify(); // notify one of them after 500 ms
|
||||||
//! piMSleep(500);
|
//! piMSleep(500);
|
||||||
//! notifier.notifyOnce(); // notify one of them after 1000 ms
|
//! notifier.notify(); // notify one of them after 1000 ms
|
||||||
//!
|
//!
|
||||||
//! for (auto * w: workers)
|
//! for (auto * w: workers)
|
||||||
//! w->waitForFinish();
|
//! w->waitForFinish();
|
||||||
@@ -93,17 +93,17 @@ PIThreadNotifier::PIThreadNotifier(): cnt(0) {}
|
|||||||
|
|
||||||
//! \~\details
|
//! \~\details
|
||||||
//! \~english
|
//! \~english
|
||||||
//! If \a notifyOnce() has been called before, then returns immediately.\n
|
//! If \a notify() 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 "n" times, then returns immediately "n" times,
|
||||||
//! but only if wait in one thread.\n
|
//! 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.
|
//! all threads total returns "n" times in undefined sequence.
|
||||||
//!
|
//!
|
||||||
//! \~russian
|
//! \~russian
|
||||||
//! Если ранее был вызван \a notifyOnce(), то возвращает управление немедленно.\n
|
//! Если ранее был вызван \a notify(), то возвращает управление немедленно.\n
|
||||||
//! Если ранее был вызван \a notifyOnce() "n" раз, то возвращает управление немедленно "n" раз,
|
//! Если ранее был вызван \a notify() "n" раз, то возвращает управление немедленно "n" раз,
|
||||||
//! но только если ожидать одним потоком.\n
|
//! но только если ожидать одним потоком.\n
|
||||||
//! Если ожидают несколько потоков, и \a notifyOnce() был вызван "n" раз,
|
//! Если ожидают несколько потоков, и \a notify() был вызван "n" раз,
|
||||||
//! то все потоки суммарно вернут управление "n" раз в неопределенной последовательности.
|
//! то все потоки суммарно вернут управление "n" раз в неопределенной последовательности.
|
||||||
//!
|
//!
|
||||||
void PIThreadNotifier::wait() {
|
void PIThreadNotifier::wait() {
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ class PIP_EXPORT PIThreadNotifier {
|
|||||||
public:
|
public:
|
||||||
PIThreadNotifier();
|
PIThreadNotifier();
|
||||||
|
|
||||||
//! \~english Start waiting, return if other thread call \a notifyOnce()
|
//! \~english Start waiting, return if other thread call \a notify()
|
||||||
//! \~russian Начать ожидание, продолжает когда другой поток вызовет \a notifyOnce()
|
//! \~russian Начать ожидание, продолжает когда другой поток вызовет \a notify()
|
||||||
void wait();
|
void wait();
|
||||||
|
|
||||||
//! \~english Notify one waiting thread, which waiting on \a wait() function
|
//! \~english Notify one waiting thread, which waiting on \a wait() function
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ bool PITimer::waitForFinish(PISystemTime timeout) {
|
|||||||
|
|
||||||
void PITimer::initFirst() {
|
void PITimer::initFirst() {
|
||||||
thread = new PIThread([this] { threadFunc(); });
|
thread = new PIThread([this] { threadFunc(); });
|
||||||
thread->setName("__S__.PITimer.thread");
|
thread->setName("_S.PITimer.thread");
|
||||||
setProperty("interval", PISystemTime());
|
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 {
|
PIString PISystemTime::toString() const {
|
||||||
static const PISystemTime is_abs_thr = 3650._d; // 10 years
|
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");
|
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 структуре
|
//! \~russian На *nix системах присваивает время к timespec структуре
|
||||||
void toTimespec(void * ts);
|
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
|
//! \~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> ..." для относительного
|
//! \~russian Возвращает "yyyy-MM-dd hh:mm:ss.zzz" для абсолютного времени и "<V> <d|h|m|s|ms|us|ns> ..." для относительного
|
||||||
PIString toString() const;
|
PIString toString() const;
|
||||||
|
|||||||
152
main.cpp
152
main.cpp
@@ -1,7 +1,11 @@
|
|||||||
#include "pibytearray.h"
|
#include "pibytearray.h"
|
||||||
|
#include "piclientserver_client.h"
|
||||||
|
#include "piclientserver_server.h"
|
||||||
#include "picodeparser.h"
|
#include "picodeparser.h"
|
||||||
|
#include "piintrospection_server.h"
|
||||||
#include "piiostream.h"
|
#include "piiostream.h"
|
||||||
#include "pijson.h"
|
#include "pijson.h"
|
||||||
|
#include "pilog.h"
|
||||||
#include "pimathbase.h"
|
#include "pimathbase.h"
|
||||||
#include "pip.h"
|
#include "pip.h"
|
||||||
#include "pivaluetree_conversions.h"
|
#include "pivaluetree_conversions.h"
|
||||||
@@ -16,22 +20,146 @@ enum MyEvent {
|
|||||||
meIntString,
|
meIntString,
|
||||||
};
|
};
|
||||||
|
|
||||||
PITimeMeasurer tm;
|
PIKbdListener kbd;
|
||||||
std::atomic_int cnt = {0};
|
|
||||||
void tfunc(int delim) {
|
|
||||||
// piCout << "tick with delimiter" << delim;
|
class MyServerClient: public PIClientServer::ServerClient {
|
||||||
++cnt;
|
public:
|
||||||
};
|
~MyServerClient() { send_thread.stopAndWait(); }
|
||||||
void tfunc4(int delim) {
|
|
||||||
piCout << "tick4 with delimiter" << delim;
|
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[]) {
|
int main(int argc, char * argv[]) {
|
||||||
uint v = 0xaabbccdd;
|
PILog log;
|
||||||
piCout << Hex << v << piChangedEndian(v);
|
log.setColorConsole(false);
|
||||||
piChangeEndianBinary(&v, sizeof(v));
|
log.setOutput(PILog::File, false);
|
||||||
piCout << Hex << v << piChangedEndian(v);
|
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;
|
return 0;
|
||||||
/*PIPackedTCP * tcp_s =
|
/*PIPackedTCP * tcp_s =
|
||||||
PIIODevice::createFromFullPath("ptcp://s::8000")->cast<PIPackedTCP>(); // new PIPackedTCP(PIPackedTCP::Server, {"0.0.0.0:8000"});
|
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(math)
|
||||||
pip_test(core)
|
pip_test(core)
|
||||||
pip_test(piobject)
|
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) {
|
TEST(PiobjectConnections, CONNECT0) {
|
||||||
Object a;
|
Object a;
|
||||||
Object b;
|
Object b;
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
CONNECT0(void, &a, event_test, &b, handler_test);
|
CONNECT0(void, &a, event_test, &b, handler_test);
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
// piCout << "================";
|
// piCout << "================";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,105 +57,105 @@ TEST(PiobjectConnections, CONNECT0_DISCONNECT) {
|
|||||||
Object b;
|
Object b;
|
||||||
a.setName("A");
|
a.setName("A");
|
||||||
b.setName("B");
|
b.setName("B");
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
CONNECT0(void, &a, event_test, &b, handler_test);
|
CONNECT0(void, &a, event_test, &b, handler_test);
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
PIObject::piDisconnect(&a, "event_test");
|
PIObject::piDisconnect(&a, "event_test");
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
// piCout << "================";
|
// piCout << "================";
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PiobjectConnections, CONNECTU) {
|
TEST(PiobjectConnections, CONNECTU) {
|
||||||
Object a;
|
Object a;
|
||||||
Object b;
|
Object b;
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
CONNECTU(&a, event_test, &b, handler_test);
|
CONNECTU(&a, event_test, &b, handler_test);
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
// piCout << "================";
|
// piCout << "================";
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PiobjectConnections, CONNECTU_DISCONNECT) {
|
TEST(PiobjectConnections, CONNECTU_DISCONNECT) {
|
||||||
Object a;
|
Object a;
|
||||||
Object b;
|
Object b;
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
CONNECTU(&a, event_test, &b, handler_test);
|
CONNECTU(&a, event_test, &b, handler_test);
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 0);
|
EXPECT_EQ(b.getX(), 0);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
PIObject::piDisconnect(&a, "event_test");
|
PIObject::piDisconnect(&a, "event_test");
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
a.test();
|
a.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
b.test();
|
b.test();
|
||||||
ASSERT_EQ(a.getX(), 0);
|
EXPECT_EQ(a.getX(), 0);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
a.handler_val(99);
|
a.handler_val(99);
|
||||||
ASSERT_EQ(a.getX(), 99);
|
EXPECT_EQ(a.getX(), 99);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
CONNECTU(&a, event_val, &b, handler_val);
|
CONNECTU(&a, event_val, &b, handler_val);
|
||||||
ASSERT_EQ(a.getX(), 99);
|
EXPECT_EQ(a.getX(), 99);
|
||||||
ASSERT_EQ(b.getX(), 1);
|
EXPECT_EQ(b.getX(), 1);
|
||||||
a.test_val();
|
a.test_val();
|
||||||
ASSERT_EQ(a.getX(), 99);
|
EXPECT_EQ(a.getX(), 99);
|
||||||
ASSERT_EQ(b.getX(), 99);
|
EXPECT_EQ(b.getX(), 99);
|
||||||
a.handler_val(-1);
|
a.handler_val(-1);
|
||||||
ASSERT_EQ(a.getX(), -1);
|
EXPECT_EQ(a.getX(), -1);
|
||||||
ASSERT_EQ(b.getX(), 99);
|
EXPECT_EQ(b.getX(), 99);
|
||||||
PIObject::piDisconnect(&a, "event_val", &b);
|
PIObject::piDisconnect(&a, "event_val", &b);
|
||||||
ASSERT_EQ(a.getX(), -1);
|
EXPECT_EQ(a.getX(), -1);
|
||||||
ASSERT_EQ(b.getX(), 99);
|
EXPECT_EQ(b.getX(), 99);
|
||||||
a.test_val();
|
a.test_val();
|
||||||
ASSERT_EQ(a.getX(), -1);
|
EXPECT_EQ(a.getX(), -1);
|
||||||
ASSERT_EQ(b.getX(), 99);
|
EXPECT_EQ(b.getX(), 99);
|
||||||
// piCout << "================";
|
// 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)) {
|
Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_" + PIString::fromNumber(randomi() % 100)) {
|
||||||
// setName("Daemon");
|
// setName("Daemon");
|
||||||
dtimer.setName("__S__Daemon_timer");
|
dtimer.setName("_S.Daemon.timer");
|
||||||
mode = rmNone;
|
mode = rmNone;
|
||||||
offset = cur = height = 0;
|
offset = cur = height = 0;
|
||||||
CONNECTU(screen, keyPressed, this, keyEvent)
|
CONNECTU(screen, keyPressed, this, keyEvent)
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ int main(int argc, char * argv[]) {
|
|||||||
MainMenu * menu = new MainMenu(*daemon);
|
MainMenu * menu = new MainMenu(*daemon);
|
||||||
if (sapp) CONNECTU(sapp, messageReceived, menu, messageFromApp);
|
if (sapp) CONNECTU(sapp, messageReceived, menu, messageFromApp);
|
||||||
if (cli.hasArgument("silent")) {
|
if (cli.hasArgument("silent")) {
|
||||||
PICout::setOutputDevices(PICout::StdOut);
|
PICout::setOutputDevices(PICout::Console);
|
||||||
PIKbdListener ls;
|
PIKbdListener ls;
|
||||||
ls.enableExitCapture(PIKbdListener::F10);
|
ls.enableExitCapture(PIKbdListener::F10);
|
||||||
ls.start();
|
ls.start();
|
||||||
|
|||||||
Reference in New Issue
Block a user