|
|
|
|
@@ -1,25 +1,36 @@
|
|
|
|
|
#include "server_core.h"
|
|
|
|
|
#include "piqt.h"
|
|
|
|
|
#include "SH_packages.h"
|
|
|
|
|
|
|
|
|
|
#include "SH_network_types.h"
|
|
|
|
|
#include "SH_packages.h"
|
|
|
|
|
#include "SH_plugins_manager.h"
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QMetaEnum>
|
|
|
|
|
#include <QCryptographicHash>
|
|
|
|
|
#include <QResource>
|
|
|
|
|
#include <qad_locations.h>
|
|
|
|
|
#include <piethernet.h>
|
|
|
|
|
#include "ccm_SHS_shared.h"
|
|
|
|
|
|
|
|
|
|
//const double keepAliveInterval_s = 2.;
|
|
|
|
|
#include <QCryptographicHash>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QMetaEnum>
|
|
|
|
|
#include <QResource>
|
|
|
|
|
#include <piethernet.h>
|
|
|
|
|
#include <piliterals_time.h>
|
|
|
|
|
#include <piqt.h>
|
|
|
|
|
#include <qad_locations.h>
|
|
|
|
|
|
|
|
|
|
// const double keepAliveInterval_s = 2.;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum TimerRole {
|
|
|
|
|
trSaveState,
|
|
|
|
|
trAdmin,
|
|
|
|
|
trServerSync,
|
|
|
|
|
trClients
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ServerCore::ServerCore(bool reservation): QObject(), SHMulticast(), eth_tcp(PIEthernet::TCP_Server) {
|
|
|
|
|
PACKAGES;
|
|
|
|
|
file_ui_state = QAD::userPath(QAD::ltCache, "ui_state" );
|
|
|
|
|
file_ui_state = QAD::userPath(QAD::ltCache, "ui_state");
|
|
|
|
|
file_ui_state_new = QAD::userPath(QAD::ltCache, "ui_state_new");
|
|
|
|
|
with_reservation = reservation;
|
|
|
|
|
auto il = PIEthernet::interfaces();
|
|
|
|
|
with_reservation = reservation;
|
|
|
|
|
auto il = PIEthernet::interfaces();
|
|
|
|
|
for (const auto & i: il) {
|
|
|
|
|
piCout << i.name << i.address;
|
|
|
|
|
if (!i.isLoopback() && !i.address.isEmpty() && i.address != "0.0.0.0") {
|
|
|
|
|
@@ -27,17 +38,27 @@ ServerCore::ServerCore(bool reservation): QObject(), SHMulticast(), eth_tcp(PIEt
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
seed = generateID();//PINetworkAddress(my_ip, 0).ip();
|
|
|
|
|
seed = generateID(); // PINetworkAddress(my_ip, 0).ip();
|
|
|
|
|
addressesChanged();
|
|
|
|
|
piCoutObj << PICoutManipulators::Hex << seed << PINetworkAddress(seed, 0);
|
|
|
|
|
connect(&engine, SIGNAL(variableHistoryAdded(QString,QPair<QDateTime,double>)), this, SLOT(variableHistoryAdded(QString,QPair<QDateTime,double>)), Qt::DirectConnection);
|
|
|
|
|
connect(&engine,
|
|
|
|
|
SIGNAL(variableHistoryAdded(QString, QPair<QDateTime, double>)),
|
|
|
|
|
this,
|
|
|
|
|
SLOT(variableHistoryAdded(QString, QPair<QDateTime, double>)),
|
|
|
|
|
Qt::DirectConnection);
|
|
|
|
|
connect(&engine, SIGNAL(debug(QString)), this, SLOT(scriptDebug(QString)), Qt::DirectConnection);
|
|
|
|
|
CONNECTU(ð_tcp, newConnection, this, newTCPConnection);
|
|
|
|
|
CONNECTU(&cloud_server, newConnection, this, newCloudConnection);
|
|
|
|
|
bindIndexedTimer(trSaveState, [this] { saveUIState(); });
|
|
|
|
|
bindIndexedTimer(trAdmin, [this] { sendAdminData(); });
|
|
|
|
|
bindIndexedTimer(trServerSync, [this] { syncServers(); });
|
|
|
|
|
bindIndexedTimer(trClients, [this] { procClients(); });
|
|
|
|
|
delete_clients_thread.start([this] { deleteOldClients(); }, 2_Hz);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ServerCore::~ServerCore() {
|
|
|
|
|
piCoutObj << "~ServerCore";
|
|
|
|
|
cloud_server.close();
|
|
|
|
|
cloud_server.stop();
|
|
|
|
|
engine.remove();
|
|
|
|
|
@@ -45,25 +66,29 @@ ServerCore::~ServerCore() {
|
|
|
|
|
PIByteArray sba = SHNetworkTypes::makeHeader(SHNetworkTypes::ServerRemove);
|
|
|
|
|
sba << seed;
|
|
|
|
|
piCoutObj << "send ServerRemove seed =" << seed;
|
|
|
|
|
send(sba);
|
|
|
|
|
killTimer(timer_save_state);
|
|
|
|
|
killTimer(timer_admin);
|
|
|
|
|
killTimer(timer_sync);
|
|
|
|
|
killTimer(timer);
|
|
|
|
|
stopRead();
|
|
|
|
|
PIVector<ServerClient * > rl = remotes.values();
|
|
|
|
|
send(sba);
|
|
|
|
|
stopIndexedTimer(trSaveState);
|
|
|
|
|
stopIndexedTimer(trAdmin);
|
|
|
|
|
stopIndexedTimer(trServerSync);
|
|
|
|
|
stopIndexedTimer(trClients);
|
|
|
|
|
delete_clients_thread.stopAndWait();
|
|
|
|
|
deleteOldClients();
|
|
|
|
|
PIVector<ServerClient *> rl = remotes.values();
|
|
|
|
|
for (ServerClient * r: rl)
|
|
|
|
|
if (r) {
|
|
|
|
|
piCoutObj << "delete" << (uintptr_t)r << "...";
|
|
|
|
|
r->destroy();
|
|
|
|
|
delete r->device;
|
|
|
|
|
delete r;
|
|
|
|
|
piCoutObj << "delete" << (uintptr_t)r << "done";
|
|
|
|
|
}
|
|
|
|
|
remotes.clear();
|
|
|
|
|
eth_tcp.stop();
|
|
|
|
|
for (auto * c: eth_tcp.clients())
|
|
|
|
|
c->stop();
|
|
|
|
|
piDeleteSafety(form);
|
|
|
|
|
if (bqr_content.data())
|
|
|
|
|
QResource::unregisterResource((uchar*)bqr_content.data());
|
|
|
|
|
if (bqr_content.data()) QResource::unregisterResource((uchar *)bqr_content.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -78,8 +103,8 @@ void ServerCore::startEth() {
|
|
|
|
|
cloud_server.startThreadedRead();
|
|
|
|
|
log(QString("Connect to cloud %1@%2").arg(sa.server, PI2QString(cloud_server.serverName())));
|
|
|
|
|
}
|
|
|
|
|
timer_sync = startTimer(100);
|
|
|
|
|
timer_admin = startTimer(1000);
|
|
|
|
|
startIndexedTimer(trServerSync, 10_Hz);
|
|
|
|
|
startIndexedTimer(trAdmin, 1_Hz);
|
|
|
|
|
SHMulticast::startRead();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -100,10 +125,10 @@ void ServerCore::loadRCC(const QString & p) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
bqr_content = Q2PIByteArray(f.readAll());
|
|
|
|
|
rcc_hash = bqr_content.hash();
|
|
|
|
|
rcc_hash = bqr_content.hash();
|
|
|
|
|
f.close();
|
|
|
|
|
if(bqr_content.isEmpty()) return;
|
|
|
|
|
if (!QResource::registerResource((uchar*)bqr_content.data())) {
|
|
|
|
|
if (bqr_content.isEmpty()) return;
|
|
|
|
|
if (!QResource::registerResource((uchar *)bqr_content.data())) {
|
|
|
|
|
log("Can`t open resource \"" + QFileInfo(f).absoluteFilePath() + "\"!", SHServer::LogWarning);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -126,10 +151,10 @@ void ServerCore::loadUI(const QString & p) {
|
|
|
|
|
}
|
|
|
|
|
f.seek(0);
|
|
|
|
|
ui_content = Q2PIByteArray(f.readAll());
|
|
|
|
|
ui_hash = ui_content.hash();
|
|
|
|
|
ui_hash = ui_content.hash();
|
|
|
|
|
ui_content = Q2PIByteArray(qCompress(PI2QByteArray(ui_content)));
|
|
|
|
|
sync.assign(&ui_loader, true);
|
|
|
|
|
RUNTIME->json_ui = sync.json_ui;
|
|
|
|
|
RUNTIME->json_ui = sync.json_ui;
|
|
|
|
|
RUNTIME->widget_list = ui_loader.loaded_widgets;
|
|
|
|
|
form->setWindowTitle(QFileInfo(p).baseName());
|
|
|
|
|
ui_loader.adjust(form);
|
|
|
|
|
@@ -149,12 +174,12 @@ void ServerCore::loadQS(const QString & p) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
log("Loaded script \"" + QFileInfo(f).absoluteFilePath() + "\"", SHServer::LogSuccess);
|
|
|
|
|
script_dir = QFileInfo(f).absoluteDir();
|
|
|
|
|
//script = QString::fromUtf8(f.readAll());
|
|
|
|
|
script_dir = QFileInfo(f).absoluteDir();
|
|
|
|
|
// script = QString::fromUtf8(f.readAll());
|
|
|
|
|
file_script = f.fileName();
|
|
|
|
|
QObject::connect(&engine, SIGNAL(error(int,QString,QString,QString)), this, SLOT(scriptError(int,QString,QString,QString)));
|
|
|
|
|
QObject::connect(&engine, SIGNAL(log(QString,int)), this, SLOT(scriptLog(QString,int)));
|
|
|
|
|
QObject::connect(&engine, SIGNAL(message(QString,int)), this, SLOT(scriptMessage(QString,int)));
|
|
|
|
|
QObject::connect(&engine, SIGNAL(error(int, QString, QString, QString)), this, SLOT(scriptError(int, QString, QString, QString)));
|
|
|
|
|
QObject::connect(&engine, SIGNAL(log(QString, int)), this, SLOT(scriptLog(QString, int)));
|
|
|
|
|
QObject::connect(&engine, SIGNAL(message(QString, int)), this, SLOT(scriptMessage(QString, int)));
|
|
|
|
|
QObject::connect(&engine, SIGNAL(logIO(QString)), this, SLOT(IOLog(QString)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -171,7 +196,7 @@ void ServerCore::loadDAT(const QString & p) {
|
|
|
|
|
}
|
|
|
|
|
log("Loaded database \"" + QFileInfo(f).absoluteFilePath() + "\"", SHServer::LogSuccess);
|
|
|
|
|
RUNTIME->setServerData(loadFromFile<SHS::ServerData>(p));
|
|
|
|
|
server_key_ = Q2PIString(RUNTIME->server_data.project.propertyValueByName("key" ).toString());
|
|
|
|
|
server_key_ = Q2PIString(RUNTIME->server_data.project.propertyValueByName("key").toString());
|
|
|
|
|
server_name_ = Q2PIString(RUNTIME->server_data.project.propertyValueByName("name").toString());
|
|
|
|
|
piCout << "key" << server_key_;
|
|
|
|
|
loadedDAT();
|
|
|
|
|
@@ -186,7 +211,7 @@ void ServerCore::loadCM(const QString & p) {
|
|
|
|
|
}
|
|
|
|
|
log("Loaded connection \"" + QFileInfo(f).absoluteFilePath() + "\"", SHServer::LogSuccess);
|
|
|
|
|
RUNTIME->connection.loadFromCMFile(p);
|
|
|
|
|
connect(&RUNTIME->connection, SIGNAL(qDataReceivedEvent(QString,QByteArray)), this, SLOT(connDataReceivedEvent(QString,QByteArray)));
|
|
|
|
|
connect(&RUNTIME->connection, SIGNAL(qDataReceivedEvent(QString, QByteArray)), this, SLOT(connDataReceivedEvent(QString, QByteArray)));
|
|
|
|
|
loadedCM();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -204,29 +229,28 @@ void ServerCore::loadVAR(const QString & p) {
|
|
|
|
|
|
|
|
|
|
void ServerCore::loadBAF(const PIString & p) {
|
|
|
|
|
piCout << "loadBAF" << p;
|
|
|
|
|
baf_path = p;
|
|
|
|
|
baf_path = p;
|
|
|
|
|
RUNTIME->server_project = SHS::ServerProject();
|
|
|
|
|
if (baf_path.isEmpty()) return;
|
|
|
|
|
RUNTIME->server_data.setRootPath(QDir::tempPath());
|
|
|
|
|
RUNTIME->modules_dir = RUNTIME->server_data.modulePath();
|
|
|
|
|
QStringList fl = ass.unpack(PI2QString(baf_path)), qspl;
|
|
|
|
|
QStringList fl = ass.unpack(PI2QString(baf_path)), qspl;
|
|
|
|
|
QString bqrp, uip, dbp, cmp, varp, sdpp;
|
|
|
|
|
for (const auto & s: fl) {
|
|
|
|
|
if (s.endsWith(".rcc")) bqrp = s;
|
|
|
|
|
if (s.endsWith(".uip")) uip = s;
|
|
|
|
|
if (s.endsWith(".uip")) uip = s;
|
|
|
|
|
if (s.endsWith(".dat") && !s.endsWith(QString(SHFileSuffix) + ".dat")) dbp = s;
|
|
|
|
|
if (s.endsWith(".qs")) qspl << s;
|
|
|
|
|
if (s.endsWith(".cm")) cmp = s;
|
|
|
|
|
if (s.endsWith(".qs")) qspl << s;
|
|
|
|
|
if (s.endsWith(".cm")) cmp = s;
|
|
|
|
|
if (s.endsWith(".var")) varp = s;
|
|
|
|
|
if (s.endsWith(".sdp")) sdpp = s;
|
|
|
|
|
}
|
|
|
|
|
if (!bqrp.isEmpty()) loadRCC(bqrp);
|
|
|
|
|
loadUI(uip);
|
|
|
|
|
if (!cmp.isEmpty()) loadCM(cmp);
|
|
|
|
|
if (!dbp.isEmpty()) loadDAT(dbp);
|
|
|
|
|
if (!cmp.isEmpty()) loadCM(cmp);
|
|
|
|
|
if (!dbp.isEmpty()) loadDAT(dbp);
|
|
|
|
|
RUNTIME->server_data.setRootPath(QDir::tempPath());
|
|
|
|
|
if (!varp.isEmpty())
|
|
|
|
|
loadVAR(varp);
|
|
|
|
|
if (!varp.isEmpty()) loadVAR(varp);
|
|
|
|
|
if (!sdpp.isEmpty())
|
|
|
|
|
loadProject(sdpp);
|
|
|
|
|
else if (qspl.size() == 1) {
|
|
|
|
|
@@ -259,221 +283,9 @@ void ServerCore::loadProject(const QString & p) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::timerEvent(QTimerEvent * e) {
|
|
|
|
|
if (e->timerId() == timer_save_state) {
|
|
|
|
|
saveUIState();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (e->timerId() == timer_sync) {
|
|
|
|
|
if (with_reservation) {
|
|
|
|
|
smutex.lock();
|
|
|
|
|
if (server_state > ServerCore::ssSync) {
|
|
|
|
|
for (int i = 0; i < servers.size_s(); ++i) {
|
|
|
|
|
servers[i].missed++;
|
|
|
|
|
if (servers[i].missed > 10) {
|
|
|
|
|
piCoutObj << "remove by timeout" << servers[i].seed;
|
|
|
|
|
if (servers[i].seed == seed_main)
|
|
|
|
|
selectNewMain();
|
|
|
|
|
servers.remove(i);
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
smutex.unlock();
|
|
|
|
|
if (sync_skip > 0) {
|
|
|
|
|
sync_skip--;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (server_state) {
|
|
|
|
|
case ServerCore::ssStart: {
|
|
|
|
|
PIByteArray sba = SHNetworkTypes::makeHeader(SHNetworkTypes::ServerNew);
|
|
|
|
|
sba << seed;
|
|
|
|
|
piCoutObj << "send ServerNew seed =" << seed << ", ip =" << my_ip;
|
|
|
|
|
send(sba);
|
|
|
|
|
selectNewMain();
|
|
|
|
|
} break;
|
|
|
|
|
case ServerCore::ssSync:
|
|
|
|
|
if (seed_main == 0) {
|
|
|
|
|
int mseed = seed;
|
|
|
|
|
int mi = -1;
|
|
|
|
|
smutex.lock();
|
|
|
|
|
for (int i = 0; i < servers.size_s(); ++i) {
|
|
|
|
|
if (mseed > servers[i].seed) {
|
|
|
|
|
mseed = servers[i].seed;
|
|
|
|
|
mi = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
smutex.unlock();
|
|
|
|
|
seed_main = mseed;
|
|
|
|
|
main_ip = PINetworkAddress(mseed, 0).ipString();
|
|
|
|
|
if (mi < 0)
|
|
|
|
|
startAsMain();
|
|
|
|
|
else
|
|
|
|
|
startAsReserve();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ServerCore::ssWorkReserve:
|
|
|
|
|
main_missed++;
|
|
|
|
|
if (main_missed > 10) {
|
|
|
|
|
main_missed = 0;
|
|
|
|
|
selectNewMain();
|
|
|
|
|
}
|
|
|
|
|
case ServerCore::ssWorkMain:
|
|
|
|
|
{
|
|
|
|
|
PIByteArray sba = SHNetworkTypes::makeHeader(SHNetworkTypes::ServerPing);
|
|
|
|
|
sba << seed;
|
|
|
|
|
//piCoutObj << "send ServerPing seed =" << seed;
|
|
|
|
|
send(sba);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else startAsMain();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (e->timerId() == timer_admin) {
|
|
|
|
|
|
|
|
|
|
lmutex.lock();
|
|
|
|
|
PacketServerLog pck_log, pck_log_hist;
|
|
|
|
|
pck_log.entries = std::move(admin_log);
|
|
|
|
|
admin_log.clear();
|
|
|
|
|
auto mq = std::move(message_queue);
|
|
|
|
|
message_queue.clear();
|
|
|
|
|
lmutex.unlock();
|
|
|
|
|
|
|
|
|
|
rmutex.lock();
|
|
|
|
|
state_dynamic.clients.clear();
|
|
|
|
|
PIVector<ServerClient * > rl = remotes.values();
|
|
|
|
|
for (ServerClient * r: rl) {
|
|
|
|
|
if (!r) continue;
|
|
|
|
|
r->updateInfo();
|
|
|
|
|
state_dynamic.clients << r->info;
|
|
|
|
|
}
|
|
|
|
|
state_dynamic.devices.clear();
|
|
|
|
|
PIVector<PIIODevice * > devs = RUNTIME->connection.boundedDevices();
|
|
|
|
|
for (PIIODevice * d: devs) {
|
|
|
|
|
if (!d) continue;
|
|
|
|
|
ServerDeviceInfo di;
|
|
|
|
|
di.classname = QLatin1String(d->className());
|
|
|
|
|
di.path = PI2QString(d->path());
|
|
|
|
|
di.mode = d->mode();
|
|
|
|
|
PIDiagnostics * diag = RUNTIME->connection.diagnostic(d);
|
|
|
|
|
if (diag) {
|
|
|
|
|
di.sended_bytes = diag->state().sended_bytes;
|
|
|
|
|
di.received_bytes = diag->state().received_bytes;
|
|
|
|
|
di.send_speed = PI2QString(diag->sendSpeed());
|
|
|
|
|
di.receive_speed = PI2QString(diag->receiveSpeed());
|
|
|
|
|
}
|
|
|
|
|
state_dynamic.devices << di;
|
|
|
|
|
}
|
|
|
|
|
for (auto & v: state_dynamic.variables) {
|
|
|
|
|
auto val = engine.getVariableValue(v.name);
|
|
|
|
|
v.changed = val.first;
|
|
|
|
|
v.value = val.second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PIByteArray msg_state;
|
|
|
|
|
msg_state = SHNetworkTypes::makeHeader(SHNetworkTypes::AdminDynamicState);
|
|
|
|
|
msg_state << state_dynamic;
|
|
|
|
|
|
|
|
|
|
for (ServerClient * r: rl) {
|
|
|
|
|
if (!r) continue;
|
|
|
|
|
|
|
|
|
|
if (r->info.role == SHServer::RoleMessages) {
|
|
|
|
|
for (const auto & m: mq) {
|
|
|
|
|
PIByteArray ba = SHNetworkTypes::makeHeader(SHNetworkTypes::Message);
|
|
|
|
|
ba << m;
|
|
|
|
|
r->queueSend(ba);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->info.role == SHServer::RoleAdmin) {
|
|
|
|
|
if (!r->log_sended) {
|
|
|
|
|
r->log_sended = true;
|
|
|
|
|
pck_log_hist.entries = admin_log_history;
|
|
|
|
|
PIByteArray msg = SHNetworkTypes::makeHeader(SHNetworkTypes::AdminLog);
|
|
|
|
|
msg << pck_log_hist;
|
|
|
|
|
r->queueSend(msg);
|
|
|
|
|
}
|
|
|
|
|
if (!msg_state.isEmpty())
|
|
|
|
|
r->queueSend(msg_state);
|
|
|
|
|
if (!pck_log.entries.isEmpty() || !r->admin_io_log.isEmpty()) {
|
|
|
|
|
PacketServerLog pckt;
|
|
|
|
|
pckt.entries << pck_log.entries << r->admin_io_log;
|
|
|
|
|
pckt.entries.sort([](const LogEntry & t0, const LogEntry & t1){return t0.time < t1.time;});
|
|
|
|
|
r->admin_io_log.clear();
|
|
|
|
|
PIByteArray msg = SHNetworkTypes::makeHeader(SHNetworkTypes::AdminLog);
|
|
|
|
|
msg << pckt;
|
|
|
|
|
r->queueSend(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rmutex.unlock();
|
|
|
|
|
|
|
|
|
|
for (const auto & e: pck_log.entries) {
|
|
|
|
|
admin_log_cur_size += e.text.size();
|
|
|
|
|
admin_log_history << e;
|
|
|
|
|
while (admin_log_cur_size > admin_log_max_size)
|
|
|
|
|
admin_log_cur_size -= admin_log_history.take_front().text.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
rmutex.lock();
|
|
|
|
|
|
|
|
|
|
sync.buildDiffForRoles();
|
|
|
|
|
|
|
|
|
|
PIVector<ServerClient * > rl = remotes.values(), to_remove;
|
|
|
|
|
for (ServerClient * r: rl) {
|
|
|
|
|
bool disconn = !r->isConnected();
|
|
|
|
|
if (r) {if (r->tcp->wasError()) disconn = true;}
|
|
|
|
|
if (disconn) {
|
|
|
|
|
log("Client " + PI2QString(r->device->path()) + " disconnected", SHServer::LogInfo);
|
|
|
|
|
//piCout << "disconn ...";
|
|
|
|
|
r->close();
|
|
|
|
|
//piCout << "disconn close";
|
|
|
|
|
if (df_client == r) {
|
|
|
|
|
df_client = 0;
|
|
|
|
|
df_device.clear();
|
|
|
|
|
engine.connection()->setInactive(false);
|
|
|
|
|
}
|
|
|
|
|
to_remove << r;
|
|
|
|
|
//piCout << "disconn done";
|
|
|
|
|
}
|
|
|
|
|
r->maybeCallQueuedEvents();
|
|
|
|
|
r->updateInfo();
|
|
|
|
|
if (!r->tcp || !r->active || (r->info.role != SHServer::RoleGui)) continue;
|
|
|
|
|
PIByteArray diff;
|
|
|
|
|
if (r->role_changed) {
|
|
|
|
|
diff = Q2PIByteArray(sync.buildTransitionDiff(r->user_role, r->new_user_role));
|
|
|
|
|
//qDebug() << "send transitional diff" << r->user_role << "->" << r->new_user_role << diff.size();
|
|
|
|
|
r->newRoleDone();
|
|
|
|
|
if (!diff.isEmpty()) {
|
|
|
|
|
diff.insert(0, SHNetworkTypes::makeHeader(SHNetworkTypes::GuiSyncDiff));
|
|
|
|
|
r->queueSend(diff);
|
|
|
|
|
}
|
|
|
|
|
diff.clear();
|
|
|
|
|
}
|
|
|
|
|
diff = sync.diffForRole(r->user_role);
|
|
|
|
|
if (!diff.isEmpty()) {
|
|
|
|
|
diff.insert(0, SHNetworkTypes::makeHeader(SHNetworkTypes::GuiSyncDiff));
|
|
|
|
|
r->queueSend(diff);
|
|
|
|
|
}
|
|
|
|
|
//piCout << "diff role" << r->user_role << diff.size();
|
|
|
|
|
}
|
|
|
|
|
for (ServerClient * r: to_remove) {
|
|
|
|
|
remotes.remove(r->device);
|
|
|
|
|
r->destroy();
|
|
|
|
|
delete r->device;
|
|
|
|
|
delete r;
|
|
|
|
|
}
|
|
|
|
|
rmutex.unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool ServerCore::hasServer(const PIString & ip) const {
|
|
|
|
|
for (const auto & s: servers)
|
|
|
|
|
if (s.ip == ip)
|
|
|
|
|
return true;
|
|
|
|
|
if (s.ip == ip) return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -504,10 +316,8 @@ void ServerCore::startAsMain() {
|
|
|
|
|
if (server_state == ServerCore::ssWorkMain) return;
|
|
|
|
|
piCoutObj << "startAsMain";
|
|
|
|
|
server_state = ServerCore::ssWorkMain;
|
|
|
|
|
if (timer > 0) killTimer(timer);
|
|
|
|
|
timer = startTimer(100);
|
|
|
|
|
if (timer_save_state > 0) killTimer(timer_save_state);
|
|
|
|
|
timer_save_state = startTimer(10000);
|
|
|
|
|
startIndexedTimer(trSaveState, 10_s);
|
|
|
|
|
startIndexedTimer(trClients, 10_Hz);
|
|
|
|
|
sync_skip = 0;
|
|
|
|
|
start();
|
|
|
|
|
engine.setDir(script_dir);
|
|
|
|
|
@@ -531,8 +341,7 @@ void ServerCore::startAsReserve() {
|
|
|
|
|
if (server_state == ServerCore::ssWorkReserve) return;
|
|
|
|
|
piCoutObj << "startAsReserve";
|
|
|
|
|
server_state = ServerCore::ssWorkReserve;
|
|
|
|
|
if (timer > 0) killTimer(timer);
|
|
|
|
|
timer = 0;
|
|
|
|
|
stopIndexedTimer(trClients);
|
|
|
|
|
sync_skip = 0;
|
|
|
|
|
start();
|
|
|
|
|
startedAsReserve();
|
|
|
|
|
@@ -541,9 +350,9 @@ void ServerCore::startAsReserve() {
|
|
|
|
|
|
|
|
|
|
void ServerCore::selectNewMain() {
|
|
|
|
|
piCoutObj << "selectNewMain";
|
|
|
|
|
seed_main = 0;
|
|
|
|
|
seed_main = 0;
|
|
|
|
|
server_state = ServerCore::ssSync;
|
|
|
|
|
sync_skip = 10;
|
|
|
|
|
sync_skip = 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -566,8 +375,7 @@ void ServerCore::restoreUIState() {
|
|
|
|
|
QFile f(file_ui_state);
|
|
|
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
|
|
|
f.setFileName(file_ui_state_new);
|
|
|
|
|
if (!f.open(QIODevice::ReadOnly))
|
|
|
|
|
return;
|
|
|
|
|
if (!f.open(QIODevice::ReadOnly)) return;
|
|
|
|
|
}
|
|
|
|
|
if (f.size() < 8) return;
|
|
|
|
|
QDataStream s(&f);
|
|
|
|
|
@@ -577,7 +385,7 @@ void ServerCore::restoreUIState() {
|
|
|
|
|
s >> v >> data;
|
|
|
|
|
if (v == SHUISync::Version3) {
|
|
|
|
|
data = sync.convertFromVersion3(data);
|
|
|
|
|
v = SHUISync::CurrentVersion;
|
|
|
|
|
v = SHUISync::CurrentVersion;
|
|
|
|
|
piCoutObj << "UI state converted from version" << SHUISync::Version3;
|
|
|
|
|
}
|
|
|
|
|
if (v != SHUISync::CurrentVersion) {
|
|
|
|
|
@@ -630,7 +438,7 @@ void ServerCore::gatherVariables() {
|
|
|
|
|
vars = engine.getVariables();
|
|
|
|
|
for (const auto & v: vars) {
|
|
|
|
|
ServerVariable sv;
|
|
|
|
|
sv.name = v.name;
|
|
|
|
|
sv.name = v.name;
|
|
|
|
|
sv.store = v.store;
|
|
|
|
|
state_dynamic.variables << sv;
|
|
|
|
|
}
|
|
|
|
|
@@ -644,9 +452,230 @@ void ServerCore::gatherFixedState() {
|
|
|
|
|
PIString server = Q2PIString(RUNTIME->server_data.project.propertyValueByName("cloud_address").toString()) + "@";
|
|
|
|
|
server += getThisCloudName();
|
|
|
|
|
state_fixed.cloud_address = PI2QString(server);
|
|
|
|
|
state_fixed.cloud_href = QString("https://") + SHServerURL + "/pult/?address=" + QString(QUrl::toPercentEncoding(PI2QString(server + getThisCloudName())));
|
|
|
|
|
state_fixed.cloud_href = QString("https://") + SHServerURL +
|
|
|
|
|
"/pult/?address=" + QString(QUrl::toPercentEncoding(PI2QString(server + getThisCloudName())));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::sendAdminData() {
|
|
|
|
|
lmutex.lock();
|
|
|
|
|
PacketServerLog pck_log, pck_log_hist;
|
|
|
|
|
pck_log.entries = std::move(admin_log);
|
|
|
|
|
admin_log.clear();
|
|
|
|
|
auto mq = std::move(message_queue);
|
|
|
|
|
message_queue.clear();
|
|
|
|
|
lmutex.unlock();
|
|
|
|
|
|
|
|
|
|
rmutex.lock();
|
|
|
|
|
state_dynamic.clients.clear();
|
|
|
|
|
PIVector<ServerClient *> rl = remotes.values();
|
|
|
|
|
for (ServerClient * r: rl) {
|
|
|
|
|
if (!r) continue;
|
|
|
|
|
r->updateInfo();
|
|
|
|
|
state_dynamic.clients << r->info;
|
|
|
|
|
}
|
|
|
|
|
state_dynamic.devices.clear();
|
|
|
|
|
PIVector<PIIODevice *> devs = RUNTIME->connection.boundedDevices();
|
|
|
|
|
for (PIIODevice * d: devs) {
|
|
|
|
|
if (!d) continue;
|
|
|
|
|
ServerDeviceInfo di;
|
|
|
|
|
di.classname = QLatin1String(d->className());
|
|
|
|
|
di.path = PI2QString(d->path());
|
|
|
|
|
di.mode = d->mode();
|
|
|
|
|
PIDiagnostics * diag = RUNTIME->connection.diagnostic(d);
|
|
|
|
|
if (diag) {
|
|
|
|
|
di.sended_bytes = diag->state().sended_bytes;
|
|
|
|
|
di.received_bytes = diag->state().received_bytes;
|
|
|
|
|
di.send_speed = PI2QString(diag->sendSpeed());
|
|
|
|
|
di.receive_speed = PI2QString(diag->receiveSpeed());
|
|
|
|
|
}
|
|
|
|
|
state_dynamic.devices << di;
|
|
|
|
|
}
|
|
|
|
|
for (auto & v: state_dynamic.variables) {
|
|
|
|
|
auto val = engine.getVariableValue(v.name);
|
|
|
|
|
v.changed = val.first;
|
|
|
|
|
v.value = val.second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PIByteArray msg_state;
|
|
|
|
|
msg_state = SHNetworkTypes::makeHeader(SHNetworkTypes::AdminDynamicState);
|
|
|
|
|
msg_state << state_dynamic;
|
|
|
|
|
|
|
|
|
|
for (ServerClient * r: rl) {
|
|
|
|
|
if (!r) continue;
|
|
|
|
|
|
|
|
|
|
if (r->info.role == SHServer::RoleMessages) {
|
|
|
|
|
for (const auto & m: mq) {
|
|
|
|
|
PIByteArray ba = SHNetworkTypes::makeHeader(SHNetworkTypes::Message);
|
|
|
|
|
ba << m;
|
|
|
|
|
r->queueSend(ba);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->info.role == SHServer::RoleAdmin) {
|
|
|
|
|
if (!r->log_sended) {
|
|
|
|
|
r->log_sended = true;
|
|
|
|
|
pck_log_hist.entries = admin_log_history;
|
|
|
|
|
PIByteArray msg = SHNetworkTypes::makeHeader(SHNetworkTypes::AdminLog);
|
|
|
|
|
msg << pck_log_hist;
|
|
|
|
|
r->queueSend(msg);
|
|
|
|
|
}
|
|
|
|
|
if (!msg_state.isEmpty()) r->queueSend(msg_state);
|
|
|
|
|
if (!pck_log.entries.isEmpty() || !r->admin_io_log.isEmpty()) {
|
|
|
|
|
PacketServerLog pckt;
|
|
|
|
|
pckt.entries << pck_log.entries << r->admin_io_log;
|
|
|
|
|
pckt.entries.sort([](const LogEntry & t0, const LogEntry & t1) { return t0.time < t1.time; });
|
|
|
|
|
r->admin_io_log.clear();
|
|
|
|
|
PIByteArray msg = SHNetworkTypes::makeHeader(SHNetworkTypes::AdminLog);
|
|
|
|
|
msg << pckt;
|
|
|
|
|
r->queueSend(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rmutex.unlock();
|
|
|
|
|
|
|
|
|
|
for (const auto & e: pck_log.entries) {
|
|
|
|
|
admin_log_cur_size += e.text.size();
|
|
|
|
|
admin_log_history << e;
|
|
|
|
|
while (admin_log_cur_size > admin_log_max_size)
|
|
|
|
|
admin_log_cur_size -= admin_log_history.take_front().text.size();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::syncServers() {
|
|
|
|
|
if (with_reservation) {
|
|
|
|
|
smutex.lock();
|
|
|
|
|
if (server_state > ServerCore::ssSync) {
|
|
|
|
|
for (int i = 0; i < servers.size_s(); ++i) {
|
|
|
|
|
servers[i].missed++;
|
|
|
|
|
if (servers[i].missed > 10) {
|
|
|
|
|
piCoutObj << "remove by timeout" << servers[i].seed;
|
|
|
|
|
if (servers[i].seed == seed_main) selectNewMain();
|
|
|
|
|
servers.remove(i);
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
smutex.unlock();
|
|
|
|
|
if (sync_skip > 0) {
|
|
|
|
|
sync_skip--;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (server_state) {
|
|
|
|
|
case ServerCore::ssStart: {
|
|
|
|
|
PIByteArray sba = SHNetworkTypes::makeHeader(SHNetworkTypes::ServerNew);
|
|
|
|
|
sba << seed;
|
|
|
|
|
piCoutObj << "send ServerNew seed =" << seed << ", ip =" << my_ip;
|
|
|
|
|
send(sba);
|
|
|
|
|
selectNewMain();
|
|
|
|
|
} break;
|
|
|
|
|
case ServerCore::ssSync:
|
|
|
|
|
if (seed_main == 0) {
|
|
|
|
|
int mseed = seed;
|
|
|
|
|
int mi = -1;
|
|
|
|
|
smutex.lock();
|
|
|
|
|
for (int i = 0; i < servers.size_s(); ++i) {
|
|
|
|
|
if (mseed > servers[i].seed) {
|
|
|
|
|
mseed = servers[i].seed;
|
|
|
|
|
mi = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
smutex.unlock();
|
|
|
|
|
seed_main = mseed;
|
|
|
|
|
main_ip = PINetworkAddress(mseed, 0).ipString();
|
|
|
|
|
if (mi < 0)
|
|
|
|
|
startAsMain();
|
|
|
|
|
else
|
|
|
|
|
startAsReserve();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ServerCore::ssWorkReserve:
|
|
|
|
|
main_missed++;
|
|
|
|
|
if (main_missed > 10) {
|
|
|
|
|
main_missed = 0;
|
|
|
|
|
selectNewMain();
|
|
|
|
|
}
|
|
|
|
|
case ServerCore::ssWorkMain: {
|
|
|
|
|
PIByteArray sba = SHNetworkTypes::makeHeader(SHNetworkTypes::ServerPing);
|
|
|
|
|
sba << seed;
|
|
|
|
|
// piCoutObj << "send ServerPing seed =" << seed;
|
|
|
|
|
send(sba);
|
|
|
|
|
} break;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
startAsMain();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::procClients() {
|
|
|
|
|
PIMutexLocker ml(rmutex);
|
|
|
|
|
|
|
|
|
|
sync.buildDiffForRoles();
|
|
|
|
|
|
|
|
|
|
PIVector<ServerClient *> rl = remotes.values(), to_remove;
|
|
|
|
|
for (ServerClient * r: rl) {
|
|
|
|
|
bool disconn = !r->isConnected();
|
|
|
|
|
if (r) {
|
|
|
|
|
if (r->tcp->wasError()) disconn = true;
|
|
|
|
|
}
|
|
|
|
|
if (disconn) {
|
|
|
|
|
log("Client " + PI2QString(r->device->path()) + " disconnected", SHServer::LogInfo);
|
|
|
|
|
// piCout << "disconn ...";
|
|
|
|
|
r->close();
|
|
|
|
|
// piCout << "disconn close";
|
|
|
|
|
if (df_client == r) {
|
|
|
|
|
df_client = 0;
|
|
|
|
|
df_device.clear();
|
|
|
|
|
engine.connection()->setInactive(false);
|
|
|
|
|
}
|
|
|
|
|
to_remove << r;
|
|
|
|
|
// piCout << "disconn done";
|
|
|
|
|
}
|
|
|
|
|
r->maybeCallQueuedEvents();
|
|
|
|
|
r->updateInfo();
|
|
|
|
|
if (!r->tcp || !r->active || (r->info.role != SHServer::RoleGui)) continue;
|
|
|
|
|
PIByteArray diff;
|
|
|
|
|
if (r->role_changed) {
|
|
|
|
|
diff = Q2PIByteArray(sync.buildTransitionDiff(r->user_role, r->new_user_role));
|
|
|
|
|
// qDebug() << "send transitional diff" << r->user_role << "->" << r->new_user_role << diff.size();
|
|
|
|
|
r->newRoleDone();
|
|
|
|
|
if (!diff.isEmpty()) {
|
|
|
|
|
diff.insert(0, SHNetworkTypes::makeHeader(SHNetworkTypes::GuiSyncDiff));
|
|
|
|
|
r->queueSend(diff);
|
|
|
|
|
}
|
|
|
|
|
diff.clear();
|
|
|
|
|
}
|
|
|
|
|
diff = sync.diffForRole(r->user_role);
|
|
|
|
|
if (!diff.isEmpty()) {
|
|
|
|
|
diff.insert(0, SHNetworkTypes::makeHeader(SHNetworkTypes::GuiSyncDiff));
|
|
|
|
|
r->queueSend(diff);
|
|
|
|
|
}
|
|
|
|
|
// piCout << "diff role" << r->user_role << diff.size();
|
|
|
|
|
}
|
|
|
|
|
for (ServerClient * r: to_remove) {
|
|
|
|
|
remotes.remove(r->device);
|
|
|
|
|
r->close();
|
|
|
|
|
rcq_mutex.lock();
|
|
|
|
|
delete_clients_queue.enqueue(r);
|
|
|
|
|
rcq_mutex.unlock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::deleteOldClients() {
|
|
|
|
|
rcq_mutex.lock();
|
|
|
|
|
auto del_queue = delete_clients_queue;
|
|
|
|
|
delete_clients_queue.clear();
|
|
|
|
|
rcq_mutex.unlock();
|
|
|
|
|
for (auto * r: del_queue) {
|
|
|
|
|
piCoutObj << "delete" << (uintptr_t)r << "...";
|
|
|
|
|
r->destroy();
|
|
|
|
|
delete r->device;
|
|
|
|
|
delete r;
|
|
|
|
|
piCoutObj << "delete" << (uintptr_t)r << "done";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -668,14 +697,14 @@ void ServerCore::connDataReceivedEvent(QString from, QByteArray data) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::variableHistoryAdded(QString vname, QPair<QDateTime, double> value) {
|
|
|
|
|
//qDebug() << "history add" << vname;
|
|
|
|
|
// qDebug() << "history add" << vname;
|
|
|
|
|
SHS::PacketGraphicData gd(vname);
|
|
|
|
|
ullong time = value.first.toMSecsSinceEpoch();
|
|
|
|
|
gd.data << PIPair<ullong, double>(time, value.second);
|
|
|
|
|
PIByteArray ba = SHNetworkTypes::makeHeader(SHNetworkTypes::GraphicData);
|
|
|
|
|
ba << gd;
|
|
|
|
|
PIMutexLocker _ml(rmutex);
|
|
|
|
|
PIVector<ServerClient * > rl = remotes.values();
|
|
|
|
|
PIVector<ServerClient *> rl = remotes.values();
|
|
|
|
|
for (auto * r: rl)
|
|
|
|
|
if (r->tcp && r->active && r->info.role == SHServer::RoleGraphics) {
|
|
|
|
|
if (r->graphics.contains(vname)) {
|
|
|
|
|
@@ -687,14 +716,14 @@ void ServerCore::variableHistoryAdded(QString vname, QPair<QDateTime, double> va
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::receivedSH(PIByteArray data, uint rec_id) {
|
|
|
|
|
//piCout << "received" << data;
|
|
|
|
|
// piCout << "received" << data;
|
|
|
|
|
PacketHeader hdr = SHNetworkTypes::takeHeader(data);
|
|
|
|
|
if (hdr.type < 0) return;
|
|
|
|
|
//piCout << "received type" << hdr.type << rec_id << data.size();
|
|
|
|
|
// piCout << "received type" << hdr.type << rec_id << data.size();
|
|
|
|
|
int _seed;
|
|
|
|
|
PIString _ip;
|
|
|
|
|
PIByteArray ba;
|
|
|
|
|
//piCout << "received" << type;
|
|
|
|
|
// piCout << "received" << type;
|
|
|
|
|
if (with_reservation) {
|
|
|
|
|
switch ((SHNetworkTypes::MulticastType)hdr.type) {
|
|
|
|
|
case SHNetworkTypes::ServerNew:
|
|
|
|
|
@@ -729,8 +758,7 @@ void ServerCore::receivedSH(PIByteArray data, uint rec_id) {
|
|
|
|
|
smutex.lock();
|
|
|
|
|
for (int i = 0; i < servers.size_s(); ++i)
|
|
|
|
|
if (servers[i].seed == _seed) {
|
|
|
|
|
if (seed_main == _seed)
|
|
|
|
|
selectNewMain();
|
|
|
|
|
if (seed_main == _seed) selectNewMain();
|
|
|
|
|
servers.remove(i);
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
@@ -745,23 +773,21 @@ void ServerCore::receivedSH(PIByteArray data, uint rec_id) {
|
|
|
|
|
break;
|
|
|
|
|
case SHNetworkTypes::ServerPing:
|
|
|
|
|
data >> _seed;
|
|
|
|
|
if (seed_main == _seed)
|
|
|
|
|
main_missed = 0;
|
|
|
|
|
if (seed_main == _seed) main_missed = 0;
|
|
|
|
|
smutex.lock();
|
|
|
|
|
for (int i = 0; i < servers.size_s(); ++i)
|
|
|
|
|
if (servers[i].seed == _seed)
|
|
|
|
|
servers[i].missed = 0;
|
|
|
|
|
if (servers[i].seed == _seed) servers[i].missed = 0;
|
|
|
|
|
smutex.unlock();
|
|
|
|
|
//seed_main = _seed;
|
|
|
|
|
//piCoutObj << "recv ServerPing seed =" << _seed;
|
|
|
|
|
// seed_main = _seed;
|
|
|
|
|
// piCoutObj << "recv ServerPing seed =" << _seed;
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (server_state != ServerCore::ssWorkMain) return;
|
|
|
|
|
//piCout << "received type" << type << rec_id << data.size();
|
|
|
|
|
// piCout << "received type" << type << rec_id << data.size();
|
|
|
|
|
if (hdr.type == SHNetworkTypes::Request) {
|
|
|
|
|
//PIMutexLocker locker(mcast_mutex);
|
|
|
|
|
// PIMutexLocker locker(mcast_mutex);
|
|
|
|
|
PIStringList addresses;
|
|
|
|
|
data >> addresses;
|
|
|
|
|
PIString addr;
|
|
|
|
|
@@ -772,17 +798,16 @@ void ServerCore::receivedSH(PIByteArray data, uint rec_id) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!addr.isEmpty())
|
|
|
|
|
break;
|
|
|
|
|
if (!addr.isEmpty()) break;
|
|
|
|
|
}
|
|
|
|
|
//piCout << "return address" << addr;
|
|
|
|
|
// piCout << "return address" << addr;
|
|
|
|
|
PacketServerInfo info;
|
|
|
|
|
info.identify = PacketIdentification::makeLocal(0, SHS_NETWORK_VERSION, SHS_UISYNC_VERSION);
|
|
|
|
|
info.identify.hashes.hash_ui = ui_hash;
|
|
|
|
|
info.identify = PacketIdentification::makeLocal(0, SHS_NETWORK_VERSION, SHS_UISYNC_VERSION);
|
|
|
|
|
info.identify.hashes.hash_ui = ui_hash;
|
|
|
|
|
info.identify.hashes.hash_rcc = rcc_hash;
|
|
|
|
|
info.connect_address = addr;
|
|
|
|
|
info.name = server_name_;
|
|
|
|
|
PIByteArray sba = SHNetworkTypes::makeHeader(SHNetworkTypes::Reply);
|
|
|
|
|
info.connect_address = addr;
|
|
|
|
|
info.name = server_name_;
|
|
|
|
|
PIByteArray sba = SHNetworkTypes::makeHeader(SHNetworkTypes::Reply);
|
|
|
|
|
sba << info;
|
|
|
|
|
send(sba, rec_id);
|
|
|
|
|
}
|
|
|
|
|
@@ -799,36 +824,36 @@ void ServerCore::addressesChanged() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::newTCPConnection(PIEthernet * client) {
|
|
|
|
|
//piCout << "newConnection" << client;
|
|
|
|
|
// piCout << "newConnection" << client;
|
|
|
|
|
log("Client connected from " + PI2QString(client->path()) + " (TCP)", SHServer::LogInfo);
|
|
|
|
|
client->setDebug(false);
|
|
|
|
|
client->setReadTimeout(60000.);
|
|
|
|
|
client->setWriteTimeout(60000.);
|
|
|
|
|
client->setParameter(PIEthernet::DisonnectOnTimeout, false);
|
|
|
|
|
ServerClient * r = new ServerClient(this, SHNetworkTypes::TCP);
|
|
|
|
|
//CONNECTU(r, packetReceived, this, packetReceived)
|
|
|
|
|
// CONNECTU(r, packetReceived, this, packetReceived)
|
|
|
|
|
r->init(client);
|
|
|
|
|
//piCout << "newConnection lock ...";
|
|
|
|
|
// piCout << "newConnection lock ...";
|
|
|
|
|
rmutex.lock();
|
|
|
|
|
remotes[client] = r;
|
|
|
|
|
rmutex.unlock();
|
|
|
|
|
client->startThreadedRead();
|
|
|
|
|
//piCout << "newConnection lock done";
|
|
|
|
|
// piCout << "newConnection lock done";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::newCloudConnection(PICloudServer::Client * client) {
|
|
|
|
|
piCout << "newCloudConnection" << client;
|
|
|
|
|
log("Client connected from " + PI2QString(client->path()) + " (Cloud)", SHServer::LogInfo);
|
|
|
|
|
//client->setDebug(false);
|
|
|
|
|
// client->setDebug(false);
|
|
|
|
|
ServerClient * r = new ServerClient(this, SHNetworkTypes::Cloud);
|
|
|
|
|
//CONNECTU(r, packetReceived, this, packetReceived)
|
|
|
|
|
// CONNECTU(r, packetReceived, this, packetReceived)
|
|
|
|
|
r->init(client);
|
|
|
|
|
//piCout << "newConnection lock ...";
|
|
|
|
|
// piCout << "newConnection lock ...";
|
|
|
|
|
rmutex.lock();
|
|
|
|
|
remotes[client] = r;
|
|
|
|
|
rmutex.unlock();
|
|
|
|
|
//piCout << "newConnection lock done";
|
|
|
|
|
// piCout << "newConnection lock done";
|
|
|
|
|
client->startThreadedRead();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -837,15 +862,15 @@ void ServerCore::receivedIdentification(ServerClient * r, PIByteArray data) {
|
|
|
|
|
PIByteArray ba;
|
|
|
|
|
PacketIdentification p;
|
|
|
|
|
data >> p;
|
|
|
|
|
r->id = r->tcp->lastRecID();
|
|
|
|
|
r->info.id = r->id;
|
|
|
|
|
r->info.OS_type = (SHPlatform::OSType)p.os_type;
|
|
|
|
|
r->info.OS_arch = PI2QString(p.arch);
|
|
|
|
|
r->id = r->tcp->lastRecID();
|
|
|
|
|
r->info.id = r->id;
|
|
|
|
|
r->info.OS_type = (SHPlatform::OSType)p.os_type;
|
|
|
|
|
r->info.OS_arch = PI2QString(p.arch);
|
|
|
|
|
r->info.OS_version = PI2QString(p.os_version);
|
|
|
|
|
r->info.hostname = PI2QString(p.hostname);
|
|
|
|
|
r->info.role = (SHServer::ClientRole)p.role;
|
|
|
|
|
r->info.hostname = PI2QString(p.hostname);
|
|
|
|
|
r->info.role = (SHServer::ClientRole)p.role;
|
|
|
|
|
|
|
|
|
|
r->net_version = p.net_version;
|
|
|
|
|
r->net_version = p.net_version;
|
|
|
|
|
if (r->net_version != SHS_NETWORK_VERSION) {
|
|
|
|
|
qDebug() << "invalid network version" << r->net_version;
|
|
|
|
|
log(tr("Client \"%1\" invalid network version: %2!").arg(r->info.hostname).arg(r->net_version), SHServer::LogWarning);
|
|
|
|
|
@@ -879,13 +904,13 @@ void ServerCore::receivedIdentification(ServerClient * r, PIByteArray data) {
|
|
|
|
|
sendInitialAdminData(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//piCoutObj << "my" << ui_hash << rcc_hash;
|
|
|
|
|
//piCoutObj << "cl" << p.hashes.hash_ui << p.hashes.hash_rcc;
|
|
|
|
|
r->upload_ui = (p.hashes.hash_ui != ui_hash);
|
|
|
|
|
// piCoutObj << "my" << ui_hash << rcc_hash;
|
|
|
|
|
// piCoutObj << "cl" << p.hashes.hash_ui << p.hashes.hash_rcc;
|
|
|
|
|
r->upload_ui = (p.hashes.hash_ui != ui_hash);
|
|
|
|
|
r->upload_rcc = (p.hashes.hash_rcc != rcc_hash);
|
|
|
|
|
r->tcp->setCheckHeader(true);
|
|
|
|
|
r->tcp->setID(r->id);
|
|
|
|
|
//qDebug() << "ident" << int(r->info.OS_type) << r->info.OS_arch << r->info.OS_version;
|
|
|
|
|
// qDebug() << "ident" << int(r->info.OS_type) << r->info.OS_arch << r->info.OS_version;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -903,16 +928,15 @@ void ServerCore::receivedKey(ServerClient * r, PIByteArray data) {
|
|
|
|
|
PIString key;
|
|
|
|
|
data >> key;
|
|
|
|
|
bool ok = (key == server_key_);
|
|
|
|
|
ba = SHNetworkTypes::makeHeader(SHNetworkTypes::KeyProbeResult);
|
|
|
|
|
ba = SHNetworkTypes::makeHeader(SHNetworkTypes::KeyProbeResult);
|
|
|
|
|
ba << uchar(ok ? 1 : 0);
|
|
|
|
|
piCout << "received key" << key;
|
|
|
|
|
r->tcp->send(ba);
|
|
|
|
|
if (ok) {
|
|
|
|
|
|
|
|
|
|
if (r->upload_rcc) {
|
|
|
|
|
ba = SHNetworkTypes::makeHeader(SHNetworkTypes::GuiSyncRCC);
|
|
|
|
|
ba.append(bqr_content);
|
|
|
|
|
//qDebug() << "send rcc" << int(SHNetworkTypes::GuiSyncRCC) << bqr_content.size();
|
|
|
|
|
// qDebug() << "send rcc" << int(SHNetworkTypes::GuiSyncRCC) << bqr_content.size();
|
|
|
|
|
} else {
|
|
|
|
|
ba = SHNetworkTypes::makeHeader(SHNetworkTypes::GuiRestoreRCC);
|
|
|
|
|
}
|
|
|
|
|
@@ -924,11 +948,11 @@ void ServerCore::receivedKey(ServerClient * r, PIByteArray data) {
|
|
|
|
|
} else {
|
|
|
|
|
ba = SHNetworkTypes::makeHeader(SHNetworkTypes::GuiRestoreUI);
|
|
|
|
|
}
|
|
|
|
|
//qDebug() << "send ui" << int(SHNetworkTypes::GuiSyncUI) << ba.size();
|
|
|
|
|
// qDebug() << "send ui" << int(SHNetworkTypes::GuiSyncUI) << ba.size();
|
|
|
|
|
r->queueSend(ba);
|
|
|
|
|
|
|
|
|
|
ba = Q2PIByteArray(sync.buildFullDiffForRole(r->user_role));
|
|
|
|
|
//qDebug() << "send init diff" << r->user_role << ba.size();
|
|
|
|
|
// qDebug() << "send init diff" << r->user_role << ba.size();
|
|
|
|
|
if (!ba.isEmpty()) {
|
|
|
|
|
PIByteArray hdr = SHNetworkTypes::makeHeader(SHNetworkTypes::GuiSyncDiff);
|
|
|
|
|
ba.insert(0, hdr);
|
|
|
|
|
@@ -938,14 +962,14 @@ void ServerCore::receivedKey(ServerClient * r, PIByteArray data) {
|
|
|
|
|
ba = SHNetworkTypes::makeHeader(SHNetworkTypes::ConnectingDone);
|
|
|
|
|
r->queueSend(ba);
|
|
|
|
|
|
|
|
|
|
//r->active = true;
|
|
|
|
|
// r->active = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerCore::sendToAll(const PIByteArray & data, SHServer::ClientRole role, bool no_check) {
|
|
|
|
|
PIMutexLocker _ml(rmutex);
|
|
|
|
|
PIVector<ServerClient * > rl = remotes.values();
|
|
|
|
|
PIVector<ServerClient *> rl = remotes.values();
|
|
|
|
|
for (ServerClient * r: rl) {
|
|
|
|
|
qDebug() << r << r->tcp << r->active << r->info.role;
|
|
|
|
|
if (!r->tcp || r->info.role != role) continue;
|
|
|
|
|
@@ -967,7 +991,7 @@ void ServerCore::sendInitialAdminData(ServerClient * r) {
|
|
|
|
|
while (it.next()) {
|
|
|
|
|
if (it.value().isLoaded()) {
|
|
|
|
|
PacketServerPlugin plugin;
|
|
|
|
|
plugin.name = it.key();
|
|
|
|
|
plugin.name = it.key();
|
|
|
|
|
plugin.version = it.value().manifest.fullVersion();
|
|
|
|
|
plugins << plugin;
|
|
|
|
|
}
|
|
|
|
|
@@ -1009,14 +1033,14 @@ void ServerCore::message(const QString & text, int type) {
|
|
|
|
|
void ServerCore::scriptError(int line, QString file, QString message, QString stack) {
|
|
|
|
|
if (lqs_err_line == line && lqs_err_msg == message) return;
|
|
|
|
|
lqs_err_line = line;
|
|
|
|
|
lqs_err_msg = message;
|
|
|
|
|
lqs_err_msg = message;
|
|
|
|
|
log(QString("Script error, %1:%2: %3\n%4").arg(file).arg(line).arg(message, stack), SHServer::LogError);
|
|
|
|
|
PIByteArray msg = SHNetworkTypes::makeHeader(SHNetworkTypes::AdminScriptError);
|
|
|
|
|
PacketScriptError se;
|
|
|
|
|
se.message = message;
|
|
|
|
|
se.stack = stack;
|
|
|
|
|
se.file = file;
|
|
|
|
|
se.line = line;
|
|
|
|
|
se.stack = stack;
|
|
|
|
|
se.file = file;
|
|
|
|
|
se.line = line;
|
|
|
|
|
se.project = PI2QString(server_name_);
|
|
|
|
|
msg << se;
|
|
|
|
|
sendToAll(msg, SHServer::RoleAdmin, true);
|
|
|
|
|
@@ -1040,7 +1064,7 @@ void ServerCore::IOLog(QString text) {
|
|
|
|
|
e.text = text;
|
|
|
|
|
e.type = SHServer::LogIO;
|
|
|
|
|
rmutex.lock();
|
|
|
|
|
PIVector<ServerClient * > rl = remotes.values();
|
|
|
|
|
PIVector<ServerClient *> rl = remotes.values();
|
|
|
|
|
for (ServerClient * r: rl) {
|
|
|
|
|
if (!r) continue;
|
|
|
|
|
if ((r->info.role != SHServer::RoleAdmin) || !r->admin_log_io) continue;
|
|
|
|
|
|