356 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			356 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| This file is part of Telegram Desktop,
 | |
| the official desktop version of Telegram messaging app, see https://telegram.org
 | |
| 
 | |
| Telegram Desktop is free software: you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation, either version 3 of the License, or
 | |
| (at your option) any later version.
 | |
| 
 | |
| It 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 General Public License for more details.
 | |
| 
 | |
| Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
 | |
| Copyright (c) 2014 John Preston, https://desktop.telegram.org
 | |
| */
 | |
| #include "stdafx.h"
 | |
| #include <iostream>
 | |
| #include "pspecific.h"
 | |
| 
 | |
| namespace {
 | |
| 	QFile debugLog, tcpLog, mtpLog, mainLog;
 | |
| 	QTextStream *debugLogStream = 0, *tcpLogStream = 0, *mtpLogStream = 0, *mainLogStream = 0;
 | |
| 	int32 part = -1;
 | |
| 	QChar zero('0');
 | |
| 
 | |
| 	QMutex debugLogMutex, mainLogMutex;
 | |
| 
 | |
| 	class _StreamCreator {
 | |
| 	public:
 | |
| 		~_StreamCreator() {
 | |
| 			logsClose();
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	QString debugLogEntryStart() {
 | |
| 		static uint32 logEntry = 0;
 | |
| 
 | |
| 		QDateTime tm(QDateTime::currentDateTime());
 | |
| 
 | |
| 		QThread *thread = QThread::currentThread();
 | |
| 		MTPThread *mtpThread = dynamic_cast<MTPThread*>(thread);
 | |
| 		uint32 threadId = mtpThread ? mtpThread->getThreadId() : 0;
 | |
| 		
 | |
| 		return QString("[%1 %2-%3]").arg(tm.toString("hh:mm:ss.zzz")).arg(QString("%1").arg(threadId, 2, 10, zero)).arg(++logEntry, 7, 10, zero);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void debugLogWrite(const char *file, int32 line, const QString &v) {
 | |
| 	if (!cDebug() || !debugLogStream) return;
 | |
| 
 | |
| 	const char *last = strstr(file, "/"), *found = 0;
 | |
| 	while (last) {
 | |
| 		found = last;
 | |
| 		last = strstr(last + 1, "/");
 | |
| 	}
 | |
| 	last = strstr(file, "\\");
 | |
| 	while (last) {
 | |
| 		found = last;
 | |
| 		last = strstr(last + 1, "\\");
 | |
| 	}
 | |
| 	if (found) {
 | |
| 		file = found + 1;
 | |
| 	}
 | |
| 
 | |
| 	{
 | |
| 		QMutexLocker lock(&debugLogMutex);
 | |
| 
 | |
| 		logsInitDebug(); // maybe need to reopen new file
 | |
| 
 | |
| 		QString msg(QString("%1 %2 (%3 : %4)\n").arg(debugLogEntryStart()).arg(v).arg(file).arg(line));
 | |
| 		(*debugLogStream) << msg;
 | |
| 		debugLogStream->flush();
 | |
| #ifdef Q_OS_WIN
 | |
| //		OutputDebugString(reinterpret_cast<const wchar_t *>(msg.utf16()));
 | |
| #elif defined Q_OS_MAC
 | |
|         objc_outputDebugString(msg);
 | |
| #elif defined Q_OS_LINUX && defined _DEBUG
 | |
|         std::cout << msg.toUtf8().constData();
 | |
| #endif
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void tcpLogWrite(const QString &v) {
 | |
| 	if (!cDebug() || !tcpLogStream) return;
 | |
| 
 | |
| 	{
 | |
| 		QMutexLocker lock(&debugLogMutex);
 | |
| 
 | |
| 		logsInitDebug(); // maybe need to reopen new file
 | |
| 
 | |
| 		(*tcpLogStream) << QString("%1 %2\n").arg(debugLogEntryStart()).arg(v);
 | |
| 		tcpLogStream->flush();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void mtpLogWrite(int32 dc, const QString &v) {
 | |
| 	if (!cDebug() || !mtpLogStream) return;
 | |
| 
 | |
| 	{
 | |
| 		QMutexLocker lock(&debugLogMutex);
 | |
| 
 | |
| 		logsInitDebug(); // maybe need to reopen new file
 | |
| 
 | |
| 		(*mtpLogStream) << QString("%1 (dc:%2) %3\n").arg(debugLogEntryStart()).arg(dc).arg(v);
 | |
| 		mtpLogStream->flush();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void logWrite(const QString &v) {
 | |
| 	if (!mainLog.isOpen()) return;
 | |
| 
 | |
| 	time_t t = time(NULL);
 | |
| 	struct tm tm;
 | |
|     mylocaltime(&tm, &t);
 | |
| 
 | |
| 	{
 | |
| 		QMutexLocker lock(&mainLogMutex);
 | |
| 		QString msg(QString("[%1.%2.%3 %4:%5:%6] %7\n").arg(tm.tm_year + 1900).arg(tm.tm_mon + 1, 2, 10, zero).arg(tm.tm_mday, 2, 10, zero).arg(tm.tm_hour, 2, 10, zero).arg(tm.tm_min, 2, 10, zero).arg(tm.tm_sec, 2, 10, zero).arg(v));
 | |
| 		(*mainLogStream) << msg;
 | |
| 		mainLogStream->flush();
 | |
| 	}
 | |
| 
 | |
| 	if (cDebug()) debugLogWrite("logs", 0, v);
 | |
| }
 | |
| 
 | |
| void moveOldDataFiles(const QString &wasDir) {
 | |
| 	QFile data(wasDir + "data"), dataConfig(wasDir + "data_config"), tdataConfig(wasDir + "tdata/config");
 | |
| 	if (data.exists() && dataConfig.exists() && !QFileInfo(cWorkingDir() + "data").exists() && !QFileInfo(cWorkingDir() + "data_config").exists()) { // move to home dir
 | |
| 		LOG(("Copying data to home dir '%1' from '%2'").arg(cWorkingDir()).arg(wasDir));
 | |
| 		if (data.copy(cWorkingDir() + "data")) {
 | |
| 			LOG(("Copied 'data' to home dir"));
 | |
| 			if (dataConfig.copy(cWorkingDir() + "data_config")) {
 | |
| 				LOG(("Copied 'data_config' to home dir"));
 | |
| 				bool tdataGood = true;
 | |
| 				if (tdataConfig.exists()) {
 | |
| 					tdataGood = false;
 | |
| 					QDir().mkpath(cWorkingDir() + "tdata");
 | |
| 					if (tdataConfig.copy(cWorkingDir() + "tdata/config")) {
 | |
| 						LOG(("Copied 'tdata/config' to home dir"));
 | |
| 						tdataGood = true;
 | |
| 					} else {
 | |
| 						LOG(("Copied 'data' and 'data_config', but could not copy 'tdata/config'!"));
 | |
| 					}
 | |
| 				}
 | |
| 				if (tdataGood) {
 | |
| 					if (data.remove()) {
 | |
| 						LOG(("Removed 'data'"));
 | |
| 					} else {
 | |
| 						LOG(("Could not remove 'data'"));
 | |
| 					}
 | |
| 					if (dataConfig.remove()) {
 | |
| 						LOG(("Removed 'data_config'"));
 | |
| 					} else {
 | |
| 						LOG(("Could not remove 'data_config'"));
 | |
| 					}
 | |
| 					if (!tdataConfig.exists() || tdataConfig.remove()) {
 | |
| 						LOG(("Removed 'tdata/config'"));
 | |
| 						LOG(("Could not remove 'tdata/config'"));
 | |
| 					} else {
 | |
| 					}
 | |
| 					QDir().rmdir(wasDir + "tdata");
 | |
| 				}
 | |
| 			} else {
 | |
| 				LOG(("Copied 'data', but could not copy 'data_config'!!"));
 | |
| 			}
 | |
| 		} else {
 | |
| 			LOG(("Could not copy 'data'!"));
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void logsInit() {
 | |
| 	static _StreamCreator streamCreator;
 | |
| 	if (mainLogStream) return;
 | |
| 
 | |
|     QString wasDir = cWorkingDir();
 | |
| #if (defined Q_OS_MAC || defined Q_OS_LINUX)
 | |
| 
 | |
| #ifdef _DEBUG
 | |
|     cForceWorkingDir(cExeDir());
 | |
| #else
 | |
|     cForceWorkingDir(psAppDataPath());
 | |
| #endif
 | |
| 
 | |
| #if (defined Q_OS_LINUX && !defined _DEBUG) // fix first version
 | |
| 	moveOldDataFiles(wasDir);
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
|     QString rightDir = cWorkingDir();
 | |
|     cForceWorkingDir(rightDir);
 | |
| 	mainLog.setFileName(cWorkingDir() + "log.txt");
 | |
| 	mainLog.open(QIODevice::WriteOnly | QIODevice::Text);
 | |
| 	if (!mainLog.isOpen()) {
 | |
| 		cForceWorkingDir(cExeDir());
 | |
| 		mainLog.setFileName(cWorkingDir() + "log.txt");
 | |
| 		mainLog.open(QIODevice::WriteOnly | QIODevice::Text);
 | |
| 		if (!mainLog.isOpen()) {
 | |
| 			cForceWorkingDir(psAppDataPath());
 | |
| 			mainLog.setFileName(cWorkingDir() + "log.txt");
 | |
| 			mainLog.open(QIODevice::WriteOnly | QIODevice::Text);
 | |
| 		}
 | |
| 	}
 | |
| 	if (mainLog.isOpen()) {
 | |
| 		mainLogStream = new QTextStream();
 | |
| 		mainLogStream->setDevice(&mainLog);
 | |
| 		mainLogStream->setCodec("UTF-8");
 | |
| 	} else {
 | |
|         cForceWorkingDir(rightDir);
 | |
| 	}
 | |
| 	cForceWorkingDir(QDir(cWorkingDir()).absolutePath() + '/');
 | |
| 
 | |
| #ifdef Q_OS_WIN
 | |
| 	if (cWorkingDir() == psAppDataPath()) { // fix old "Telegram Win (Unofficial)" version
 | |
| 		moveOldDataFiles(psAppDataPathOld());
 | |
| 	}
 | |
| #endif
 | |
| 	if (cDebug()) {
 | |
| 		logsInitDebug();
 | |
| 	} else if (QFile(cWorkingDir() + qsl("tdata/withdebug")).exists()) {
 | |
| 		logsInitDebug();
 | |
| 		cSetDebug(true);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void logsInitDebug() {
 | |
| 	time_t t = time(NULL);
 | |
| 	struct tm tm;
 | |
| 	mylocaltime(&tm, &t);
 | |
| 
 | |
| 	static const int switchEach = 15; // minutes
 | |
| 	int32 newPart = (tm.tm_min + tm.tm_hour * 60) / switchEach;
 | |
| 	if (newPart == part) return;
 | |
| 
 | |
| 	part = newPart;
 | |
| 
 | |
| 	int32 dayIndex = (tm.tm_year + 1900) * 10000 + (tm.tm_mon + 1) * 100 + tm.tm_mday;
 | |
| 	QString logPostfix = QString("_%4_%5").arg((part * switchEach) / 60, 2, 10, zero).arg((part * switchEach) % 60, 2, 10, zero);
 | |
| 
 | |
| 	if (debugLogStream) {
 | |
| 		delete debugLogStream;
 | |
| 		debugLogStream = 0;
 | |
| 		debugLog.close();
 | |
| 	}
 | |
| 	debugLog.setFileName(cWorkingDir() + qsl("DebugLogs/log") + logPostfix + qsl(".txt"));
 | |
| 	QIODevice::OpenMode debugLogMode = QIODevice::WriteOnly | QIODevice::Text;
 | |
| 	if (debugLog.exists()) {
 | |
| 		if (debugLog.open(QIODevice::ReadOnly | QIODevice::Text)) {
 | |
| 			if (QString::fromUtf8(debugLog.readLine()).toInt() == dayIndex) {
 | |
| 				debugLogMode |= QIODevice::Append;
 | |
| 			}
 | |
| 			debugLog.close();
 | |
| 		}
 | |
| 	}
 | |
| 	if (!debugLog.open(debugLogMode)) {
 | |
| 		QDir dir(QDir::current());
 | |
| 		dir.mkdir(cWorkingDir() + qsl("DebugLogs"));
 | |
| 		debugLog.open(debugLogMode);
 | |
| 	}
 | |
| 	if (debugLog.isOpen()) {
 | |
| 		debugLogStream = new QTextStream();
 | |
| 		debugLogStream->setDevice(&debugLog);
 | |
| 		debugLogStream->setCodec("UTF-8");
 | |
| 		(*debugLogStream) << ((debugLogMode & QIODevice::Append) ? qsl("----------------------------------------------------------------\nNEW LOGGING INSTANCE STARTED!!!\n----------------------------------------------------------------\n") : qsl("%1\n").arg(dayIndex));
 | |
| 		debugLogStream->flush();
 | |
| 	}
 | |
| 	if (tcpLogStream) {
 | |
| 		delete tcpLogStream;
 | |
| 		tcpLogStream = 0;
 | |
| 		tcpLog.close();
 | |
| 	}
 | |
| 	tcpLog.setFileName(cWorkingDir() + qsl("DebugLogs/tcp") + logPostfix + qsl(".txt"));
 | |
| 	QIODevice::OpenMode tcpLogMode = QIODevice::WriteOnly | QIODevice::Text;
 | |
| 	if (tcpLog.exists()) {
 | |
| 		if (tcpLog.open(QIODevice::ReadOnly | QIODevice::Text)) {
 | |
| 			if (QString::fromUtf8(tcpLog.readLine()).toInt() == dayIndex) {
 | |
| 				tcpLogMode |= QIODevice::Append;
 | |
| 			}
 | |
| 			tcpLog.close();
 | |
| 		}
 | |
| 	}
 | |
| 	if (tcpLog.open(tcpLogMode)) {
 | |
| 		tcpLogStream = new QTextStream();
 | |
| 		tcpLogStream->setDevice(&tcpLog);
 | |
| 		tcpLogStream->setCodec("UTF-8");
 | |
| 		(*tcpLogStream) << ((tcpLogMode & QIODevice::Append) ? qsl("----------------------------------------------------------------\nNEW LOGGING INSTANCE STARTED!!!\n----------------------------------------------------------------\n") : qsl("%1\n").arg(dayIndex));
 | |
| 		tcpLogStream->flush();
 | |
| 	}
 | |
| 	if (mtpLogStream) {
 | |
| 		delete mtpLogStream;
 | |
| 		mtpLogStream = 0;
 | |
| 		mtpLog.close();
 | |
| 	}
 | |
| 	mtpLog.setFileName(cWorkingDir() + qsl("DebugLogs/mtp") + logPostfix + qsl(".txt"));
 | |
| 	QIODevice::OpenMode mtpLogMode = QIODevice::WriteOnly | QIODevice::Text;
 | |
| 	if (mtpLog.exists()) {
 | |
| 		if (mtpLog.open(QIODevice::ReadOnly | QIODevice::Text)) {
 | |
| 			if (QString::fromUtf8(mtpLog.readLine()).toInt() == dayIndex) {
 | |
| 				mtpLogMode |= QIODevice::Append;
 | |
| 			}
 | |
| 			mtpLog.close();
 | |
| 		}
 | |
| 	}
 | |
| 	if (mtpLog.open(mtpLogMode)) {
 | |
| 		mtpLogStream = new QTextStream();
 | |
| 		mtpLogStream->setDevice(&mtpLog);
 | |
| 		mtpLogStream->setCodec("UTF-8");
 | |
| 		(*mtpLogStream) << ((mtpLogMode & QIODevice::Append) ? qsl("----------------------------------------------------------------\nNEW LOGGING INSTANCE STARTED!!!\n----------------------------------------------------------------\n") : qsl("%1\n").arg(dayIndex));
 | |
| 		mtpLogStream->flush();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void logsClose() {
 | |
| 	if (cDebug()) {
 | |
| 		if (debugLogStream) {
 | |
| 			delete debugLogStream;
 | |
| 			debugLogStream = 0;
 | |
| 			debugLog.close();
 | |
| 		}
 | |
| 		if (tcpLogStream) {
 | |
| 			delete tcpLogStream;
 | |
| 			tcpLogStream = 0;
 | |
| 			tcpLog.close();
 | |
| 		}
 | |
| 		if (mtpLogStream) {
 | |
| 			delete mtpLogStream;
 | |
| 			mtpLogStream = 0;
 | |
| 			mtpLog.close();
 | |
| 		}
 | |
| 	}
 | |
| 	if (mainLogStream) {
 | |
| 		delete mainLogStream;
 | |
| 		mainLogStream = 0;
 | |
| 		mainLog.close();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| QString logVectorLong(const QVector<MTPlong> &ids) {
 | |
| 	if (!ids.size()) return "[void list]";
 | |
| 	QString idsStr = QString("[%1").arg(ids.cbegin()->v);
 | |
| 	for (QVector<MTPlong>::const_iterator i = ids.cbegin() + 1, e = ids.cend(); i != e; ++i) {
 | |
| 		idsStr += QString(", %2").arg(i->v);
 | |
| 	}
 | |
| 	return idsStr + "]";
 | |
| }
 | |
| 
 | |
| QString logVectorLong(const QVector<uint64> &ids) {
 | |
| 	if (!ids.size()) return "[void list]";
 | |
| 	QString idsStr = QString("[%1").arg(*ids.cbegin());
 | |
| 	for (QVector<uint64>::const_iterator i = ids.cbegin() + 1, e = ids.cend(); i != e; ++i) {
 | |
| 		idsStr += QString(", %2").arg(*i);
 | |
| 	}
 | |
| 	return idsStr + "]";
 | |
| }
 | 
