// Copyright (c) 2011-2016 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "PaymentGateService.h" #include #include "Common/SignalHandler.h" #include "InProcessNode/InProcessNode.h" #include "Logging/LoggerRef.h" #include "PaymentGate/PaymentServiceJsonRpcServer.h" #include "CryptoNoteCore/CoreConfig.h" #include "CryptoNoteCore/Core.h" #include "CryptoNoteProtocol/CryptoNoteProtocolHandler.h" #include "P2p/NetNode.h" #include "PaymentGate/WalletFactory.h" #include #ifdef ERROR #undef ERROR #endif #ifdef _WIN32 #include #else #include #endif using namespace PaymentService; void changeDirectory(const std::string& path) { if (chdir(path.c_str())) { throw std::runtime_error("Couldn't change directory to \'" + path + "\': " + strerror(errno)); } } void stopSignalHandler(PaymentGateService* pg) { pg->stop(); } bool PaymentGateService::init(int argc, char** argv) { if (!config.init(argc, argv)) { return false; } logger.setMaxLevel(static_cast(config.gateConfiguration.logLevel)); logger.addLogger(consoleLogger); Logging::LoggerRef log(logger, "main"); if (config.gateConfiguration.testnet) { log(Logging::INFO) << "Starting in testnet mode"; currencyBuilder.testnet(true); } if (!config.gateConfiguration.serverRoot.empty()) { changeDirectory(config.gateConfiguration.serverRoot); log(Logging::INFO) << "Current working directory now is " << config.gateConfiguration.serverRoot; } fileStream.open(config.gateConfiguration.logFile, std::ofstream::app); if (!fileStream) { throw std::runtime_error("Couldn't open log file"); } fileLogger.attachToStream(fileStream); logger.addLogger(fileLogger); return true; } WalletConfiguration PaymentGateService::getWalletConfig() const { return WalletConfiguration{ config.gateConfiguration.containerFile, config.gateConfiguration.containerPassword }; } const CryptoNote::Currency PaymentGateService::getCurrency() { return currencyBuilder.currency(); } void PaymentGateService::run() { System::Dispatcher localDispatcher; System::Event localStopEvent(localDispatcher); this->dispatcher = &localDispatcher; this->stopEvent = &localStopEvent; Tools::SignalHandler::install(std::bind(&stopSignalHandler, this)); Logging::LoggerRef log(logger, "run"); if (config.startInprocess) { runInProcess(log); } else { runRpcProxy(log); } this->dispatcher = nullptr; this->stopEvent = nullptr; } void PaymentGateService::stop() { Logging::LoggerRef log(logger, "stop"); log(Logging::INFO) << "Stop signal caught"; if (dispatcher != nullptr) { dispatcher->remoteSpawn([&]() { if (stopEvent != nullptr) { stopEvent->set(); } }); } } void PaymentGateService::runInProcess(Logging::LoggerRef& log) { if (!config.coreConfig.configFolderDefaulted) { if (!Tools::directoryExists(config.coreConfig.configFolder)) { throw std::runtime_error("Directory does not exist: " + config.coreConfig.configFolder); } } else { if (!Tools::create_directories_if_necessary(config.coreConfig.configFolder)) { throw std::runtime_error("Can't create directory: " + config.coreConfig.configFolder); } } log(Logging::INFO) << "Starting Payment Gate with local node"; CryptoNote::Currency currency = currencyBuilder.currency(); CryptoNote::core core(currency, NULL, logger); CryptoNote::CryptoNoteProtocolHandler protocol(currency, *dispatcher, core, NULL, logger); CryptoNote::NodeServer p2pNode(*dispatcher, protocol, logger); protocol.set_p2p_endpoint(&p2pNode); core.set_cryptonote_protocol(&protocol); log(Logging::INFO) << "initializing p2pNode"; if (!p2pNode.init(config.netNodeConfig)) { throw std::runtime_error("Failed to init p2pNode"); } log(Logging::INFO) << "initializing core"; CryptoNote::MinerConfig emptyMiner; core.init(config.coreConfig, emptyMiner, true); std::promise initPromise; auto initFuture = initPromise.get_future(); std::unique_ptr node(new CryptoNote::InProcessNode(core, protocol)); node->init([&initPromise, &log](std::error_code ec) { if (ec) { log(Logging::WARNING, Logging::YELLOW) << "Failed to init node: " << ec.message(); } else { log(Logging::INFO) << "node is inited successfully"; } initPromise.set_value(ec); }); auto ec = initFuture.get(); if (ec) { throw std::system_error(ec); } log(Logging::INFO) << "Spawning p2p server"; System::Event p2pStarted(*dispatcher); System::Context<> context(*dispatcher, [&]() { p2pStarted.set(); p2pNode.run(); }); p2pStarted.wait(); runWalletService(currency, *node); p2pNode.sendStopSignal(); context.get(); node->shutdown(); core.deinit(); p2pNode.deinit(); } void PaymentGateService::runRpcProxy(Logging::LoggerRef& log) { log(Logging::INFO) << "Starting Payment Gate with remote node"; CryptoNote::Currency currency = currencyBuilder.currency(); std::unique_ptr node( PaymentService::NodeFactory::createNode( config.remoteNodeConfig.daemonHost, config.remoteNodeConfig.daemonPort)); runWalletService(currency, *node); } void PaymentGateService::runWalletService(const CryptoNote::Currency& currency, CryptoNote::INode& node) { PaymentService::WalletConfiguration walletConfiguration{ config.gateConfiguration.containerFile, config.gateConfiguration.containerPassword }; std::unique_ptr wallet (WalletFactory::createWallet(currency, node, *dispatcher)); service = new PaymentService::WalletService(currency, *dispatcher, node, *wallet, walletConfiguration, logger); std::unique_ptr serviceGuard(service); try { service->init(); } catch (std::exception& e) { Logging::LoggerRef(logger, "run")(Logging::ERROR, Logging::BRIGHT_RED) << "Failed to init walletService reason: " << e.what(); return; } if (config.gateConfiguration.printAddresses) { // print addresses and exit std::vector addresses; service->getAddresses(addresses); for (const auto& address: addresses) { std::cout << "Address: " << address << std::endl; } } else { PaymentService::PaymentServiceJsonRpcServer rpcServer(*dispatcher, *stopEvent, *service, logger); rpcServer.start(config.gateConfiguration.bindAddress, config.gateConfiguration.bindPort); try { service->saveWallet(); } catch (std::exception& ex) { Logging::LoggerRef(logger, "saveWallet")(Logging::WARNING, Logging::YELLOW) << "Couldn't save container: " << ex.what(); } } }