2025-10-16 16:08:28 +01:00
// Copyright (c) 2017-2025 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// You may obtain a copy of the licence at:
//
// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
//
// The EUPL is a copyleft licence that is compatible with the MIT/X11
// licence used by the original projects; but maintains OSS status,
// where regional copyright law requires ownership to dictate licence terms.
//
// SPDX‑ License‑ Identifier: EUPL-1.2
//
2025-10-10 23:18:02 +01:00
# include "ApiServer.hpp"
2025-10-16 17:06:57 +01:00
# include "controller/ApiCoreInfo.hpp"
2025-10-16 16:08:28 +01:00
# include "controller/path/info.hpp"
# include "controller/path/block.hpp"
2025-10-17 18:40:11 +01:00
# include "controller/path/block/identifier.hpp"
2025-10-17 18:58:18 +01:00
# include "controller/path/block/height.hpp"
2025-10-16 17:06:57 +01:00
# include "controller/path/info/version.hpp"
2025-10-10 23:18:02 +01:00
# include "oatpp/network/Server.hpp"
# include "oatpp-swagger/Controller.hpp"
# include "version.h"
2025-10-15 22:28:49 +01:00
# include "common/command_line.h"
namespace
{
const command_line : : arg_descriptor < uint16_t > arg_api_bind_port = { " api-bind-port " , " Port for API server to bind to " , 36943 } ;
const command_line : : arg_descriptor < std : : string > arg_api_bind_host = { " api-bind-host " , " IP/Hostname for API server to bind to " , " 127.0.0.1 " } ;
}
uint16_t ApiServer : : m_port = 8000 ;
std : : string ApiServer : : m_host = " 127.0.0.1 " ;
void ApiServer : : init_options ( boost : : program_options : : options_description & desc ) {
command_line : : add_arg ( desc , arg_api_bind_port ) ;
command_line : : add_arg ( desc , arg_api_bind_host ) ;
}
2025-10-16 14:10:04 +01:00
ApiServer : : ApiServer ( const boost : : program_options : : variables_map & vm , currency : : core * ccore , p2psrv_t * p2p , currency : : core_rpc_server * rpc_server )
: m_vm ( vm ) , m_ccore ( ccore ) , m_p2p ( p2p ) , m_rpc_server ( rpc_server ) {
2025-10-15 22:28:49 +01:00
if ( vm . count ( arg_api_bind_port . name ) ) {
m_port = vm [ arg_api_bind_port . name ] . as < uint16_t > ( ) ;
}
if ( vm . count ( arg_api_bind_host . name ) ) {
m_host = vm [ arg_api_bind_host . name ] . as < std : : string > ( ) ;
}
}
2025-10-10 23:18:02 +01:00
void ApiServer : : run ( ) {
/* Register Components in scope of run() method */
Components components ;
2025-10-16 17:06:57 +01:00
OATPP_CREATE_COMPONENT ( std : : shared_ptr < ApiCoreInfo > , coreInfoComponent )
2025-10-16 14:10:04 +01:00
( [ this ] {
2025-10-16 17:06:57 +01:00
return std : : make_shared < ApiCoreInfo > ( * m_ccore , * m_p2p , * m_rpc_server ) ;
2025-10-16 14:10:04 +01:00
} ( ) ) ;
2025-10-10 23:18:02 +01:00
/* Get router component */
OATPP_COMPONENT ( std : : shared_ptr < oatpp : : web : : server : : HttpRouter > , router ) ;
auto docEndpoints = std : : make_shared < oatpp : : web : : server : : api : : Endpoints > ( ) ;
2025-10-16 17:06:57 +01:00
/*
* Create and register controllers , this list will get VERY large , but , it has to be this way as oatpp creates a
* static routing file before compile time , can ' t dynamically add controllers , or , be smart AND also have project code awareness
* by this list being large , it allows for per endpoint code separation ;
* any PR that tries to reduce this , MUST have unit tests to prove it works , no exceptions .
*/
2025-10-10 23:18:02 +01:00
auto infoController = std : : make_shared < InfoController > ( ) ;
docEndpoints - > append ( infoController - > getEndpoints ( ) ) ;
2025-10-16 16:08:28 +01:00
router - > addController ( infoController ) ;
2025-10-10 23:18:02 +01:00
2025-10-16 17:06:57 +01:00
auto infoVersionController = std : : make_shared < InfoVersionController > ( ) ;
docEndpoints - > append ( infoVersionController - > getEndpoints ( ) ) ;
router - > addController ( infoVersionController ) ;
2025-10-16 14:10:04 +01:00
auto blockController = std : : make_shared < BlockController > ( ) ;
docEndpoints - > append ( blockController - > getEndpoints ( ) ) ;
router - > addController ( blockController ) ;
2025-10-10 23:18:02 +01:00
2025-10-17 18:58:18 +01:00
auto blockHeightController = std : : make_shared < BlockHeightController > ( ) ;
docEndpoints - > append ( blockHeightController - > getEndpoints ( ) ) ;
router - > addController ( blockHeightController ) ;
2025-10-17 18:40:11 +01:00
auto blockIdentifierController = std : : make_shared < BlockIdentifierController > ( ) ;
docEndpoints - > append ( blockIdentifierController - > getEndpoints ( ) ) ;
router - > addController ( blockIdentifierController ) ;
2025-10-16 16:08:28 +01:00
2025-10-17 18:58:18 +01:00
2025-10-10 23:18:02 +01:00
OATPP_CREATE_COMPONENT ( std : : shared_ptr < oatpp : : swagger : : DocumentInfo > , swaggerDocumentInfo )
( [ ]
{
oatpp : : swagger : : DocumentInfo : : Builder builder ;
builder
. setTitle ( " Lethean Blockchain API " )
2025-10-15 22:28:55 +01:00
. setDescription ( " OpenAPI for Lethean Blockchain " )
2025-10-10 23:18:02 +01:00
. setVersion ( PROJECT_VERSION )
. setContactName ( " Lethean " )
. setContactUrl ( " https://lt.hn/ " )
. setLicenseName ( " EUPL-1.2 " )
. setLicenseUrl ( " https://joinup.ec.europa.eu/software/page/eupl/licence-eupl " )
2025-10-15 22:28:55 +01:00
. addServer ( " http:// " + ApiServer : : m_host + " : " + std : : to_string ( ApiServer : : m_port ) , " Local Daemon " )
. addServer ( " http://seed.lethean.io:36943 " , " Seed Server " ) ;
2025-10-10 23:18:02 +01:00
return builder . build ( ) ; } ( ) ) ;
/* Create a Swagger-UI controller and add its endpoints to the router */
auto swaggerController = oatpp : : swagger : : Controller : : createShared ( * docEndpoints ) ;
router - > addController ( swaggerController ) ;
/* Get a connection handler component */
OATPP_COMPONENT ( std : : shared_ptr < oatpp : : network : : ConnectionHandler > , connectionHandler ) ;
/* Get a connection provider component */
OATPP_COMPONENT ( std : : shared_ptr < oatpp : : network : : ServerConnectionProvider > , connectionProvider ) ;
/* Create a server which takes provided TCP connections and passes them to the HTTP connection handler */
2025-10-15 20:58:57 +01:00
m_server = std : : make_shared < oatpp : : network : : Server > ( connectionProvider , connectionHandler ) ;
2025-10-10 23:18:02 +01:00
/* Print server port */
OATPP_LOGI ( " lethean-api " , " Server running, API Docs: http://127.0.0.1:%s/swagger/ui " , static_cast < const char * > ( connectionProvider - > getProperty ( " port " ) . getData ( ) ) ) ;
/* Run server */
2025-10-15 20:58:57 +01:00
m_server - > run ( ) ;
2025-10-10 23:18:02 +01:00
}
2025-10-15 20:58:57 +01:00
void ApiServer : : start ( ) {
m_server_thread = std : : thread ( & ApiServer : : run , this ) ;
}
2025-10-16 18:39:25 +01:00
void ApiServer : : stop ( ) const
{
2025-10-15 20:58:57 +01:00
if ( m_server ) {
m_server - > stop ( ) ;
}
}
void ApiServer : : wait ( ) {
if ( m_server_thread . joinable ( ) ) {
m_server_thread . join ( ) ;
}
}