// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers // // This file is part of Bytecoin. // // Bytecoin is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Bytecoin 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with Bytecoin. If not, see . #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 #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.walletFile, config.gateConfiguration.walletPassword }; } 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) { 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::INFO) << "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.walletFile, config.gateConfiguration.walletPassword }; service = new PaymentService::WalletService(currency, *dispatcher, node, walletConfiguration, logger); std::unique_ptr serviceGuard(service); try { service->init(); } catch (std::exception& e) { Logging::LoggerRef(logger, "run")(Logging::ERROR) << "Failed to init walletService reason: " << e.what(); return; } if (config.gateConfiguration.printAddresses) { // print addresses and exit size_t addressCount = 0; service->getAddressCount(addressCount); for (size_t i = 0; i < addressCount; ++i) { std::string address; if (service->getAddress(i, address) == std::error_code()) { 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) << "Couldn't save wallet: " << ex.what(); } } }