mirror of
https://github.com/uroni/urbackup_backend.git
synced 2025-10-26 11:36:50 +00:00
637 lines
15 KiB
C++
637 lines
15 KiB
C++
/*************************************************************************
|
|
* UrBackup - Client/Server backup system
|
|
* Copyright (C) 2011-2016 Martin Raiber
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
**************************************************************************/
|
|
|
|
#ifndef CLIENT_ONLY
|
|
|
|
#include "server_status.h"
|
|
#include "../Interface/Server.h"
|
|
#include "../Interface/Pipe.h"
|
|
#include "action_header.h"
|
|
#include <time.h>
|
|
#include <algorithm>
|
|
#include <assert.h>
|
|
|
|
IMutex *ServerStatus::mutex=NULL;
|
|
std::map<std::string, SStatus> ServerStatus::status;
|
|
int64 ServerStatus::last_status_update;
|
|
size_t ServerStatus::curr_process_id = 0;
|
|
|
|
|
|
int ServerStatus::server_nospc_stalled=0;
|
|
bool ServerStatus::server_nospc_fatal=false;
|
|
|
|
const unsigned int inactive_time_const=30*60*1000;
|
|
|
|
void ServerStatus::init_mutex(void)
|
|
{
|
|
mutex=Server->createMutex();
|
|
last_status_update=Server->getTimeMS();
|
|
}
|
|
|
|
void ServerStatus::destroy_mutex(void)
|
|
{
|
|
Server->destroy(mutex);
|
|
}
|
|
|
|
void ServerStatus::updateActive(void)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
last_status_update=Server->getTimeMS();
|
|
}
|
|
|
|
void ServerStatus::setOnline(const std::string &clientname, bool bonline)
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
if(bonline)
|
|
{
|
|
*s=SStatus();
|
|
}
|
|
s->online=bonline;
|
|
s->client=clientname;
|
|
s->has_status=true;
|
|
s->r_online=bonline;
|
|
if(bonline)
|
|
{
|
|
last_status_update=Server->getTimeMS();
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setROnline(const std::string &clientname, bool bonline)
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->r_online=bonline;
|
|
if(bonline)
|
|
{
|
|
last_status_update=Server->getTimeMS();
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setIP(const std::string &clientname, unsigned int ip)
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->ip_addr=ip;
|
|
}
|
|
|
|
void ServerStatus::setStatusError(const std::string &clientname, SStatusError se)
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->status_error=se;
|
|
}
|
|
|
|
void ServerStatus::setCommPipe(const std::string &clientname, IPipe *p)
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->comm_pipe=p;
|
|
}
|
|
|
|
void ServerStatus::stopProcess(const std::string &clientname, size_t id, bool b)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
if(proc!=NULL)
|
|
{
|
|
proc->stop=true;
|
|
}
|
|
}
|
|
|
|
bool ServerStatus::isProcessStopped(const std::string &clientname, size_t id)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
if(proc!=NULL)
|
|
{
|
|
return proc->stop;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::vector<SStatus> ServerStatus::getStatus(void)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
std::vector<SStatus> ret;
|
|
for(std::map<std::string, SStatus>::iterator it=status.begin();it!=status.end();++it)
|
|
{
|
|
ret.push_back(it->second);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
SStatus ServerStatus::getStatus(const std::string &clientname)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
std::map<std::string, SStatus>::iterator iter=status.find(clientname);
|
|
if(iter!=status.end())
|
|
return iter->second;
|
|
else
|
|
return SStatus();
|
|
}
|
|
|
|
bool ServerStatus::isActive(void)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
if( Server->getTimeMS()-last_status_update>inactive_time_const)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::resetServerNospcStalled()
|
|
{
|
|
IScopedLock lock(mutex);
|
|
server_nospc_stalled = 0;
|
|
}
|
|
|
|
void ServerStatus::incrementServerNospcStalled(int add)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
server_nospc_stalled+=add;
|
|
}
|
|
|
|
void ServerStatus::setServerNospcFatal(bool b)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
server_nospc_fatal=b;
|
|
}
|
|
|
|
int ServerStatus::getServerNospcStalled(void)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
return server_nospc_stalled;
|
|
}
|
|
|
|
bool ServerStatus::getServerNospcFatal(void)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
return server_nospc_fatal;
|
|
}
|
|
|
|
void ServerStatus::setClientVersionString(const std::string &clientname, const std::string& client_version_string)
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->client_version_string=client_version_string;
|
|
}
|
|
|
|
void ServerStatus::setOSVersionString(const std::string &clientname, const std::string& os_version_string)
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->os_version_string=os_version_string;
|
|
}
|
|
|
|
bool ServerStatus::sendToCommPipe( const std::string &clientname, const std::string& msg )
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
if(s->comm_pipe==NULL)
|
|
return false;
|
|
|
|
s->comm_pipe->Write(msg);
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t ServerStatus::startProcess( const std::string &clientname, SStatusAction action,
|
|
const std::string& details, logid_t logid, bool can_stop, int clientid)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
|
|
if (s->client.empty())
|
|
{
|
|
s->client = clientname;
|
|
}
|
|
|
|
if (s->clientid == 0)
|
|
{
|
|
s->clientid = clientid;
|
|
}
|
|
|
|
SProcess new_proc(++curr_process_id, action, details);
|
|
new_proc.logid = logid;
|
|
new_proc.can_stop = can_stop;
|
|
s->processes.push_back(new_proc);
|
|
|
|
return new_proc.id;
|
|
}
|
|
|
|
bool ServerStatus::stopProcess( const std::string &clientname, size_t id )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
|
|
std::vector<SProcess>::iterator it = std::find(s->processes.begin(), s->processes.end(), SProcess(id, sa_none, std::string()));
|
|
|
|
if(it!=s->processes.end())
|
|
{
|
|
s->processes.erase(it);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ServerStatus::changeProcess(const std::string & clientname, size_t id, SStatusAction action)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SStatus *s = &status[clientname];
|
|
|
|
std::vector<SProcess>::iterator it = std::find(s->processes.begin(), s->processes.end(), SProcess(id, sa_none, std::string()));
|
|
|
|
if (it != s->processes.end())
|
|
{
|
|
it->action = action;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SProcess* ServerStatus::getProcessInt( const std::string &clientname, size_t id )
|
|
{
|
|
SStatus *s=&status[clientname];
|
|
|
|
std::vector<SProcess>::iterator it = std::find(s->processes.begin(), s->processes.end(), SProcess(id, sa_none, std::string()));
|
|
|
|
if(it!=s->processes.end())
|
|
{
|
|
return &(*it);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessQueuesize( const std::string &clientname, size_t id, unsigned int prepare_hashqueuesize, unsigned int hashqueuesize )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if(proc!=NULL)
|
|
{
|
|
proc->prepare_hashqueuesize = prepare_hashqueuesize;
|
|
proc->hashqueuesize = hashqueuesize;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessStarttime( const std::string &clientname, size_t id, int64 starttime )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if(proc!=NULL)
|
|
{
|
|
proc->starttime = starttime;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessEta( const std::string &clientname, size_t id, int64 eta_ms, int64 eta_set_time )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if(proc!=NULL)
|
|
{
|
|
proc->eta_ms = eta_ms;
|
|
proc->eta_set_time = eta_set_time;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessEta( const std::string &clientname, size_t id, int64 eta_ms )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if(proc!=NULL)
|
|
{
|
|
proc->eta_ms = eta_ms;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessSpeed(const std::string &clientname, size_t id, double speed_bpms)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if (proc != NULL)
|
|
{
|
|
proc->past_speed_bpms.push_back(proc->speed_bpms);
|
|
while (proc->past_speed_bpms.size() >= 20)
|
|
{
|
|
proc->past_speed_bpms.pop_front();
|
|
}
|
|
proc->speed_bpms = speed_bpms;
|
|
}
|
|
}
|
|
|
|
bool ServerStatus::removeStatus( const std::string &clientname )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
|
|
std::map<std::string, SStatus>::iterator it=status.find(clientname);
|
|
|
|
if(it!=status.end())
|
|
{
|
|
status.erase(it);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessPcDone( const std::string &clientname, size_t id, int pcdone )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if(proc!=NULL)
|
|
{
|
|
proc->pcdone = pcdone;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessTotalBytes(const std::string & clientname, size_t id, int64 total_bytes)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if (proc != NULL)
|
|
{
|
|
proc->total_bytes = total_bytes;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessDoneBytes(const std::string & clientname, size_t id, int64 done_bytes)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if (proc != NULL)
|
|
{
|
|
proc->done_bytes = done_bytes;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessDoneBytes(const std::string & clientname, size_t id, int64 done_bytes, int64 total_bytes)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if (proc != NULL)
|
|
{
|
|
proc->done_bytes = done_bytes;
|
|
proc->total_bytes = total_bytes;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessDetails(const std::string & clientname, size_t id,
|
|
std::string details, int detail_pc)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if (proc != NULL)
|
|
{
|
|
proc->details = details;
|
|
proc->detail_pc = detail_pc;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessPaused(const std::string & clientname, size_t id, bool b)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if (proc != NULL)
|
|
{
|
|
proc->paused = b;
|
|
}
|
|
}
|
|
|
|
SProcess ServerStatus::getProcess( const std::string &clientname, size_t id )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
if(proc!=NULL)
|
|
{
|
|
return *proc;
|
|
}
|
|
else
|
|
{
|
|
return SProcess(0, sa_none, std::string());
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setProcessEtaSetTime( const std::string &clientname, size_t id, int64 eta_set_time )
|
|
{
|
|
IScopedLock lock(mutex);
|
|
SProcess* proc = getProcessInt(clientname, id);
|
|
|
|
if(proc!=NULL)
|
|
{
|
|
proc->eta_set_time = eta_set_time;
|
|
}
|
|
}
|
|
|
|
void ServerStatus::setClientId( const std::string &clientname, int clientid)
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->clientid = clientid;
|
|
}
|
|
|
|
void ServerStatus::addRunningJob( const std::string &clientname )
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->running_jobs+=1;
|
|
}
|
|
|
|
void ServerStatus::subRunningJob( const std::string &clientname )
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->running_jobs-=1;
|
|
}
|
|
|
|
int ServerStatus::numRunningJobs( const std::string &clientname )
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
return s->running_jobs;
|
|
}
|
|
|
|
void ServerStatus::setRestore( const std::string &clientname, ERestore restore )
|
|
{
|
|
assert(!clientname.empty());
|
|
|
|
IScopedLock lock(mutex);
|
|
SStatus *s=&status[clientname];
|
|
s->restore = restore;
|
|
}
|
|
|
|
bool ServerStatus::canRestore( const std::string &clientname, bool& server_confirms)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
std::map<std::string, SStatus>::iterator it=status.find(clientname);
|
|
if(it==status.end())
|
|
{
|
|
return false;
|
|
}
|
|
SStatus* s=&it->second;
|
|
server_confirms = s->restore==ERestore_server_confirms;
|
|
return s->online && s->r_online && s->restore!=ERestore_disabled;
|
|
}
|
|
|
|
void ServerStatus::updateLastseen(const std::string & clientname)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
std::map<std::string, SStatus>::iterator it = status.find(clientname);
|
|
if (it == status.end())
|
|
{
|
|
return;
|
|
}
|
|
it->second.lastseen = Server->getTimeSeconds();
|
|
}
|
|
|
|
int64 ServerStatus::getLastseen(const std::string & clientname)
|
|
{
|
|
IScopedLock lock(mutex);
|
|
std::map<std::string, SStatus>::iterator it = status.find(clientname);
|
|
if (it == status.end())
|
|
{
|
|
return 0;
|
|
}
|
|
return it->second.lastseen;
|
|
}
|
|
|
|
ACTION_IMPL(server_status)
|
|
{
|
|
#ifndef _DEBUG
|
|
Server->Write(tid, "Forbidden");
|
|
#else
|
|
ITemplate *tmpl=Server->createTemplate("urbackup/status.htm");
|
|
|
|
std::vector<SStatus> status=ServerStatus::getStatus();
|
|
|
|
tmpl->getTable("CLIENTS");
|
|
|
|
for(size_t i=0;i<status.size();++i)
|
|
{
|
|
/*ITable *tab=tmpl->getTable(L"CLIENTS."+convert(i));
|
|
tab->addString(L"NAME", status[i].client );
|
|
if(status[i].has_status)
|
|
{
|
|
tab->addString(L"PCDONE", convert(status[i].pcdone) );
|
|
tab->addString(L"HASHQUEUESIZE", convert(status[i].hashqueuesize) );
|
|
tab->addString(L"HASHQUEUE_PREPARE", convert(status[i].prepare_hashqueuesize) );
|
|
tab->addString(L"ONLINE", convert(status[i].online) );
|
|
|
|
time_t tt=(time_t)(time(0)-((Server->getTimeMS()-status[i].starttime)/1000));
|
|
#ifdef _WIN32
|
|
struct tm ttm;
|
|
localtime_s(&ttm, &tt);
|
|
char buf[1000];
|
|
strftime(buf, 1000, "%d.%m.%Y %H:%M", &ttm);
|
|
#else
|
|
struct tm *ttm=localtime(&tt);
|
|
char buf[1000];
|
|
strftime(buf, 1000, "%d.%m.%Y %H:%M", ttm);
|
|
#endif
|
|
|
|
tab->addString(L"STARTTIME", widen((std::string)buf) );
|
|
tab->addString(L"DONE", convert(status[i].done) );
|
|
std::string action;
|
|
switch(status[i].statusaction)
|
|
{
|
|
case sa_none:
|
|
action=L"none"; break;
|
|
case sa_incr_file:
|
|
action=L"incr_file"; break;
|
|
case sa_full_file:
|
|
action=L"full_file"; break;
|
|
case sa_incr_image:
|
|
action=L"incr_image"; break;
|
|
case sa_full_image:
|
|
action=L"full_image"; break;
|
|
case sa_resume_full_file:
|
|
action=L"resume_full_file"; break;
|
|
case sa_resume_incr_file:
|
|
action=L"resume_incr_file"; break;
|
|
}
|
|
tab->addString(L"ACTION", action);
|
|
}
|
|
else
|
|
{
|
|
tab->addString(L"PCDONE", L" ");
|
|
tab->addString(L"HASHQUEUESIZE", L" ");
|
|
tab->addString(L"HASHQUEUE_PREPARE", L" ");
|
|
tab->addString(L"ONLINE", convert(status[i].online));
|
|
tab->addString(L"STARTTIME", L" ");
|
|
tab->addString(L"DONE", L" ");
|
|
tab->addString(L"ACTION", L" ");
|
|
}*/
|
|
}
|
|
|
|
Server->Write(tid, tmpl->getData());
|
|
Server->destroy(tmpl);
|
|
#endif
|
|
}
|
|
|
|
#endif //CLIENT_ONLY
|