// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// 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 .
//-------------------------------------------------------------------------------------------------
// includes
//-------------------------------------------------------------------------------------------------
#include "stdpch.h"
#include "_backup_service_interface_singleton.h"
#include "utils.h"
//-------------------------------------------------------------------------------------------------
// namespaces
//-------------------------------------------------------------------------------------------------
using namespace std;
using namespace NLNET;
using namespace NLMISC;
//-------------------------------------------------------------------------------------------------
// const FileNameValidator
//-------------------------------------------------------------------------------------------------
// little class designed to test validity of file names in a reasonably rapid manor
class CFileNameValidator
{
public:
// setup the set of valid characters for the file name
CFileNameValidator()
{
memset(&_Data,0,sizeof(_Data));
for (uint32 i='A'; i<='Z';++i) _Data[i]= true;
for (uint32 i='a'; i<='z';++i) _Data[i]= true;
for (uint32 i='0'; i<='9';++i) _Data[i]= true;
_Data['/']= true;
_Data['.']= true;
_Data['_']= true;
_Data[' ']= true;
}
// lookup a character to determine whether it's valid or not
bool operator[](char c) const
{
return _Data[(uint8)c];
}
// check all of the characters in a file name to ensure that it is valid
// return true if the file name is ok, otherwise false
bool checkFileName(const std::string& fileName) const
{
for (uint32 i=(uint32)fileName.size();i--;)
{
if (operator[](fileName[i])==true)
continue;
nlwarning("FileNameValidator: refusing character '%c' (%u) in file name: %s",fileName[i],fileName[i],fileName.c_str());
return false;
}
return true;
}
private:
// private data
bool _Data[256];
};
// a constant instance of the validator class
static const CFileNameValidator FileNameValidator;
//-------------------------------------------------------------------------------------------------
// methods & globals CBackupMsgSaveFile
//-------------------------------------------------------------------------------------------------
CBackupMsgSaveFile::CBackupMsgSaveFile( const std::string& filename, TBackupMsgSaveFileType msgType, const CBackupServiceInterface& itf )
{
//DataMsg.setType( getConversionTable().toString( msgType ) );
DataMsg.setType( _TypesStr[msgType] );
string pathFilename = itf.getRemotePath() + filename;
DataMsg.serial( pathFilename );
FileName = filename; // the filename with no heading remote path
_MsgType = msgType;
}
const char *CBackupMsgSaveFile::_TypesStr [CBackupMsgSaveFile::NbTypes] =
{
"save_file",
"SAVE_CHECK_FILE",
"append_file",
"append_file_check",
};
//-------------------------------------------------------------------------------------------------
// methods CBackupServiceInterface
//-------------------------------------------------------------------------------------------------
void CBackupServiceInterface::init(const std::string& bsiname)
{
_Name= bsiname;
}
void CBackupServiceInterface::setRemotePath( const std::string& remotePath )
{
_RemotePath = CPath::standardizePath( remotePath );
}
void CBackupServiceInterface::setLocalPath( const std::string& localPath )
{
_LocalPath = CPath::standardizePath( localPath );
}
void CBackupServiceInterface::requestFile(const std::string& fileName, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_RequestFile);
// check that the file name is valid
BOMB_IF(!FileNameValidator.checkFileName(fileName),"Failed to send get file request "+CSString(fileName).quote()+" due to invalid characters in file name",return);
// if there's no BS connected then complain and queue the file for loading later
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
BOMB( ("Failed to request file "+CSString(fileName).quote()+" because the backup services are all down!").c_str() , nlSleep(5000); exit(0) );
}
// create a log message...
// nldebug("BSIF: requestFile(): FileName: %s",fileName.quote().c_str(),msg.DataMsg.length());
// store away the callback for this action and retrieve the associated request id
uint32 requestId= CBackupInterfaceSingleton::getInstance()->pushFileCallback(cb, this);
// dispatch the request
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchRequestFile(_Name, requestId, _RemotePath+fileName);
}
// load a file synchronously
void CBackupServiceInterface::syncLoadFile(const std::string& fileName, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_RequestFile);
// check that the file name is valid
BOMB_IF(!FileNameValidator.checkFileName(fileName),"Failed to send sync load file "+CSString(fileName).quote()+" due to invalid characters in file name",return);
// store away the callback for this action and retrieve the associated request id
uint32 requestId= CBackupInterfaceSingleton::getInstance()->pushFileCallback(cb, this);
// dispatch the request
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchSyncLoadFile(_Name, requestId, _RemotePath+fileName, false);
}
// load a set of file synchronously
void CBackupServiceInterface::syncLoadFiles(const std::vector& fileNames, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_RequestFile);
// for each file, send a request request to the BS
for (uint i=0; ipushFileCallback(cb, this);
// dispatch the request (not blocking)
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchSyncLoadFile(_Name, requestId, _RemotePath+fileName, true);
}
// block until all files are loaded
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->terminateSyncLoads();
}
void CBackupServiceInterface::sendFile(CBackupMsgSaveFile& msg, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_SendFile);
// check that the file name is valid
BOMB_IF(!FileNameValidator.checkFileName(msg.FileName),"Failed to send save file request "+CSString(msg.FileName).quote()+" due to invalid characters in file name",return);
// if there's no BS connected then complain and queue the file for saving later
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
BOMB( ("Failed to send file "+CSString(msg.FileName).quote()+" because the backup services are all down!").c_str() , nlSleep(5000); exit(0) );
}
// create a log message...
// nldebug("BSIF: sendFile(): FileName: \"%s\", Size: %d bytes",msg.FileName.c_str(),msg.DataMsg.length());
// store away the callback for this action and retrieve the associated request id
uint32 requestId= CBackupInterfaceSingleton::getInstance()->pushGenericAckCallback(cb, this);
// dispatch the request
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchSendFile(_Name,requestId,msg);
}
// Append a data stream to a file
void CBackupServiceInterface::append(CBackupMsgSaveFile& msg, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_AppendFile);
// check that the file name is valid
BOMB_IF(!FileNameValidator.checkFileName(msg.FileName),"Failed to send append request "+CSString(msg.FileName).quote()+" due to invalid characters in file name",return);
// if there's no BS connected then complain and queue the file for saving later
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
BOMB( ("Failed to append to file "+CSString(msg.FileName).quote()+" because the backup services are all down!").c_str() , nlSleep(5000); exit(0) );
}
// create a log message...
// nldebug("BSIF: append(): FileName: \"%s\", Size: %d bytes",msg.FileName.c_str(),msg.DataMsg.length());
// store away the callback for this action and retrieve the associated request id
uint32 requestId= CBackupInterfaceSingleton::getInstance()->pushGenericAckCallback(cb, this);
// dispatch the request
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchAppendData(_Name,requestId,msg);
}
// Append a line to a file
void CBackupServiceInterface::append(const std::string& filename, const std::string& line, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_AppendText);
// check that the file name is valid
BOMB_IF(!FileNameValidator.checkFileName(filename),"Failed to send append file request "+CSString(filename).quote()+" due to invalid characters in file name",return);
// if there's no BS connected then complain and queue the file for saving later
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
BOMB( ("Failed to append to file "+CSString(filename).quote()+" because the backup services are all down!").c_str() , nlSleep(5000); exit(0) );
}
// create a log message...
// nldebug("BSIF: append(): FileName: %s, %s",filename.quote().c_str(),line.quote().c_str());
// store away the callback for this action and retrieve the associated request id
uint32 requestId= CBackupInterfaceSingleton::getInstance()->pushGenericAckCallback(cb, this);
// dispatch the request
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchAppendText(_Name,requestId,_RemotePath+filename,line);
}
// request for a file to be deleted (WARNING: no archiving of the file)
void CBackupServiceInterface::deleteFile(const std::string& fileName, bool keepBackupOfFile, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_DeleteFile);
// check that the file name is valid
BOMB_IF(!FileNameValidator.checkFileName(fileName),"Failed to send delete request "+CSString(fileName).quote()+" due to invalid characters in file name",return);
// if there's no BS connected then complain and queue the file for deleting later
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
BOMB( ("Failed to delete file "+CSString(fileName).quote()+" because the backup services are all down!").c_str() , nlSleep(5000); exit(0) );
}
// create a log message...
// nldebug("BSIF: deleteFile(): FileName: \"%s\", KeepBackup: %s",fileName.c_str(), keepBackupOfFile ? "true" : "false");
// store away the callback for this action and retrieve the associated request id
uint32 requestId= CBackupInterfaceSingleton::getInstance()->pushGenericAckCallback(cb, this);
// dispatch the request
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchDeleteFile(_Name,requestId,_RemotePath+fileName,keepBackupOfFile);
}
// request BS sends me files matching the given file classes
void CBackupServiceInterface::requestFileClass(const std::string& directory, const std::vector& classes, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_RequestFileClass);
// if there's no BS connected then complain and queue the file for retrieving later
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
BOMB( ("Failed to request file class in directory "+CSString(directory).quote()+" because the backup services are all down!").c_str() , nlSleep(5000); exit(0) );
}
// create a log message...
// NLMISC::CSString patterns;
// for (uint32 j=0;jpushFileClassCallback(cb, this);
// dispatch the request
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchRequestFileClass(_Name,requestId,_RemotePath+directory,classes);
}
// request BS sends me files matching the given file classes
void CBackupServiceInterface::syncLoadFileClass(const std::string& directory, const std::vector& classes, NLMISC::CSmartPtr cb)
{
H_AUTO(BSIF_syncLoadFileClass);
// if there's no BS connected then complain and queue the file for retrieving later
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
BOMB( ("Failed to request file class in directory "+CSString(directory).quote()+" because the backup services are all down!").c_str() , nlSleep(5000); exit(0) );
}
// create a log message...
// NLMISC::CSString patterns;
// for (uint32 j=0;jpushFileClassCallback(cb, this);
// dispatch the request
CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->dispatchSyncLoadFileClass(_Name,requestId,_RemotePath+directory,classes);
}
NLMISC::TTime CBackupServiceInterface::getLastAckTime() const
{
// if there's no BS connected then give up
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
return 0;
}
// delegate...
return CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->getLastAckTime();
}
NLMISC::TTime CBackupServiceInterface::getLastAckDelay() const
{
// if there's no BS connected then give up
if (!CBackupInterfaceSingleton::getInstance()->isConnected())
{
// return 64 bit signed maxint (a very big number)
return uint64(sint64(-1))>>1;
}
// delegate...
return CBackupInterfaceSingleton::getInstance()->getBSIImplementation()->getLastAckDelay();
}