Files

199 lines
6.9 KiB
C++
Raw Permalink Normal View History

2019-09-08 17:27:48 +02:00
/*
* This file is part of the Flowee project
2021-06-20 22:44:44 +02:00
* Copyright (C) 2019 Tom Zander <tom@flowee.org>
2019-09-08 17:27:48 +02:00
*
* This program 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.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QCoreApplication>
#include <QDir>
#include <QTextStream>
#include <QProcess>
#include <qdebug.h>
#include <unistd.h>
#include <signal.h>
/*
Interprets env vars;
FLOWEE_INDEXERS
list of indexers to enable. For instance: =txid, address, spent
FLOWEE_DB
list of variables to connect to the DB
driver=postgres,hostname=localhost,db=flowee,username=flowee_indexer,password=SECRET
FLOWEE_HUB=host:port
FLOWEE_LOGLEVEL
info, quiet or silent
*/
static QProcess *indexer = new QProcess();
void HandleSignals(int) {
qWarning() << "Docker: TERM received";
qint64 pid = indexer->processId();
if (pid > 0) kill(pid, SIGTERM); // politely tell the indexer to terminate
}
int main(int x, char**y) {
QCoreApplication app(x,y);
QDir data("/data");
if (!data.exists()) {
qWarning() << "No volume found on /data, refusing to start";
return 1;
}
const QDir confDir(QDir::homePath() + "/.config/flowee/indexer");
confDir.mkpath(".");
QFile configFile(confDir.absolutePath() + "/indexer.conf");
if (!configFile.open(QIODevice::WriteOnly)) {
qWarning() << "Can't write conf file";
} else {
QTextStream out(&configFile);
out << "# autogenerated flowee indexer config\n";
QString dbSpec = getenv("FLOWEE_DB");
QStringList pairs = dbSpec.split(QRegExp("[ ,;&]"), QString::SkipEmptyParts);
for (auto pair : pairs) {
QStringList items = pair.split("=");
if (items.size() != 2) {
qWarning() << "DB item not understood:" << pair;
continue;
}
auto token = items.at(0).toLower();
if (token == "driver") {
auto driver = items.at(1).toUpper();
if (driver.startsWith("POSTGRES") || driver == "PSQL") {
driver = "QPSQL";
}
// TODO support other drivers
out << "db_driver=" << driver << endl;
}
else if (token == "hostname") {
out << "db_hostname=" << items.at(1) << endl;
}
else if (token == "db" || token == "database") {
out << "db_database=" << items.at(1) << endl;
}
else if (token == "user" || token == "username" || token == "uname") {
out << "db_username=" << items.at(1) << endl;
}
else if (token == "pwd" || token == "password" || token == "passwd") {
out << "db_password=" << items.at(1) << endl;
}
}
out << endl;
QString indexers = getenv("FLOWEE_INDEXERS");
if (indexers.isEmpty())
indexers = "txid";
QStringList components = indexers.split(QRegExp("[, :;]"), QString::SkipEmptyParts);
for (auto c : components) {
if (c.compare("txid", Qt::CaseInsensitive) == 0
|| c.compare("txdb", Qt::CaseInsensitive) == 0
|| c == "transaction-id") {
out << "[txdb]\nenabled=true\n\n";
}
else if (c.compare("addressdb", Qt::CaseInsensitive) == 0
|| c.compare("address", Qt::CaseInsensitive) == 0
|| c.compare("addresses", Qt::CaseInsensitive) == 0) {
out << "[addressdb]\nenabled=true\n\n";
}
else if (c.compare("spentdb", Qt::CaseInsensitive) == 0
|| c.compare("spenddb", Qt::CaseInsensitive) == 0
|| c.compare("spend", Qt::CaseInsensitive) == 0
|| c.compare("spent", Qt::CaseInsensitive) == 0) {
out << "[spentdb]\nenabled=true\n\n";
}
}
configFile.close();
}
QFile logsFile(confDir.absolutePath() + "/logs.conf");
QString logLevel = getenv("FLOWEE_LOGLEVEL");
if (logLevel.isEmpty() && logsFile.exists()) {
qWarning() << "Not changing existing logs.conf";
}
else if (!logsFile.open(QIODevice::WriteOnly)) {
qWarning() << "Can't write logs.conf file" << confDir.absoluteFilePath("logs.conf");
}
else {
QTextStream out(&logsFile);
out << "# Flowee logging config.\n"
"channel console\n"
" option timestamp\n"
"channel file\n"
" option timestamp date time\n"
" option path /data/indexer.log\n";
if (logLevel.toLower() == "info")
out << "\nALL info\n";
else if (logLevel.toLower() == "quiet")
out << "\nALL quiet\n";
else if (logLevel.toLower() == "silent")
out << "\nALL silent\n";
2019-10-08 12:40:18 +02:00
else if (!logLevel.isEmpty())
qWarning() << "FLOWEE_LOGLEVEL not understood. Options are 'info', 'quiet' or 'silent'";
2019-09-08 17:27:48 +02:00
logsFile.close();
}
struct sigaction sa;
sa.sa_handler = HandleSignals;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
// Ignore SIGPIPE
signal(SIGPIPE, SIG_IGN);
QStringList args;
args << "--conf" << confDir.absolutePath() + "/indexer.conf"
<< "--datadir" << "/data"
<< "--bind" << "0.0.0.0:1234";
if (getenv("FLOWEE_HUB")) {
QString hub = getenv("FLOWEE_HUB");
args << "--connect" << hub;
} else {
qWarning() << "WARNING: Without FLOWEE_HUB env-var we will not get updated!";
}
indexer->setReadChannel(QProcess::StandardOutput);
indexer->start(QLatin1String("/usr/bin/indexer"), args, QIODevice::ReadOnly);
indexer->waitForReadyRead(20000);
if (indexer->state() == QProcess::NotRunning) { // time out
qWarning() << "ERROR: indexer fails to start, timing out";
indexer->kill();
return 1;
}
QTextStream out(stdout);
while (true) {
auto logData = indexer->readAllStandardError();
out << logData;
logData = indexer->readAllStandardOutput();
out << logData;
if (indexer->state() != QProcess::Running)
break;
out.flush();
indexer->waitForReadyRead(20000);
}
fflush(NULL);
sync();
return indexer->exitCode();
}