mirror of
https://port.numenaute.org/aleajactaest/khanat-code-old.git
synced 2024-12-15 13:38:42 +00:00
393 lines
9 KiB
C++
393 lines
9 KiB
C++
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||
|
// 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 <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
#include "nel/misc/types_nl.h"
|
||
|
#include "nel/misc/command.h"
|
||
|
#include "nel/misc/path.h"
|
||
|
#include "nel/misc/file.h"
|
||
|
#include "nel/misc/md5.h"
|
||
|
|
||
|
#include "backup_service.h"
|
||
|
#include "game_share/persistent_data.h"
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace NLMISC;
|
||
|
using namespace NLNET;
|
||
|
|
||
|
|
||
|
CDirectoryRateStat DirStats;
|
||
|
|
||
|
extern CVariable<string> SaveShardRoot;
|
||
|
|
||
|
|
||
|
NLMISC_COMMAND(displayFileStats, "display file read/write stats for the last minute", "")
|
||
|
{
|
||
|
DirStats.display(log);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
NLMISC_DYNVARIABLE(string, FileReadStat, "mean file read in bytes per seconds for the last minute")
|
||
|
{
|
||
|
if (get)
|
||
|
*pointer = bytesToHumanReadable(DirStats.getMeanReadRate());
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
NLMISC_DYNVARIABLE(string, FileWriteStat, "mean file write in bytes per seconds for the last minute")
|
||
|
{
|
||
|
if (get)
|
||
|
*pointer = bytesToHumanReadable(DirStats.getMeanWriteRate());
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
NLMISC_COMMAND ( resumeBackupService, "reset stall mode for resume backup process", "no params")
|
||
|
{
|
||
|
CBackupService::getInstance()->setStall( false );
|
||
|
CMessage msgOut("RESUME_SHARD");
|
||
|
CUnifiedNetwork::getInstance()->send("EGS", msgOut );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
NLMISC_COMMAND ( stallBackupService, "set backup service un stall mode", "no params")
|
||
|
{
|
||
|
CBackupService::getInstance()->stallShard( std::string("Stalled by admin command") );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
NLMISC_COMMAND ( dumpCharacterFile, "dump the content of the save file for a character. Invoke with no param to display a list of available shardId.", "<shardId> <playerID> <slotNum> [<onlyThisTag>|listTokens]")
|
||
|
{
|
||
|
if (args.size() == 0)
|
||
|
{
|
||
|
// just output the list of available shard id
|
||
|
vector<string> shards;
|
||
|
CPath::getPathContent(SaveShardRoot, false, true, false, shards);
|
||
|
|
||
|
log.displayNL("Listing %u available shard id in path '%s':", shards.size(), SaveShardRoot.c_str());
|
||
|
for (uint i=0; i<shards.size(); ++i)
|
||
|
{
|
||
|
string id = shards[i];
|
||
|
id = CPath::standardizePath(id, false);
|
||
|
if (!id.empty() && (id[id.size()-1] == '\\' || id[id.size()-1] == '/'))
|
||
|
id.resize(id.size()-1);
|
||
|
id = CFile::getFilename(id);
|
||
|
|
||
|
log.displayNL(" %s", id.c_str());
|
||
|
}
|
||
|
log.displayNL("End of list.");
|
||
|
|
||
|
// build a list
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
if (args.size() < 3)
|
||
|
return false;
|
||
|
|
||
|
bool useFilter = false;
|
||
|
string filterIn;
|
||
|
string filterOut;
|
||
|
|
||
|
if (args.size() == 4)
|
||
|
{
|
||
|
filterIn = string("<")+args[3];
|
||
|
filterOut = string("</")+args[3];
|
||
|
useFilter = true;
|
||
|
}
|
||
|
|
||
|
string fileName = SaveShardRoot.toString()+"/"+args[0]+"/characters/account_"+args[1]+"_"+args[2]+"_pdr.bin";
|
||
|
if (!CFile::isExists(fileName))
|
||
|
{
|
||
|
log.displayNL("The file '%s' (located here '%s') cannot be found in '%s' backup directory",
|
||
|
CFile::getFilename(fileName).c_str(),
|
||
|
fileName.c_str(),
|
||
|
args[0].c_str());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// the file exist !
|
||
|
static CPersistentDataRecord pdr;
|
||
|
pdr.clear();
|
||
|
|
||
|
if (!pdr.readFromBinFile(fileName.c_str()))
|
||
|
{
|
||
|
log.displayNL("Error while reading file '%s'", fileName.c_str());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
string xml;
|
||
|
if (!pdr.toString(xml))
|
||
|
{
|
||
|
log.displayNL("Error while converting file '%s' to XML", fileName.c_str());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (useFilter && args[3] == "listTokens")
|
||
|
{
|
||
|
// build a list of tokens and output it
|
||
|
set<string> tokens;
|
||
|
|
||
|
string::size_type pos = 0;
|
||
|
pos = xml.find("<");
|
||
|
while (pos != string::npos)
|
||
|
{
|
||
|
++pos;
|
||
|
string token;
|
||
|
while (xml[pos] != ' ' && xml[pos] != '\t' && xml[pos] != '/' && xml[pos] != '>')
|
||
|
token += xml[pos++];
|
||
|
|
||
|
tokens.insert(token);
|
||
|
|
||
|
pos = xml.find("<", pos);
|
||
|
}
|
||
|
|
||
|
// output the result
|
||
|
log.displayNL("Displaying %u tokens in characters file :", tokens.size());
|
||
|
string line;
|
||
|
set<string>::iterator first(tokens.begin()), last(tokens.end());
|
||
|
for (; first != last; ++first)
|
||
|
{
|
||
|
line += *first+" ";
|
||
|
|
||
|
if (line.size() > 80)
|
||
|
{
|
||
|
log.displayNL("%s", line.c_str());
|
||
|
line = "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!line.empty())
|
||
|
log.displayNL("%s", line.c_str());
|
||
|
|
||
|
log.displayNL("End of token list");
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// ok, now display the data
|
||
|
vector<string> lines;
|
||
|
explode(xml, string("\n"), lines);
|
||
|
|
||
|
bool logOn = !useFilter;
|
||
|
|
||
|
for (uint i=0; i<lines.size(); ++i)
|
||
|
{
|
||
|
// check filters
|
||
|
if (useFilter)
|
||
|
if (!logOn && lines[i].find(filterIn) != string::npos)
|
||
|
logOn = true;
|
||
|
|
||
|
if (logOn)
|
||
|
log.displayNL("%s", lines[i].c_str());
|
||
|
|
||
|
// check filter
|
||
|
if (useFilter)
|
||
|
{
|
||
|
if (logOn
|
||
|
&& (lines[i].find(filterOut) != string::npos
|
||
|
|| (lines[i].find(filterIn) != string::npos
|
||
|
&& lines[i].find("/>") != string::npos)
|
||
|
))
|
||
|
logOn = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static char base64Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||
|
static uint8 base64Revert[256];
|
||
|
static bool base64Init = false;
|
||
|
|
||
|
static void base64Encode(const std::vector<uint8>& buffer, std::string& encoded)
|
||
|
{
|
||
|
encoded.clear();
|
||
|
encoded.reserve(buffer.size()*4/3+3);
|
||
|
|
||
|
uint i;
|
||
|
for (i=0; i<buffer.size(); )
|
||
|
{
|
||
|
uint32 b = 0;
|
||
|
|
||
|
b |= (buffer[i++] << 16);
|
||
|
encoded += base64Table[(b >> 18) & 0x3f];
|
||
|
|
||
|
if (i < buffer.size())
|
||
|
{
|
||
|
b |= (buffer[i++] << 8);
|
||
|
encoded += base64Table[(b >> 12) & 0x3f];
|
||
|
|
||
|
if (i < buffer.size())
|
||
|
{
|
||
|
b |= buffer[i++];
|
||
|
encoded += base64Table[(b >> 6) & 0x3f];
|
||
|
encoded += base64Table[b & 0x3f];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
encoded += base64Table[(b >> 6) & 0x3f];
|
||
|
encoded += '=';
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
encoded += base64Table[(b >> 12) & 0x3f];
|
||
|
encoded += '=';
|
||
|
encoded += '=';
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void base64Decode(std::vector<uint8>& buffer, const std::string& encoded)
|
||
|
{
|
||
|
uint i;
|
||
|
|
||
|
if (!base64Init)
|
||
|
{
|
||
|
for (i=0; i<256; ++i)
|
||
|
base64Revert[i] = 255;
|
||
|
for (i=0; i<sizeof(base64Table); ++i)
|
||
|
base64Revert[base64Table[i]] = i;
|
||
|
}
|
||
|
|
||
|
uint sz = (uint)encoded.size();
|
||
|
uint inbits = 0;
|
||
|
uint bitbuffer = 0;
|
||
|
for (i=0; i<sz; ++i)
|
||
|
{
|
||
|
// padding? -> leave
|
||
|
if (encoded[i] == '=')
|
||
|
break;
|
||
|
|
||
|
// unknown char? -> skip
|
||
|
if (base64Revert[(uint8)encoded[i]] == 255)
|
||
|
continue;
|
||
|
|
||
|
bitbuffer = (bitbuffer << 6) | base64Revert[(uint8)encoded[i]];
|
||
|
inbits += 6;
|
||
|
|
||
|
if (inbits >= 8)
|
||
|
{
|
||
|
buffer.push_back((uint8)(bitbuffer >> (inbits-8)));
|
||
|
inbits -= 8;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NLMISC_COMMAND ( stallShard, "stall backup service and connected shards (via EGS)", "")
|
||
|
{
|
||
|
CBackupService::getInstance()->FileManager.setMode(CFileAccessManager::Stalled, "MANUAL BS STALL");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
NLMISC_COMMAND ( resumeShard, "resume backup service and connected shards (via EGS)", "")
|
||
|
{
|
||
|
CBackupService::getInstance()->FileManager.setMode(CFileAccessManager::Normal, "MANUAL BS RESUME");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
NLMISC_COMMAND ( removeFileAccess, "remove a file access from file access manager (see displayFileAccesses)", "<hexa pointer>")
|
||
|
{
|
||
|
if (args.size() != 1)
|
||
|
return false;
|
||
|
|
||
|
IFileAccess* access = NULL;
|
||
|
sscanf(args[0].c_str(), "%p", &access);
|
||
|
|
||
|
CBackupService::getInstance()->FileManager.removeFileAccess(access);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
NLMISC_COMMAND ( displayFileAccesses, "display stacked file accesses", "")
|
||
|
{
|
||
|
CBackupService::getInstance()->FileManager.displayFileAccesses(log);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NLMISC_COMMAND (getFileBase64Content, "dump file content in Base64 encoded form", "<file>")
|
||
|
{
|
||
|
if (args.size() != 1)
|
||
|
{
|
||
|
log.displayRawNL("file INVALIDFILE lines 0 size 0");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
CIFile f;
|
||
|
if (!CFile::fileExists(args[0]) || CFile::getFileSize(args[0]) == 0 || !f.open(args[0]))
|
||
|
{
|
||
|
log.displayRawNL("file %s lines 0 size 0", args[0].c_str());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
uint filesize = f.getFileSize();
|
||
|
|
||
|
std::vector<uint8> buffer;
|
||
|
buffer.resize(filesize);
|
||
|
f.serialBuffer(&(buffer[0]), filesize);
|
||
|
f.close();
|
||
|
|
||
|
CHashKeyMD5 key = getMD5(&(buffer[0]), filesize);
|
||
|
|
||
|
std::string encoded;
|
||
|
base64Encode(buffer, encoded);
|
||
|
|
||
|
uint numcharperline = 224;
|
||
|
uint numlines = ((uint)encoded.size()+numcharperline-1)/numcharperline;
|
||
|
|
||
|
log.displayRawNL("file %s lines %d size %d haskey %s", args[0].c_str(), numlines, filesize, key.toString().c_str());
|
||
|
|
||
|
uint cpos = 0;
|
||
|
while (cpos < encoded.size())
|
||
|
{
|
||
|
std::string line = encoded.substr(cpos, numcharperline);
|
||
|
log.displayRawNL("%s", line.c_str());
|
||
|
cpos += numcharperline;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
NLMISC_COMMAND (putFileBase64Content, "fill file with content in Base64 encoded form", "<file> <base64content>")
|
||
|
{
|
||
|
if (args.size() < 2)
|
||
|
return false;
|
||
|
|
||
|
COFile f;
|
||
|
if (!f.open(args[0]))
|
||
|
return false;
|
||
|
|
||
|
std::string encoded;
|
||
|
uint i;
|
||
|
for (i=1; i<args.size(); ++i)
|
||
|
encoded += args[i];
|
||
|
|
||
|
std::vector<uint8> buffer;
|
||
|
base64Decode(buffer, encoded);
|
||
|
|
||
|
f.serialBuffer(&(buffer[0]), (uint)buffer.size());
|
||
|
f.close();
|
||
|
|
||
|
return true;
|
||
|
}
|