/* * This file is part of the Flowee project * Copyright (C) 2020-2021 Tom Zander * * 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 . */ #include "BitcoinValue.h" #include "FloweePay.h" #include "NetDataProvider.h" #include "NewWalletConfig.h" #include "PortfolioDataProvider.h" #include "PriceDataProvider.h" #include "Payment.h" #include "QRCreator.h" #include // for ECC_Start() #include #include #include #include #include #include #include #include #include #include namespace { void HandleSigTerm(int) { QCoreApplication::quit(); } struct ECC_State { ECC_State() { // Init crypto lib. ECC_Start(); } ~ECC_State() { ECC_Stop(); } }; } // defined in qml_path_helper.cpp.in void handleLocalQml(QQmlApplicationEngine &engine); int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication qapp(argc, argv); qapp.setOrganizationName("flowee"); qapp.setApplicationName("pay"); qapp.setApplicationVersion("2021.07.0"); qapp.setWindowIcon(QIcon(":/FloweePay.png")); srand((quint32) QDateTime::currentMSecsSinceEpoch()); qmlRegisterType("Flowee.org.pay", 1, 0, "Bitcoin"); qmlRegisterType("Flowee.org.pay", 1, 0, "BitcoinValue"); qmlRegisterType("Flowee.org.pay", 1, 0, "NewWalletConfig"); qmlRegisterType("Flowee.org.pay", 1, 0, "Payment"); QCommandLineParser parser; parser.setApplicationDescription("Flowee pay"); QCommandLineOption debug(QStringList() << "debug", "Use debug level logging"); QCommandLineOption verbose(QStringList() << "verbose" << "v", "Be more verbose"); QCommandLineOption quiet(QStringList() << "quiet" << "q", "Be quiet, only errors are shown"); QCommandLineOption connect(QStringList() << "connect", "Connect to HOST", "HOST"); QCommandLineOption testnet4(QStringList() << "testnet4", "Use testnet4"); parser.addHelpOption(); parser.addOption(debug); parser.addOption(verbose); parser.addOption(quiet); parser.addOption(connect); parser.addOption(testnet4); // nice features to test your QML changes. QCommandLineOption offline(QStringList() << "offline", "Do not connect"); parser.addOption(offline); #ifndef NDEBUG // to protect people from the bad effect of having and later not having headers we only allow this // override in debug mode. QCommandLineOption headers(QStringList() << "headers", "Override location of blockheaders", "PATH"); parser.addOption(headers); #endif parser.process(qapp); auto *logger = Log::Manager::instance(); logger->clearChannels(); Log::Verbosity v = Log::WarningLevel; #ifndef BCH_NO_DEBUG_OUTPUT if (parser.isSet(debug)) v = Log::DebugLevel; else #endif if (parser.isSet(verbose)) v = Log::InfoLevel; else if (parser.isSet(quiet)) v = Log::FatalLevel; logger->clearLogLevels(v); logger->addConsoleChannel(); static const char* languagePacks[] = { "floweepay-desktop", "floweepay-common", "floweepay-mobile", nullptr }; for (int i = 0; languagePacks[i]; ++i) { auto *translator = new QTranslator(&qapp); if (translator->load(QLocale(), languagePacks[i], QLatin1String("_"), QLatin1String(":/i18n"))) QCoreApplication::installTranslator(translator); else delete translator; } PriceDataProvider prices; // select chain auto chain = P2PNet::MainChain; if (parser.isSet(testnet4)) chain = P2PNet::Testnet4Chain; if (parser.isSet(offline)) prices.mock(50000); else if (!parser.isSet(testnet4)) prices.start(); FloweePay::selectChain(chain); std::unique_ptr blockheaders; // pointer to own the memmapped blockheaders file. // lets try by default to open the path /usr/share/floweepay/* blockheaders.reset(new QFile(QString("/usr/share/floweepay/") + (chain == P2PNet::MainChain ? "blockheaders" : "blockheaders-testnet4"))); #ifndef NDEBUG // override only available in debug mode if (parser.isSet(headers)) { QFileInfo info(parser.value(headers)); if (info.exists()) { if (info.isDir()) blockheaders.reset(new QFile(info.absoluteFilePath() + (chain == P2PNet::MainChain ? "/blockheaders" : "/blockheaders-testnet4"))); else blockheaders.reset(new QFile(info.absoluteFilePath())); } else { // do not load if pointing to invalid path. logWarning() << "Headers disabled by cli option"; blockheaders.reset(); } } #endif if (blockheaders) { if (!blockheaders->open(QIODevice::ReadOnly)) { // can't be opened for reading. blockheaders.reset(); } else { Blockchain::setStaticChain(blockheaders->map(0, blockheaders->size()), blockheaders->size()); blockheaders->close(); } } ECC_State crypo_state; // allows the secp256k1 to function. qmlRegisterType("Flowee.org.pay", 1, 0, "TransactionInfo"); qmlRegisterType("Flowee.org.pay", 1, 0, "PaymentRequest"); QQmlApplicationEngine engine; engine.addImageProvider(QLatin1String("qr"), new QRCreator()); engine.rootContext()->setContextProperty("Pay", FloweePay::instance()); engine.rootContext()->setContextProperty("Fiat", &prices); handleLocalQml(engine); engine.load(engine.baseUrl().url() + "/main.qml"); QObject::connect(FloweePay::instance(), &FloweePay::loadComplete, &engine, [&engine, &parser, &connect, offline]() { FloweePay *app = FloweePay::instance(); NetDataProvider *netData = new NetDataProvider(app->p2pNet()->blockHeight(), &engine); app->p2pNet()->addP2PNetListener(netData); netData->startRefreshTimer(); PortfolioDataProvider *portfolio = new PortfolioDataProvider(&engine); for (auto &wallet : app->wallets()) { portfolio->addWalletAccount(wallet); } portfolio->selectDefaultWallet(); engine.rootContext()->setContextProperty("net", netData); engine.rootContext()->setContextProperty("portfolio", portfolio); if (parser.isSet(connect)) { app->p2pNet()->connectionManager().peerAddressDb().addOne( // actually connect to it too. EndPoint(parser.value(connect).toStdString(), 8333)); } if (!parser.isSet(offline)) app->p2pNet()->start(); // lets go! }); // Clean shutdown on SIGTERM struct sigaction sa; sa.sa_handler = HandleSigTerm; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGTERM, &sa, nullptr); sigaction(SIGINT, &sa, nullptr); // Ignore SIGPIPE signal(SIGPIPE, SIG_IGN); return qapp.exec(); }