Fulcrum/Util.cpp
Calin Culianu 2477a7a8a3 Added initial TcpServer stub implementation
- Already supports listening on as many sockets as you wish
- Each listening server has its own thread
- Will implement later: SSL server

Also refactored code a bit, created the generic "Controller" class, made
EXMgr and SrvMgr inherit from it.

ToDo: Figure out workflow for connections and clients, model client
sessions, etc.
2019-04-26 08:47:46 +03:00

192 lines
5.5 KiB
C++

#include "Util.h"
#include "App.h"
#include "Logger.h"
#include <iostream>
#include <chrono>
namespace Util {
QString basename(const QString &s) {
QRegExp re("[\\/]");
auto toks = s.split(re);
return toks.last();
}
qint64 getTime() {
return getTimeNS() / 1000000LL;
}
static const std::chrono::time_point t0(std::chrono::high_resolution_clock::now());
qint64 getTimeNS() {
auto now = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::nanoseconds>(now - t0).count();
}
double getTimeSecs() {
return double(getTime()) / 1000.0;
}
namespace Json {
Error::~Error() {} // for vtable
QVariant parseString(const QString &str, bool expectMap) {
QJsonParseError e;
QJsonDocument d = QJsonDocument::fromJson(str.toUtf8(), &e);
if (d.isNull())
throw Error(QString("Error parsing Json from string: %1").arg(e.errorString()));
auto v = d.toVariant();
if (expectMap && v.type() != QVariant::Map)
throw Error("Json Error, expected map, got a list instead");
if (!expectMap && v.type() != QVariant::List)
throw Error("Json Error, expected list, got a map instead");
return v;
}
QVariant parseFile(const QString &file, bool expectMap) {
QFile f(file);
if (!f.open(QFile::ReadOnly))
throw Error(QString("Could not open file: %1").arg(file));
QString s(f.readAll());
return parseString(s, expectMap);
}
QString toString(const QVariant &v, bool compact) {
if (v.isNull() || !v.isValid()) throw Error("Empty or invalid QVariant passed to Json::toString");
auto d = QJsonDocument::fromVariant(v);
if (d.isNull())
throw Error("Bad QVariant pased to Json::toString");
return d.toJson(compact ? QJsonDocument::Compact : QJsonDocument::Indented);
}
}
}
Log::Log() {}
Log::Log(Color c)
{
setColor(c);
}
Log::Log(const char *fmt...)
: s()
{
va_list ap;
va_start(ap,fmt);
str = QString::vasprintf(fmt,ap);
va_end(ap);
s.setString(&str, QIODevice::WriteOnly|QIODevice::Append);
}
Log::~Log()
{
if (doprt) {
App *ourApp = app();
s.flush(); // does nothing probably..
QString dateStr = ourApp && ourApp->options.syslogMode ? "" : QString("[") + QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz") + QString("] ");
QString thrdStr = "";
if (QThread *th = QThread::currentThread(); th && ourApp && th != ourApp->thread()) {
QString thrdName = th->objectName();
if (thrdName.trimmed().isEmpty()) thrdName = QString::asprintf("%p", reinterpret_cast<void *>(QThread::currentThreadId()));
thrdStr = QString("<Thread: %1> ").arg(thrdName);
}
Logger *logger = ourApp ? ourApp->logger() : nullptr;
QString theString = dateStr + thrdStr + (logger && logger->isaTTY() ? colorify(str, color) : str);
if (logger) {
emit logger->log(theString);
} else {
// just print to console for now..
std::cerr << Q2C(theString) << std::endl << std::flush;
}
}
}
/* static */
QString Log::colorString(Color c) {
const char *suffix = "[0m"; // normal
switch(c) {
case Black: suffix = "[30m"; break;
case Red: suffix = "[31m"; break;
case Green: suffix = "[32m"; break;
case Yellow: suffix = "[33m"; break;
case Blue: suffix = "[34m"; break;
case Magenta: suffix = "[35m"; break;
case Cyan: suffix = "[36m"; break;
case White: suffix = "[37m"; break;
case BrightBlack: suffix = "[30;1m"; break;
case BrightRed: suffix = "[31;1m"; break;
case BrightGreen: suffix = "[1,32m"; break;
case BrightYellow: suffix = "[33;1m"; break;
case BrightBlue: suffix = "[34;1m"; break;
case BrightMagenta: suffix = "[35;1m"; break;
case BrightCyan: suffix = "[36;1m"; break;
case BrightWhite: suffix = "[37;1m"; break;
default:
// will just use normal
break;
}
static const char prefix[2] = { 033, 0 }; // esc 033 in octal
return QString::asprintf("%s%s", prefix, suffix);
}
QString Log::colorify(const QString &str, Color c) {
QString colorStr = useColor && c != Normal ? colorString(c) : "";
QString normalStr = useColor && c != Normal ? colorString(Normal) : "";
return colorStr + str + normalStr;
}
template <> Log & Log::operator<<(const Color &c) { setColor(c); return *this; }
Debug::Debug(const char *fmt...)
: Log()
{
va_list ap;
va_start(ap,fmt);
str = QString::vasprintf(fmt,ap);
va_end(ap);
s.setString(&str, QIODevice::WriteOnly|QIODevice::Append);
}
Debug::~Debug()
{
auto ourApp = app();
doprt = !ourApp || ourApp->options.verboseDebug;
if (!doprt) return;
if (!colorOverridden) color = Blue;
str = QString("(Debug) ") + str;
}
Error::Error(const char *fmt...)
: Log()
{
va_list ap;
va_start(ap,fmt);
str = QString::vasprintf(fmt,ap);
va_end(ap);
s.setString(&str, QIODevice::WriteOnly|QIODevice::Append);
}
Error::~Error()
{
if (!colorOverridden) color = Red;
}
Warning::Warning(const char *fmt...)
: Log()
{
va_list ap;
va_start(ap,fmt);
str = QString::vasprintf(fmt,ap);
va_end(ap);
s.setString(&str, QIODevice::WriteOnly|QIODevice::Append);
}
Warning::~Warning()
{
if (!colorOverridden) color = Yellow;
}