199 lines
6.9 KiB
C++
199 lines
6.9 KiB
C++
/*
|
|
* This file is part of the Flowee project
|
|
* Copyright (C) 2019 Tom Zander <tom@flowee.org>
|
|
*
|
|
* 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";
|
|
else if (!logLevel.isEmpty())
|
|
qWarning() << "FLOWEE_LOGLEVEL not understood. Options are 'info', 'quiet' or 'silent'";
|
|
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();
|
|
}
|