Files
less_shitty_proxyjs/main.cpp
0xFEEDC0DE64 c2a9aea916
Some checks failed
Build and push docker image / build (push) Failing after 1m40s
100% kubernetes scalable now
2025-08-17 22:39:03 +02:00

216 lines
7.5 KiB
C++

#include <QCoreApplication>
#include <QCommandLineParser>
#include "webserver.h"
#ifdef FEATURE_REDIS
#include <hiredis/async.h>
#include "redisqtadapter.h"
#endif
#include <QTcpServer>
#include <QDebug>
#include <QUuid>
static QHostAddress parseHostAddress(const QString &str);
int main(int argc, char *argv[])
{
qSetMessagePattern("%{time dd.MM.yyyy HH:mm:ss.zzz} "
"["
"%{if-debug}D%{endif}"
"%{if-info}I%{endif}"
"%{if-warning}W%{endif}"
"%{if-critical}C%{endif}"
"%{if-fatal}F%{endif}"
"] "
"%{function}(): "
"%{message}");
QCoreApplication app{argc, argv};
QCoreApplication::setApplicationName("less_shitty_proxyjs");
QCoreApplication::setApplicationVersion("1.0");
QHostAddress listenAddress = QHostAddress::Any;
if (auto str = qgetenv("PROXYJS_LISTEN_ADDR"); !str.isEmpty())
listenAddress = parseHostAddress(str);
uint16_t port = 8080;
if (auto str = qgetenv("PROXYJS_PORT"); !str.isEmpty())
port = str.toInt();
QString identity = "proxyjs_" + QUuid::createUuid().toString(QUuid::WithoutBraces);
if (auto str = qgetenv("PROXYJS_IDENTITY"); !str.isEmpty())
identity = str;
#ifdef FEATURE_REDIS
QString redisHost = "localhost";
if (auto str = qgetenv("PROXYJS_REDIS_HOST"); !str.isEmpty())
redisHost = str;
QString redisPassword;
if (auto str = qgetenv("PROXYJS_REDIS_PASSWORD"); !str.isEmpty())
redisPassword = str;
QString endpointAddr;
if (auto str = qgetenv("PROXYJS_ENDPOINT_ADDR"); !str.isEmpty())
endpointAddr = str;
#endif
{
QCommandLineParser parser;
parser.setApplicationDescription("Test helper");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption listenAddrOption{QStringList{ "l", "listenAddress" },
QCoreApplication::translate("main", "The address to listen on (Can be \"Any\" \"Localhost\" or any valid ip address)."),
QCoreApplication::translate("main", "listenAddress")};
parser.addOption(listenAddrOption);
QCommandLineOption portOption{QStringList{ "p", "port" },
QCoreApplication::translate("main", "The port to listen on (will only listen on localhost)."),
QCoreApplication::translate("main", "port")};
parser.addOption(portOption);
QCommandLineOption identityOption{QStringList{ "i", "identity" },
QCoreApplication::translate("main", "The name of this service instance"),
QCoreApplication::translate("main", "identity")};
parser.addOption(identityOption);
#ifdef FEATURE_REDIS
QCommandLineOption redisHostOption{QStringList{ "H", "redisHost" },
QCoreApplication::translate("main", "The redis host"),
QCoreApplication::translate("main", "redisHost")};
parser.addOption(redisHostOption);
QCommandLineOption redisPasswordOption{QStringList{ "r", "redisPassword" },
QCoreApplication::translate("main", "The redis password"),
QCoreApplication::translate("main", "redisPassword")};
parser.addOption(redisPasswordOption);
QCommandLineOption endpointAddrOption{QStringList{ "e", "endpointAddr" },
QCoreApplication::translate("main", "Endpoint address for traefik"),
QCoreApplication::translate("main", "endpointAddr")};
parser.addOption(endpointAddrOption);
#endif
parser.process(app);
if (parser.isSet(listenAddrOption))
{
listenAddress = parseHostAddress(parser.value(listenAddrOption));
}
if (parser.isSet(portOption))
{
const auto &str = parser.value(portOption);
bool ok;
port = str.toInt(&ok);
if (!ok)
{
qCritical("could not parse port: %s", qPrintable(str));
return -1;
}
}
if (parser.isSet(identityOption))
identity = parser.value(identityOption);
#ifdef FEATURE_REDIS
if (parser.isSet(redisHostOption))
redisHost = parser.value(redisHostOption);
if (parser.isSet(redisPasswordOption))
redisPassword = parser.value(redisPasswordOption);
if (parser.isSet(endpointAddrOption))
endpointAddr = parser.value(endpointAddrOption);
#endif
}
#ifdef FEATURE_REDIS
if (endpointAddr.isEmpty())
endpointAddr = QString{"http://localhost:%0"}.arg(port);
#endif
qSetMessagePattern(QString{"%{time dd.MM.yyyy HH:mm:ss.zzz} %0 "
"["
"%{if-debug}D%{endif}"
"%{if-info}I%{endif}"
"%{if-warning}W%{endif}"
"%{if-critical}C%{endif}"
"%{if-fatal}F%{endif}"
"] "
"%{function}(): "
"%{message}"}.arg(identity));
#ifdef FEATURE_REDIS
redisAsyncContext * const redis = redisAsyncConnect(redisHost.toUtf8().constData(), 6379);
if (redis->err)
qFatal("error with redis connection: %s", redis->errstr);
RedisQtAdapter redisAdapter;
redisAdapter.setContext(redis);
if (!redisPassword.isEmpty())
{
qDebug() << "redis AUTH" << redisPassword;
redisAsyncCommand(redis, NULL, NULL, "AUTH %s",
redisPassword.toUtf8().constData());
}
qDebug() << "redis connected";
#endif
WebServer server{identity
#ifdef FEATURE_REDIS
, redis
#endif
};
QTcpServer tcpServer;
if (!tcpServer.listen(listenAddress, port))
{
qCritical("failed to start listening on addr %s port %hu: %s", qPrintable(listenAddress.toString()), port, qPrintable(tcpServer.errorString()));
return -1;
}
if (!server.bind(&tcpServer))
{
qCritical("failed to webserver on socket!");
return -2;
}
#ifdef FEATURE_REDIS
redisAsyncCommand(redis, NULL, NULL, "SET %s %s",
QString{"traefik/http/services/%0/loadbalancer/servers/0/url"}
.arg(identity).toUtf8().constData(),
endpointAddr.toUtf8().constData()
);
#endif
qDebug() << "server started on" << listenAddress << "port" << port;
auto result = app.exec();
#ifdef FEATURE_REDIS
redisAsyncCommand(redis, NULL, NULL, "DEL %s",
QString{"traefik/http/services/%0/loadbalancer/servers/0/url"}
.arg(identity).toUtf8().constData());
#endif
qDebug() << "bey bey!";
return result;
}
static QHostAddress parseHostAddress(const QString &str)
{
if (str == "Any")
return QHostAddress::Any;
else if (str == "AnyIPv4")
return QHostAddress::AnyIPv4;
else if (str == "AnyIPv6")
return QHostAddress::AnyIPv6;
else if (str == "LocalHost")
return QHostAddress::LocalHost;
else if (str == "LocalHostIPv6")
return QHostAddress::LocalHostIPv6;
else
return QHostAddress{str};
}