2017-08-08 13:53:47 +02:00
# include "server_http.hpp"
# include "client_http.hpp"
# define BOOST_SPIRIT_THREADSAFE
# include <boost/property_tree/ptree.hpp>
# include <boost/property_tree/xml_parser.hpp>
# include <boost/property_tree/json_parser.hpp>
2018-03-06 22:22:19 +01:00
# include <Logging/Logger.h>
2018-06-10 16:34:26 +00:00
# include <Config/ConfigMgr.h>
2017-08-08 13:53:47 +02:00
2018-03-06 22:22:19 +01:00
# include <Network/Connection.h>
# include <Network/Hive.h>
# include <Network/Acceptor.h>
2017-08-08 13:53:47 +02:00
2018-03-06 22:22:19 +01:00
# include <Exd/ExdDataGenerated.h>
# include <Crypt/base64.h>
2017-08-08 13:53:47 +02:00
2018-03-06 22:22:19 +01:00
# include <Database/DbLoader.h>
# include <Database/CharaDbConnection.h>
# include <Database/DbWorkerPool.h>
# include <Database/PreparedStatement.h>
2017-10-07 23:10:13 +02:00
2017-08-08 13:53:47 +02:00
//Added for the default_resource example
# include <fstream>
# include <string>
# include <boost/filesystem.hpp>
2017-08-10 22:13:00 +01:00
# include <boost/make_shared.hpp>
2017-08-08 13:53:47 +02:00
# include <vector>
# include <algorithm>
2018-03-09 00:06:44 +01:00
# include <Framework.h>
2017-08-08 13:53:47 +02:00
# include "Forwards.h"
# include "SapphireAPI.h"
2018-03-09 00:06:44 +01:00
Core : : Framework g_fw ;
2017-08-08 13:53:47 +02:00
Core : : Logger g_log ;
2017-10-07 23:10:13 +02:00
Core : : Db : : DbWorkerPool < Core : : Db : : CharaDbConnection > g_charaDb ;
2018-01-31 11:43:22 +01:00
Core : : Data : : ExdDataGenerated g_exdDataGen ;
2017-08-08 13:53:47 +02:00
Core : : Network : : SapphireAPI g_sapphireAPI ;
using namespace std ;
using namespace boost : : property_tree ;
2017-11-19 22:43:26 +01:00
using HttpServer = SimpleWeb : : Server < SimpleWeb : : HTTP > ;
using HttpClient = SimpleWeb : : Client < SimpleWeb : : HTTP > ;
2017-08-08 13:53:47 +02:00
//Added for the default_resource example
2017-10-26 12:16:34 +02:00
void default_resource_send ( const HttpServer & server , const shared_ptr < HttpServer : : Response > & response ,
const shared_ptr < ifstream > & ifs ) ;
2017-08-08 13:53:47 +02:00
2017-08-10 22:13:00 +01:00
2018-06-10 16:34:26 +00:00
auto m_pConfig = boost : : make_shared < Core : : ConfigMgr > ( ) ;
2017-08-10 22:13:00 +01:00
HttpServer server ;
2018-06-10 16:34:26 +00:00
std : : string configPath ( " rest.ini " ) ;
2017-08-10 22:13:00 +01:00
void reloadConfig ( )
{
2018-06-10 16:34:26 +00:00
m_pConfig = boost : : make_shared < Core : : ConfigMgr > ( ) ;
2017-08-10 22:13:00 +01:00
2017-10-26 12:16:34 +02:00
if ( ! m_pConfig - > loadConfig ( configPath ) )
2017-08-10 23:33:46 +01:00
throw " Error loading config " ;
2017-08-10 22:13:00 +01:00
}
2017-10-26 12:16:34 +02:00
void print_request_info ( shared_ptr < HttpServer : : Request > request )
{
2017-08-08 13:53:47 +02:00
g_log . info ( " Request from " + request - > remote_endpoint_address + " ( " + request - > path + " ) " ) ;
}
2017-10-26 12:16:34 +02:00
2017-08-11 22:56:30 +01:00
bool loadSettings ( int32_t argc , char * argv [ ] )
2017-08-08 13:53:47 +02:00
{
2017-08-10 22:13:00 +01:00
g_log . info ( " Loading config " + configPath ) ;
2017-08-08 13:53:47 +02:00
2017-08-10 22:13:00 +01:00
if ( ! m_pConfig - > loadConfig ( configPath ) )
{
g_log . fatal ( " Error loading config " + configPath ) ;
return false ;
}
2017-08-08 13:53:47 +02:00
2017-08-10 22:13:00 +01:00
std : : vector < std : : string > args ( argv + 1 , argv + argc ) ;
2017-10-19 07:12:09 -07:00
for ( size_t i = 0 ; i + 1 < args . size ( ) ; i + = 2 )
2017-08-10 22:13:00 +01:00
{
std : : string arg ( " " ) ;
std : : string val ( " " ) ;
2017-08-08 13:53:47 +02:00
2017-08-10 22:13:00 +01:00
try
{
arg = boost : : to_lower_copy ( std : : string ( args [ i ] ) ) ;
val = std : : string ( args [ i + 1 ] ) ;
2017-08-08 13:53:47 +02:00
2017-08-10 22:13:00 +01:00
// trim '-' from start of arg
arg = arg . erase ( 0 , arg . find_first_not_of ( ' - ' ) ) ;
if ( arg = = " ip " )
{
2018-06-23 21:05:31 +02:00
m_pConfig - > setValue < std : : string > ( " RestNetwork.ListenIp " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " p " | | arg = = " port " )
{
2018-06-23 21:05:31 +02:00
m_pConfig - > setValue < std : : string > ( " RestNetwork.ListenPort " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " exdpath " | | arg = = " datapath " )
{
2018-06-10 16:34:26 +00:00
m_pConfig - > setValue < std : : string > ( " GlobalParameters.DataPath " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " h " | | arg = = " dbhost " )
{
2018-06-10 16:34:26 +00:00
m_pConfig - > setValue < std : : string > ( " Database.Host " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " dbport " )
{
2018-06-10 16:34:26 +00:00
m_pConfig - > setValue < std : : string > ( " Database.Port " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " u " | | arg = = " user " | | arg = = " dbuser " )
{
2018-06-10 16:34:26 +00:00
m_pConfig - > setValue < std : : string > ( " Database.Username " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " pass " | | arg = = " dbpass " )
{
2018-06-10 16:34:26 +00:00
m_pConfig - > setValue < std : : string > ( " Database.Password " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " d " | | arg = = " db " | | arg = = " database " )
{
2018-06-10 16:34:26 +00:00
m_pConfig - > setValue < std : : string > ( " Database.Database " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " lobbyip " | | arg = = " lobbyhost " )
{
2018-06-10 16:34:26 +00:00
m_pConfig - > setValue < std : : string > ( " GlobalNetwork.LobbyHost " , val ) ;
2017-08-10 22:13:00 +01:00
}
else if ( arg = = " lobbyport " )
{
2018-06-10 16:34:26 +00:00
m_pConfig - > setValue < std : : string > ( " GlobalNetwork.LobbyPort " , val ) ;
2017-08-10 22:13:00 +01:00
}
}
catch ( . . . )
{
g_log . error ( " Error parsing argument: " + arg + " " + " value: " + val + " \n " ) ;
g_log . error ( " Usage: <arg> <val> \n " ) ;
}
2017-08-08 13:53:47 +02:00
}
2018-01-31 11:43:22 +01:00
g_log . info ( " Setting up generated EXD data " ) ;
2018-06-10 16:34:26 +00:00
if ( ! g_exdDataGen . init ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.DataPath " , " " ) ) )
2017-08-08 13:53:47 +02:00
{
2018-01-31 11:43:22 +01:00
g_log . fatal ( " Error setting up generated EXD data " ) ;
2017-08-10 22:13:00 +01:00
return false ;
2017-08-08 13:53:47 +02:00
}
2017-10-07 23:10:13 +02:00
Core : : Db : : DbLoader loader ;
Core : : Db : : ConnectionInfo info ;
2018-06-10 16:34:26 +00:00
info . password = m_pConfig - > getValue < std : : string > ( " Database.Password " , " " ) ;
info . host = m_pConfig - > getValue < std : : string > ( " Database.Host " , " 127.0.0.1 " ) ;
info . database = m_pConfig - > getValue < std : : string > ( " Database.Database " , " sapphire " ) ;
info . port = m_pConfig - > getValue < uint16_t > ( " Database.Port " , 3306 ) ;
info . user = m_pConfig - > getValue < std : : string > ( " Database.Username " , " root " ) ;
info . syncThreads = m_pConfig - > getValue < uint8_t > ( " Database.SyncThreads " , 2 ) ;
info . asyncThreads = m_pConfig - > getValue < uint8_t > ( " Database.AsyncThreads " , 2 ) ;
2017-10-07 23:10:13 +02:00
loader . addDb ( g_charaDb , info ) ;
if ( ! loader . initDbs ( ) )
return false ;
2018-06-23 21:05:31 +02:00
server . config . port = static_cast < uint16_t > ( std : : stoul ( m_pConfig - > getValue < std : : string > ( " RestNetwork.ListenPort " , " 80 " ) ) ) ;
server . config . address = m_pConfig - > getValue < std : : string > ( " RestNetwork.ListenIp " , " 0.0.0.0 " ) ;
2017-08-10 22:13:00 +01:00
2017-10-26 12:16:34 +02:00
g_log . info ( " Database: Connected to " + info . host + " : " + std : : to_string ( info . port ) ) ;
2017-08-10 22:13:00 +01:00
return true ;
}
2017-12-04 11:00:08 +01:00
using ContentType = enum
2017-08-10 22:13:00 +01:00
{
2017-12-04 11:00:08 +01:00
NONE ,
TEXT_PLAIN ,
JSON ,
XML ,
} ;
2017-08-10 22:13:00 +01:00
2017-12-04 11:00:08 +01:00
std : : string buildHttpResponse ( uint16_t rCode , const std : : string & content = " " , ContentType type = NONE )
{
std : : string result { " " } ;
std : : string httpHead { " HTTP/1.1 " } ;
std : : string contentHeader { " Content-Length: " } ;
std : : string contentTypeHeader { " Content-Type: " } ;
2017-08-10 22:13:00 +01:00
2017-12-04 11:00:08 +01:00
switch ( type )
2017-08-10 22:13:00 +01:00
{
2017-12-04 11:00:08 +01:00
case NONE :
contentTypeHeader = " " ;
break ;
case TEXT_PLAIN :
contentTypeHeader + = " text/plain \r \n " ;
break ;
case JSON :
contentTypeHeader + = " application/json \r \n " ;
break ;
case XML :
contentTypeHeader + = " text/xml \r \n " ;
break ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
switch ( rCode )
{
case 200 :
result + = httpHead + " 200 OK \r \n " ;
if ( content . size ( ) > 0 )
{
result + = contentTypeHeader ;
result + = contentHeader + std : : to_string ( content . size ( ) ) + " \r \n " ;
}
break ;
case 400 :
case 401 :
case 402 :
case 403 :
result + = httpHead + std : : to_string ( rCode ) + " \r \n " ;
if ( content . size ( ) > 0 )
{
result + = contentTypeHeader ;
result + = contentHeader + std : : to_string ( content . size ( ) ) + " \r \n " ;
}
break ;
case 500 :
result + = httpHead + " 500 Internal Server Error \r \n " ;
break ;
default :
result + = httpHead + std : : to_string ( rCode ) + " \r \n " ;
}
result + = " \r \n " ;
if ( content . size ( ) > 0 )
result + = content ;
return result ;
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void getZoneName ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
string number = request - > path_match [ 1 ] ;
2018-02-14 12:31:47 +01:00
auto info = g_exdDataGen . get < Core : : Data : : TerritoryType > ( atoi ( number . c_str ( ) ) ) ;
2017-12-04 11:00:08 +01:00
std : : string responseStr = " Not found! " ;
2018-01-31 11:43:22 +01:00
if ( info )
responseStr = info - > name + " , " + info - > bg ;
2017-12-04 11:00:08 +01:00
* response < < buildHttpResponse ( 200 , responseStr ) ;
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void createAccount ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
std : : string pass = pt . get < string > ( " pass " ) ;
std : : string user = pt . get < string > ( " username " ) ;
// reloadConfig();
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
std : : string sId ;
if ( g_sapphireAPI . createAccount ( user , pass , sId ) )
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" sId \" : \" " + sId +
2018-06-10 16:34:26 +00:00
" \" , \" lobbyHost \" : \" " + m_pConfig - > getValue < std : : string > ( " GlobalNetwork.LobbyHost " ) +
" \" , \" frontierHost \" : \" " + m_pConfig - > getValue < std : : string > ( " GlobalNetwork.RestHost " ) + " \" } " ;
2017-12-04 11:00:08 +01:00
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
}
else
* response < < buildHttpResponse ( 400 ) ;
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void login ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
std : : string pass = pt . get < string > ( " pass " ) ;
std : : string user = pt . get < string > ( " username " ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
std : : string sId ;
2017-08-10 22:13:00 +01:00
2017-12-04 11:00:08 +01:00
// reloadConfig();
if ( g_sapphireAPI . login ( user , pass , sId ) )
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" sId \" : \" " + sId +
2018-06-10 16:34:26 +00:00
" \" , \" lobbyHost \" : \" " + m_pConfig - > getValue < std : : string > ( " GlobalNetwork.LobbyHost " ) +
" \" , \" frontierHost \" : \" " + m_pConfig - > getValue < std : : string > ( " GlobalNetwork.RestHost " ) + " \" } " ;
2017-12-04 11:00:08 +01:00
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
else
* response < < buildHttpResponse ( 400 ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void deleteCharacter ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
std : : string sId = pt . get < string > ( " sId " ) ;
std : : string secret = pt . get < string > ( " secret " ) ;
std : : string name = pt . get < string > ( " name " ) ;
// reloadConfig();
2017-08-10 22:13:00 +01:00
2017-12-04 11:00:08 +01:00
int32_t accountId = g_sapphireAPI . checkSession ( sId ) ;
2017-08-08 13:53:47 +02:00
2018-06-10 16:34:26 +00:00
if ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.ServerSecret " ) ! = secret )
2017-12-04 11:00:08 +01:00
{
std : : string json_string = " { \" result \" : \" invalid_secret \" } " ;
* response < < buildHttpResponse ( 403 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
else
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
g_sapphireAPI . deleteCharacter ( name , accountId ) ;
std : : string json_string = " { \" result \" : \" success \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void createCharacter ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
std : : string sId = pt . get < string > ( " sId " ) ;
std : : string secret = pt . get < string > ( " secret " ) ;
std : : string name = pt . get < string > ( " name " ) ;
std : : string infoJson = pt . get < string > ( " infoJson " ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
std : : string finalJson = Core : : Util : : base64_decode ( infoJson ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
// reloadConfig();
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
int32_t result = g_sapphireAPI . checkSession ( sId ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
if ( result ! = - 1 )
{
2018-06-10 16:34:26 +00:00
if ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.ServerSecret " ) ! = secret )
2017-12-04 11:00:08 +01:00
{
2017-08-08 13:53:47 +02:00
std : : string json_string = " { \" result \" : \" invalid_secret \" } " ;
2017-12-04 11:00:08 +01:00
* response < < buildHttpResponse ( 403 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
else
{
2018-06-10 16:34:26 +00:00
int32_t charId = g_sapphireAPI . createCharacter ( result , name , finalJson , m_pConfig - > getValue < uint8_t > ( " CharacterCreation.DefaultGMRank " , 255 ) ) ;
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" " + std : : to_string ( charId ) + " \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
}
2017-12-04 11:00:08 +01:00
else
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" invalid \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void insertSession ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
std : : string sId = pt . get < string > ( " sId " ) ;
uint32_t accountId = pt . get < uint32_t > ( " accountId " ) ;
std : : string secret = pt . get < string > ( " secret " ) ;
2017-08-10 22:13:00 +01:00
// reloadConfig();
2018-06-10 16:34:26 +00:00
if ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.ServerSecret " ) ! = secret )
2017-12-04 11:00:08 +01:00
{
std : : string json_string = " { \" result \" : \" invalid_secret \" } " ;
* response < < buildHttpResponse ( 403 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
else
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
g_sapphireAPI . insertSession ( accountId , sId ) ;
std : : string json_string = " { \" result \" : \" success \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void checkNameTaken ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
2017-08-08 22:55:02 +02:00
2017-12-04 11:00:08 +01:00
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
2017-08-08 22:55:02 +02:00
2017-12-04 11:00:08 +01:00
std : : string name = pt . get < string > ( " name " ) ;
std : : string secret = pt . get < string > ( " secret " ) ;
2017-08-08 22:55:02 +02:00
2017-12-04 11:00:08 +01:00
// reloadConfig();
2017-08-08 13:53:47 +02:00
2018-06-10 16:34:26 +00:00
if ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.ServerSecret " ) ! = secret )
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" invalid_secret \" } " ;
* response < < buildHttpResponse ( 403 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
else
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string ;
if ( ! g_sapphireAPI . checkNameTaken ( name ) )
json_string = " { \" result \" : \" false \" } " ;
else
json_string = " { \" result \" : \" true \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void checkSession ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
std : : string sId = pt . get < string > ( " sId " ) ;
std : : string secret = pt . get < string > ( " secret " ) ;
int32_t result = g_sapphireAPI . checkSession ( sId ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
// reloadConfig();
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
if ( result ! = - 1 )
2017-08-08 13:53:47 +02:00
{
2018-06-10 16:34:26 +00:00
if ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.ServerSecret " ) ! = secret )
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" invalid_secret \" } " ;
* response < < buildHttpResponse ( 403 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
else
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" " + std : : to_string ( result ) + " \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
}
2017-12-04 11:00:08 +01:00
else
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" invalid \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void getNextCharId ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
std : : string secret = pt . get < string > ( " secret " ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
// reloadConfig();
2017-08-08 13:53:47 +02:00
2018-06-10 16:34:26 +00:00
if ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.ServerSecret " ) ! = secret )
2017-12-04 11:00:08 +01:00
{
std : : string json_string = " { \" result \" : \" invalid_secret \" } " ;
* response < < buildHttpResponse ( 403 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
else
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" " + std : : to_string ( g_sapphireAPI . getNextCharId ( ) ) + " \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void getNextContentId ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
std : : string secret = pt . get < string > ( " secret " ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
// reloadConfig();
2017-08-08 13:53:47 +02:00
2018-06-10 16:34:26 +00:00
if ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.ServerSecret " ) ! = secret )
2017-12-04 11:00:08 +01:00
{
std : : string json_string = " { \" result \" : \" invalid_secret \" } " ;
* response < < buildHttpResponse ( 403 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
else
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" " + std : : to_string ( g_sapphireAPI . getNextContentId ( ) ) + " \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void getCharacterList ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
using namespace boost : : property_tree ;
ptree pt ;
read_json ( request - > content , pt ) ;
std : : string sId = pt . get < string > ( " sId " ) ;
std : : string secret = pt . get < string > ( " secret " ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
// reloadConfig();
2017-08-10 22:13:00 +01:00
2017-12-04 11:00:08 +01:00
int32_t result = g_sapphireAPI . checkSession ( sId ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
if ( result ! = - 1 )
{
2018-06-10 16:34:26 +00:00
if ( m_pConfig - > getValue < std : : string > ( " GlobalParameters.ServerSecret " ) ! = secret )
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" invalid_secret \" } " ;
* response < < buildHttpResponse ( 403 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
else
{
2017-12-04 11:00:08 +01:00
auto charList = g_sapphireAPI . getCharList ( result ) ;
using boost : : property_tree : : ptree ;
ptree pt ;
ptree char_tree ;
for ( auto entry : charList )
{
ptree tree_entry ;
tree_entry . put ( " name " , std : : string ( entry . getName ( ) ) ) ;
tree_entry . put ( " charId " , std : : to_string ( entry . getId ( ) ) ) ;
tree_entry . put ( " contentId " , std : : to_string ( entry . getContentId ( ) ) ) ;
tree_entry . put ( " infoJson " , std : : string ( entry . getInfoJson ( ) ) ) ;
char_tree . push_back ( std : : make_pair ( " " , tree_entry ) ) ;
}
pt . add_child ( " charArray " , char_tree ) ;
pt . put ( " result " , " success " ) ;
std : : ostringstream oss ;
write_json ( oss , pt ) ;
std : : string responseStr = oss . str ( ) ;
* response < < buildHttpResponse ( 200 , responseStr , JSON ) ;
2017-08-08 13:53:47 +02:00
}
}
2017-12-04 11:00:08 +01:00
else
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
std : : string json_string = " { \" result \" : \" invalid \" } " ;
* response < < buildHttpResponse ( 200 , json_string , JSON ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
}
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
void get_init ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
auto web_root_path = boost : : filesystem : : canonical ( " web " ) ;
auto path = boost : : filesystem : : canonical ( web_root_path / " news.xml " ) ;
//Check if path is within web_root_path
if ( distance ( web_root_path . begin ( ) , web_root_path . end ( ) ) > distance ( path . begin ( ) , path . end ( ) ) | |
! std : : equal ( web_root_path . begin ( ) , web_root_path . end ( ) , path . begin ( ) ) )
throw invalid_argument ( " path must be within root path " ) ;
if ( ! ( boost : : filesystem : : exists ( path ) & & boost : : filesystem : : is_regular_file ( path ) ) )
throw invalid_argument ( " file does not exist " ) ;
auto ifs = make_shared < ifstream > ( ) ;
ifs - > open ( path . string ( ) , ifstream : : in | ios : : binary | ios : : ate ) ;
if ( * ifs )
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
auto length = ifs - > tellg ( ) ;
ifs - > seekg ( 0 , ios : : beg ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
* response < < " HTTP/1.1 200 OK \r \n " < < " Content-Length: " < < length < < " \r \n \r \n " ;
default_resource_send ( server , response , ifs ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
else
throw invalid_argument ( " could not read file " ) ;
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
}
void get_headline_all ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
auto web_root_path = boost : : filesystem : : canonical ( " web " ) ;
auto path = boost : : filesystem : : canonical ( web_root_path / " headlines.xml " ) ;
//Check if path is within web_root_path
if ( distance ( web_root_path . begin ( ) , web_root_path . end ( ) ) > distance ( path . begin ( ) , path . end ( ) ) | |
! std : : equal ( web_root_path . begin ( ) , web_root_path . end ( ) , path . begin ( ) ) )
throw invalid_argument ( " path must be within root path " ) ;
if ( ! ( boost : : filesystem : : exists ( path ) & & boost : : filesystem : : is_regular_file ( path ) ) )
throw invalid_argument ( " file does not exist " ) ;
auto ifs = make_shared < ifstream > ( ) ;
ifs - > open ( path . string ( ) , ifstream : : in | ios : : binary | ios : : ate ) ;
if ( * ifs )
{
auto length = ifs - > tellg ( ) ;
ifs - > seekg ( 0 , ios : : beg ) ;
* response < < " HTTP/1.1 200 OK \r \n " < < " Content-Length: " < < length < < " \r \n \r \n " ;
default_resource_send ( server , response , ifs ) ;
}
else
throw invalid_argument ( " could not read file " ) ;
}
catch ( exception & e )
{
* response < < buildHttpResponse ( 500 ) ;
g_log . error ( e . what ( ) ) ;
}
}
void defaultGet ( shared_ptr < HttpServer : : Response > response , shared_ptr < HttpServer : : Request > request )
{
print_request_info ( request ) ;
try
{
auto web_root_path = boost : : filesystem : : canonical ( " web " ) ;
auto path = boost : : filesystem : : canonical ( web_root_path / request - > path ) ;
//Check if path is within web_root_path
if ( distance ( web_root_path . begin ( ) , web_root_path . end ( ) ) > distance ( path . begin ( ) , path . end ( ) ) | |
! std : : equal ( web_root_path . begin ( ) , web_root_path . end ( ) , path . begin ( ) ) )
throw invalid_argument ( " path must be within root path " ) ;
if ( boost : : filesystem : : is_directory ( path ) )
path / = " index.html " ;
if ( ! ( boost : : filesystem : : exists ( path ) & & boost : : filesystem : : is_regular_file ( path ) ) )
throw invalid_argument ( " file does not exist " ) ;
auto ifs = make_shared < ifstream > ( ) ;
ifs - > open ( path . string ( ) , ifstream : : in | ios : : binary | ios : : ate ) ;
if ( * ifs )
2017-08-08 13:53:47 +02:00
{
2017-12-04 11:00:08 +01:00
auto length = ifs - > tellg ( ) ;
ifs - > seekg ( 0 , ios : : beg ) ;
* response < < " HTTP/1.1 200 OK \r \n " < < " Content-Length: " < < length < < " \r \n \r \n " ;
default_resource_send ( server , response , ifs ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-04 11:00:08 +01:00
else
throw invalid_argument ( " could not read file " ) ;
}
catch ( const exception & )
{
string content = " Path not found: " + request - > path ;
* response < < buildHttpResponse ( 400 , content ) ;
}
}
int main ( int argc , char * argv [ ] )
{
2018-03-09 00:06:44 +01:00
auto pLog = boost : : shared_ptr < Core : : Logger > ( new Core : : Logger ( ) ) ;
g_fw . set < Core : : Logger > ( pLog ) ;
2018-02-09 20:11:30 +11:00
g_log . setLogPath ( " log/SapphireAPI " ) ;
2017-12-04 11:00:08 +01:00
g_log . init ( ) ;
g_log . info ( " =========================================================== " ) ;
g_log . info ( " Sapphire API Server " ) ;
g_log . info ( " Version: 0.0.1 " ) ;
g_log . info ( " Compiled: " __DATE__ " " __TIME__ ) ;
g_log . info ( " =========================================================== " ) ;
if ( ! loadSettings ( argc , argv ) )
throw std : : exception ( ) ;
2017-08-08 13:53:47 +02:00
2017-12-04 11:00:08 +01:00
server . resource [ " ^/ZoneName/([0-9]+)$ " ] [ " GET " ] = & getZoneName ;
server . resource [ " ^/sapphire-api/lobby/createAccount " ] [ " POST " ] = & createAccount ;
server . resource [ " ^/sapphire-api/lobby/login " ] [ " POST " ] = & login ;
server . resource [ " ^/sapphire-api/lobby/deleteCharacter " ] [ " POST " ] = & deleteCharacter ;
server . resource [ " ^/sapphire-api/lobby/createCharacter " ] [ " POST " ] = & createCharacter ;
server . resource [ " ^/sapphire-api/lobby/insertSession " ] [ " POST " ] = & insertSession ;
server . resource [ " ^/sapphire-api/lobby/checkNameTaken " ] [ " POST " ] = & checkNameTaken ;
server . resource [ " ^/sapphire-api/lobby/checkSession " ] [ " POST " ] = & checkSession ;
server . resource [ " ^/sapphire-api/lobby/getNextCharId " ] [ " POST " ] = & getNextCharId ;
server . resource [ " ^/sapphire-api/lobby/getNextContentId " ] [ " POST " ] = & getNextContentId ;
server . resource [ " ^/sapphire-api/lobby/getCharacterList " ] [ " POST " ] = & getCharacterList ;
server . resource [ " ^(/frontier-api/ffxivsupport/view/get_init)(.*) " ] [ " GET " ] = & get_init ;
server . resource [ " ^(/frontier-api/ffxivsupport/information/get_headline_all)(.*) " ] [ " GET " ] = & get_headline_all ;
server . default_resource [ " GET " ] = & defaultGet ;
thread server_thread ( [ & ] ( )
{
2017-08-08 13:53:47 +02:00
//Start server
server . start ( ) ;
} ) ;
2018-06-23 21:05:31 +02:00
g_log . info ( " API server running on " + m_pConfig - > getValue < std : : string > ( " RestNetwork.ListenIp " , " 0.0.0.0 " ) + " : " + m_pConfig - > getValue < std : : string > ( " RestNetwork.ListenPort " , " 80 " ) ) ;
2017-08-08 13:53:47 +02:00
//Wait for server to start so that the client can connect
this_thread : : sleep_for ( chrono : : seconds ( 1 ) ) ;
server_thread . join ( ) ;
return 0 ;
}
void default_resource_send ( const HttpServer & server , const shared_ptr < HttpServer : : Response > & response ,
const shared_ptr < ifstream > & ifs )
{
//read and send 128 KB at a time
static vector < char > buffer ( 131072 ) ; // Safe when server is running on one thread
streamsize read_length ;
if ( ( read_length = ifs - > read ( & buffer [ 0 ] , buffer . size ( ) ) . gcount ( ) ) > 0 )
{
response - > write ( & buffer [ 0 ] , read_length ) ;
if ( read_length = = static_cast < streamsize > ( buffer . size ( ) ) )
{
server . send ( response , [ & server , response , ifs ] ( const boost : : system : : error_code & ec ) {
if ( ! ec )
default_resource_send ( server , response , ifs ) ;
else
cerr < < " Connection interrupted " < < endl ;
} ) ;
}
}
}