Files
pip/utils/system_daemon/main.cpp
peri4 caa7880cc4 get rid of piForeach
apply some code analyzer recommendations
ICU flag now check if libicu exists
prepare for more accurate growth of containers (limited PoT, then constantly increase size)
2024-11-20 20:01:47 +03:00

441 lines
16 KiB
C++
Executable File

/*
PIP - Platform Independent Primitives
PIP System Daemon
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/>.
*/
#include "daemon.h"
#include "file_manager.h"
#include "picli.h"
#include "piintrospection_server.h"
#include "piliterals_time.h"
#include "piprocess.h"
#include "pisingleapplication.h"
#include "pisysteminfo.h"
#include "pisystemmonitor.h"
#include "shared.h"
STATIC_INITIALIZER_BEGIN
randomize();
STATIC_INITIALIZER_END
PISystemMonitor sys_mon;
PIScreen * screen = nullptr;
class MainMenu: public PITimer {
PIOBJECT_SUBCLASS(MainMenu, PITimer)
public:
MainMenu(Daemon & d): daemon_(d) {
cur_peer = -1;
title = new TileSimple("title");
updateTitle(title);
title->back_format.color_back = Yellow;
title->size_policy = Fixed;
screen->rootTile()->addTile(title);
PIScreenTile * center = new PIScreenTile("center");
center->back_format.color_back = Cyan;
center->size_policy = Expanding;
center->setMargins(2, 2, 1, 1);
screen->rootTile()->addTile(center);
PIScreenTile * mt = tmenu = menuTile();
mt->show();
mt->name() = "main menu";
center->addTile(mt);
mtiles << mt;
mt = tinfo = infoTile();
mt->hide();
mt->name() = "local info";
center->addTile(mt);
mtiles << mt;
mt = tdaemon = daemon_.tile();
mt->hide();
mt->name() = "daemon";
center->addTile(mt);
mtiles << mt;
mt = tpeer = peerTile();
mt->hide();
mt->name() = "peer info";
center->addTile(mt);
mtiles << mt;
mt = tpeerdiag = peerDiagTile();
mt->hide();
mt->name() = "peer diag";
center->addTile(mt);
mtiles << mt;
tpicout = new TilePICout();
tpicout->hide();
tpicout->size_policy = PIScreenTypes::Expanding;
screen->rootTile()->addTile(tpicout);
CONNECTU(screen, tileEvent, this, tileEvent)
CONNECTU(screen, keyPressed, this, keyEvent)
CONNECTU(&daemon_, menuRequest, this, menuRequest)
start(40_Hz);
}
PIScreenTile * menuTile() {
TileList * ret = new TileList();
ret->content << TileList::Row("Show local info", CellFormat());
ret->content << TileList::Row("Local file manager", CellFormat());
ret->content << TileList::Row("Connect to another daemon", CellFormat());
ret->content << TileList::Row("Peer info", CellFormat());
ret->content << TileList::Row("Peer reinit", CellFormat());
ret->content << TileList::Row("Peer diagnostics", CellFormat());
ret->content << TileList::Row("Peer change self name", CellFormat());
ret->content << TileList::Row("Exit", CellFormat());
ret->selection_mode = TileList::NoSelection;
return ret;
}
PIScreenTile * infoTile() {
TileList * ret = new TileList();
local_info_base << TileList::Row("Exec command: " + PISystemInfo::instance()->execCommand, CellFormat());
local_info_base << TileList::Row(" Executed on " + PISystemInfo::instance()->execDateTime.toString(), CellFormat());
local_info_base << TileList::Row(" Hostname: " + PISystemInfo::instance()->hostname, CellFormat());
local_info_base << TileList::Row(" Username: " + PISystemInfo::instance()->user, CellFormat());
local_info_base << TileList::Row(" OS name: " + PISystemInfo::instance()->OS_name, CellFormat());
local_info_base << TileList::Row(" OS version: " + PISystemInfo::instance()->OS_version, CellFormat());
local_info_base << TileList::Row("Architecture: " + PISystemInfo::instance()->architecture, CellFormat());
local_info_base << TileList::Row(" CPU count: " + PIString::fromNumber(PISystemInfo::instance()->processorsCount), CellFormat());
local_info_base << TileList::Row("", CellFormat());
return ret;
}
PIScreenTile * peerDiagTile() {
PIScreenTile * ret = new PIScreenTile();
TileSimple * htl = new TileSimple();
htl->size_policy = PIScreenTypes::Fixed;
ret->direction = PIScreenTypes::Vertical;
htl->content << TileSimple::Row("Peer: " + daemon_.name() + " | " + daemon_.selfInfo().name,
CellFormat(PIScreenTypes::Default, PIScreenTypes::Default, PIScreenTypes::Bold));
PIScreenTile * diag = new PIScreenTile();
diag->direction = PIScreenTypes::Horizontal;
peerdiagdata_tl = new TileSimple();
peerdiagservice_tl = new TileSimple();
ret->addTile(htl);
ret->addTile(diag);
diag->addTile(peerdiagdata_tl);
diag->addTile(peerdiagservice_tl);
return ret;
}
PIScreenTile * peerTile() {
PIScreenTile * ret = new PIScreenTile();
ret->direction = PIScreenTypes::Vertical;
peerinfo_header = new TileSimple();
peerinfo_header->size_policy = PIScreenTypes::Fixed;
peerinfo_header->content << TileSimple::Row("Peer: " + daemon_.name() + " | " + daemon_.selfInfo().name,
CellFormat(PIScreenTypes::Default, PIScreenTypes::Default, PIScreenTypes::Bold));
addrs_tl = new TileList();
peers_tl = new TileList();
peerinfo_tl = new TileSimple();
peermap_tl = new TileList();
peerinfo_tl->size_policy = PIScreenTypes::Fixed;
ret->addTile(peerinfo_header);
ret->addTile(peers_tl);
ret->addTile(peerinfo_tl);
ret->addTile(addrs_tl);
ret->addTile(peermap_tl);
return ret;
}
void updateTitle(TileSimple * tl) {
tl->content.clear();
tl->content << TileSimple::Row("pisd (PI System Daemon, PIP version " + PIPVersion() + ")", CellFormat(Black, Transparent));
tl->content << TileSimple::Row("This daemon: \"" + daemon_.thisDaemonName() + "\"", CellFormat(Black, Transparent));
}
void updatePeerDiag(TileSimple * tl, const PIDiagnostics & diag) {
tl->content.clear();
PIDiagnostics::State ds = diag.state();
tl->content << TileSimple::Row(diag.name() + " diagnostics",
CellFormat(PIScreenTypes::Default, PIScreenTypes::Default, PIScreenTypes::Bold));
tl->content << TileSimple::Row("Received count: " + PIString::fromNumber(ds.received_packets), CellFormat());
tl->content << TileSimple::Row("Invalid count: " + PIString::fromNumber(ds.received_packets_wrong), CellFormat());
tl->content << TileSimple::Row("Sended count: " + PIString::fromNumber(ds.sended_packets), CellFormat());
tl->content << TileSimple::Row("Immediate Frequency, Hz: " + PIString::fromNumber(ds.immediate_freq), CellFormat());
tl->content << TileSimple::Row("Integral Frequency, Hz: " + PIString::fromNumber(ds.integral_freq), CellFormat());
tl->content << TileSimple::Row("Receive speed: " + ds.receive_speed, CellFormat());
tl->content << TileSimple::Row("Send speed: " + ds.send_speed, CellFormat());
tl->content << TileSimple::Row("Quality: " + PIString::fromNumber((int)ds.quality), CellFormat());
}
void updatePeerInfo() {
// bool pm = daemon_.lockedPeers();
screen->lock();
daemon_.lock();
peers_tl->content.clear();
addrs_tl->content.clear();
peerinfo_tl->content.clear();
peermap_tl->content.clear();
peers_tl->content << TileList::Row(
"this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s())
// + " [em = " + PIString::fromBool(daemon_.lockedEth()) + ",
//" "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", "
//"sm
//=
//"
//+ PIString::fromBool(daemon_.lockedSends()) + ", " "ms = " +
// PIString::fromBool(daemon_.lockedMCSends()) + ", " "pm = " + PIString::fromBool(pm)
// +
// "]"
,
CellFormat());
for (const auto & p: daemon_.allPeers())
peers_tl->content << TileList::Row(p.name + " | d = " + PIString::fromNumber(p.dist) + " | p = " +
PIString::fromNumber(p.ping()) + " | n = " + PIString::fromBool(p.isNeighbour()),
CellFormat());
PIPeer::PeerInfo pi = daemon_.selfInfo();
if (cur_peer >= 0 && cur_peer < daemon_.allPeers().size_s()) pi = daemon_.allPeers()[cur_peer];
peerinfo_tl->content << TileSimple::Row("Name: " + pi.name, CellFormat());
peerinfo_tl->content << TileSimple::Row("Addreses: " + PIString::fromNumber(pi.addresses.size()), CellFormat());
peerinfo_tl->content << TileSimple::Row("Neighbours: " + pi.neighbours.join(", "), CellFormat());
for (const auto & a: pi.addresses)
addrs_tl->content << TileList::Row(a.address.toString() + " | p = " + PIString::fromNumber(a.ping) +
" | a = " + PIString::fromBool(a.isAvailable()),
CellFormat());
PIStringList peermap;
for (auto p = daemon_._peerMap().begin(); p != daemon_._peerMap().end(); p++) {
PIString s = p.key() + " | ";
piForeachCR(PIPeer::PeerInfo * pp, p.value())
s += " -> " + pp->name;
peermap << s;
}
for (const auto & s: peermap)
peermap_tl->content << TileList::Row(s, CellFormat());
updatePeerDiag(peerdiagdata_tl, daemon_.diagnosticData());
updatePeerDiag(peerdiagservice_tl, daemon_.diagnosticService());
daemon_.unlock();
screen->unlock();
}
void updateSysMon() {
TileList * tile = (TileList *)tinfo;
PIVector<PISystemMonitor::ThreadStats> ts = sys_mon.threadsStatistic();
screen->lock();
tile->content = local_info_base;
int num = 0, maxlen = 0;
PIString line = "Process load: k ";
PIString ns = PIString::fromNumber(sys_mon.statistic().cpu_load_system, 'f', 2);
line += ns.expandLeftTo(5, ' ') + " %, u ";
ns = PIString::fromNumber(sys_mon.statistic().cpu_load_user, 'f', 2);
line += ns.expandLeftTo(5, ' ') + " %";
tile->content << TileList::Row("PID: " + PIString::fromNumber(sys_mon.statistic().ID), CellFormat());
tile->content << TileList::Row(line, CellFormat());
tile->content << TileList::Row("Threads:", CellFormat());
for (const auto & t: ts)
maxlen = piMaxi(maxlen, t.name.length());
for (const auto & t: ts) {
line = PIString::fromNumber(++num).expandLeftTo(2, ' ') + ": ";
line += PIString(t.name).expandRightTo(maxlen, ' ') + ": k ";
PIString ns = PIString::fromNumber(t.cpu_load_kernel, 'f', 2);
line += ns.expandLeftTo(5, ' ') + " %, u ";
ns = PIString::fromNumber(t.cpu_load_user, 'f', 2);
line += ns.expandLeftTo(5, ' ') + " %";
tile->content << TileList::Row(line, CellFormat());
}
screen->unlock();
}
void tick(int delimiter) override {
if (tpeerdiag->visible || tpeer->visible) updatePeerInfo();
if (tinfo->visible) updateSysMon();
}
EVENT_HANDLER(void, menuRequest) {
for (auto * t: mtiles)
t->hide();
daemon_.disconnect();
tmenu->show();
tmenu->setFocus();
}
EVENT_HANDLER2(void, tileEvent, PIScreenTile *, t, PIScreenTypes::TileEvent, e) {
if (t == tmenu) {
if (e.type == TileList::RowPressed) {
for (auto * t: mtiles)
t->hide();
switch (e.data.toInt()) {
case 0: tinfo->show(); break;
case 1:
daemon_.fm.setLocal();
daemon_.showLocalFilemanager();
tdaemon->show();
break;
case 2:
daemon_.fm.setRemote();
daemon_.showMainList();
tdaemon->show();
break;
case 3:
tpeer->show();
peers_tl->setFocus();
break;
case 4:
daemon_.reinit();
tmenu->show();
break;
case 5: tpeerdiag->show(); break;
case 6: {
PIString nn = askUserInput("Peer name:");
if (!nn.isEmpty()) {
daemon_.changeName(pisd_prefix + nn);
peerinfo_header->content.clear();
peerinfo_header->content
<< TileSimple::Row("Peer: " + daemon_.name() + " | " + daemon_.selfInfo().name,
CellFormat(PIScreenTypes::Default, PIScreenTypes::Default, PIScreenTypes::Bold));
updateTitle(title);
}
menuRequest();
} break;
case 7: PIKbdListener::exiting = true; break;
}
}
return;
}
if (t == peers_tl) {
if (e.type == TileList::RowPressed) {
cur_peer = e.data.toInt() - 1;
updatePeerInfo();
}
return;
}
}
EVENT_HANDLER1(void, keyEvent, PIKbdListener::KeyEvent, e) {
if (e.key == PIKbdListener::F9) {
tpicout->visible = !tpicout->visible;
return;
}
if (e.key == PIKbdListener::Esc && e.modifiers[PIKbdListener::Shift]) {
PIKbdListener::exiting = true;
return;
}
if (screen->dialogTile()) return;
if (tpeer->visible || tinfo->visible || tpeerdiag->visible)
if (e.key == PIKbdListener::Esc) menuRequest();
// piCout << "key" << e.key;
}
EVENT_HANDLER1(void, messageFromApp, PIByteArray, m) {
if (m[0] == 'k') PIKbdListener::exiting = true;
}
Daemon & daemon_;
PIScreenTile *tmenu, *tinfo, *tfm, *tdaemon, *tpeer, *tpeerdiag;
TileList *peers_tl, *addrs_tl, *peermap_tl;
TilePICout * tpicout;
TileSimple * title;
TileSimple *peerinfo_tl, *peerinfo_header;
TileSimple *peerdiagdata_tl, *peerdiagservice_tl;
PIVector<PIScreenTile *> mtiles;
PIDeque<TileList::Row> local_info_base;
int cur_peer;
};
void usage() {
piCout << PICoutManipulators::Bold << "PIP System Daemon";
piCout << PICoutManipulators::Cyan << "Version" << PICoutManipulators::Bold << PIPVersion() << PICoutManipulators::NewLine;
piCout << PICoutManipulators::Green << PICoutManipulators::Bold << "Usage:" << PICoutManipulators::Default
<< "\"pisd [-1hdfk] [-n <name>] [-a <ip>]\"" << PICoutManipulators::NewLine;
piCout << PICoutManipulators::Green << PICoutManipulators::Bold << "Details:";
piCout << "-h --help " << PICoutManipulators::Green << "- display this message and exit";
piCout << "-d --daemon " << PICoutManipulators::Green << "- start as daemon";
piCout << "-k --kill " << PICoutManipulators::Green << "- kill daemon";
piCout << "-f --force " << PICoutManipulators::Green << "- don`t check for another running instance";
piCout << "-n --name <name> " << PICoutManipulators::Green << "- set daemon name";
piCout << "-a --address <ip>" << PICoutManipulators::Green << "- connect to remote daemon via tcp";
piCout << "-s --silent " << PICoutManipulators::Green << "- run without user interfase";
}
int main(int argc, char * argv[]) {
sys_mon.startOnSelf();
// piDebug = false;
PICLI cli(argc, argv);
cli.addArgument("help");
cli.addArgument("daemon");
cli.addArgument("force");
cli.addArgument("kill");
cli.addArgument("1");
cli.addArgument("silent");
cli.addArgument("name", true);
cli.addArgument("address", true);
if (cli.hasArgument("help")) {
usage();
return 0;
}
PIString name = cli.argumentValue("name");
PIString sip = cli.argumentValue("address");
PISingleApplication * sapp = 0;
if ((cli.hasArgument("1") && !cli.hasArgument("force")) || cli.hasArgument("kill")) {
sapp = new PISingleApplication("pisd");
if (cli.hasArgument("1")) {
if (!sapp->isFirst()) {
piCout << "Another pisd is running, exit";
delete sapp;
return 0;
}
}
if (cli.hasArgument("kill")) {
sapp->sendMessage(PIByteArray("k", 1));
delete sapp;
return 0;
}
}
PIINTROSPECTION_START(pisd)
if (cli.hasArgument("daemon")) {
PIStringList args;
args << "-1"
<< "-s";
if (cli.hasArgument("force")) args << "-f";
if (cli.hasArgument("address")) args << "-a" << sip;
if (!name.isEmpty()) args << "-n" << name;
PIString exe;
#ifdef WINDOWS
exe = PISystemInfo::instance()->execCommand;
#else
exe = PIProcess::getEnvironmentVariable("_");
#endif
piCout << "start in background:" << exe; // << "; with args" << args;
PIProcess::execIndependent(exe, args);
return 0;
}
screen = new PIScreen(false);
screen->setMouseEnabled(true);
Daemon * daemon = new Daemon();
if (!sip.isEmpty()) daemon->setTcpServerIP(sip);
screen->enableExitCapture(PIKbdListener::F10);
if (!name.isEmpty()) daemon->changeName(pisd_prefix + name);
MainMenu * menu = new MainMenu(*daemon);
if (sapp) CONNECTU(sapp, messageReceived, menu, messageFromApp);
if (cli.hasArgument("silent")) {
PICout::setOutputDevices(PICout::Console);
PIKbdListener ls;
ls.enableExitCapture(PIKbdListener::F10);
ls.start();
WAIT_FOR_EXIT
ls.stopAndWait();
} else {
screen->start();
screen->waitForFinish();
screen->stop(true);
}
sys_mon.stop();
delete menu;
delete daemon;
delete screen;
if (sapp) delete sapp;
return 0;
}