Files
2021-06-20 22:44:44 +02:00

199 lines
6.4 KiB
C++

/*
* This file is part of the Flowee project
* Copyright (C) 2019-2020 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>
#include <ifaddrs.h>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE /* To get defns of NI_MAXHOST */
#endif
#include <netdb.h>
/*
Interprets env vars;
FLOWEE_HUB=host:port
FLOWEE_INDEXER=host:port
FLOWEE_HUBS=host:port
FLOWEE_INDEXERS=host:port
FLOWEE_JSON_VERBOSE=x
*/
static QProcess *proc = new QProcess();
QStringList hubs()
{
QStringList answer;
const char *flowee_hub = getenv("FLOWEE_HUB");
const char *flowee_hubs = getenv("FLOWEE_HUBS");
if (flowee_hub)
answer.append(QString::fromLocal8Bit(flowee_hub));
if (flowee_hubs) {
for (auto h : QString::fromLocal8Bit(flowee_hubs).split(QRegExp("[ ,;&]"), QString::SkipEmptyParts)) {
answer.append(h);
}
}
if (answer.isEmpty()) {
qWarning() << "No info passed where to find the Hub, trying localhost";
qWarning() << "Suggest to pass FLOWEE_HUB with 'IP' or 'IP:port' where a running Hub can be found";
answer.append("localhost");
}
return answer;
}
QStringList indexers()
{
QStringList answer;
const char *flowee_indexer = getenv("FLOWEE_INDEXER");
const char *flowee_indexers = getenv("FLOWEE_INDEXERS");
if (flowee_indexer)
answer.append(QString::fromLocal8Bit(flowee_indexer));
if (flowee_indexers) {
for (auto h : QString::fromLocal8Bit(flowee_indexers).split(QRegExp("[ ,;&]"), QString::SkipEmptyParts)) {
answer.append(h);
}
}
if (answer.isEmpty()) {
qWarning() << "No info passed where to find the indexer, trying localhost";
qWarning() << "Suggest to pass FLOWEE_INDEXER with 'IP' or 'IP:port' where a running indexer can be found";
answer.append("localhost");
}
return answer;
}
void HandleSignals(int) {
qWarning() << "Docker: TERM received";
qint64 pid = proc->processId();
if (pid > 0) kill(pid, SIGTERM); // politely tell the proc to terminate
}
int main(int x, char**y) {
QCoreApplication app(x,y);
const QDir confDir(QDir::homePath() + "/.config/flowee/bitcore-proxy");
confDir.mkpath(".");
QFile configFile(confDir.absolutePath() + "/bitcore-proxy.conf");
if (!configFile.open(QIODevice::WriteOnly)) {
qWarning() << "Can't write conf file";
} else {
QTextStream out(&configFile);
out << "# autogenerated flowee bitcore-proxy config\n\n[services]\n";
for (auto h : hubs()) {
out << "hub=" << h << endl;
}
for (auto i : indexers()) {
out << "indexer=" << i << endl;
}
if (getenv("FLOWEE_JSON_VERBOSE"))
out << "\n[json]\ncompact=false\n";
configFile.close();
}
QFile logsFile(confDir.absolutePath() + "/logs.conf");
if (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";
QString logLevel = getenv("FLOWEE_LOGLEVEL");
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() + "/bitcore-proxy.conf";
// the http server can only listen on one interface and defaults to localhost.
// We should listen on the public interface instead in order to make standard (bridge) docker
// networking work and allow port forwarding which won't work when binding on localhost.
struct ifaddrs *ifaddr;
if (getifaddrs(&ifaddr) != -1) {
for (struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr)
continue;
int family = ifa->ifa_addr->sa_family;
if (family != AF_INET || ifa->ifa_addr->sa_data[2] == 127)
continue;
char host[NI_MAXHOST];
if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST) == 0) {
args << QString("--bind") << QString(host);
break;
}
freeifaddrs(ifaddr);
}
}
proc->setReadChannel(QProcess::StandardOutput);
proc->start(QLatin1String("/usr/bin/rest-service"), args, QIODevice::ReadOnly);
proc->waitForReadyRead(20000);
if (proc->state() == QProcess::NotRunning) { // time out
qWarning() << "ERROR: rest-service(v2) fails to start, timing out";
proc->kill();
return 1;
}
QTextStream out(stdout);
while (true) {
auto logData = proc->readAllStandardError();
out << logData;
logData = proc->readAllStandardOutput();
out << logData;
if (proc->state() != QProcess::Running)
break;
out.flush();
proc->waitForReadyRead(20000);
}
fflush(NULL);
sync();
return proc->exitCode();
}