Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 27 additions & 16 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ endif()

# If no variable is passed from the environment/command line, use a fallback
if(NOT DEFINED BUILD_VERSION)
set(BUILD_VERSION "0.1.0")
set(BUILD_VERSION "0.0.0")
endif()

# Separate the SemVer string into major, minor, patch parts
Expand Down Expand Up @@ -48,20 +48,6 @@ find_package(UserModules QUIET)
# )
# target_include_directories(xtrpg_core PUBLIC include)

# Link imported targets across platforms
# target_link_libraries(xtrpg_core PUBLIC
# asio::asio
# OpenSSL::SSL
# OpenSSL::Crypto
# )

# Platform-specific OS network primitives for raw sockets
# if(WIN32)
# target_link_libraries(xtrpg_core PUBLIC ws2_32 wsock32 crypt32)
# elseif(UNIX AND NOT APPLE)
# target_link_libraries(xtrpg_core PUBLIC pthread dl)
# endif()

# Conditional Storage Compilation
# if(ENABLE_STORAGE_SQLITE)
# find_package(SQLite3 REQUIRED)
Expand Down Expand Up @@ -93,6 +79,31 @@ add_library(xtrpg_config STATIC
)
target_include_directories(xtrpg_config PUBLIC include)

# Network LIB
add_library(xtrpg_network STATIC
src/network/SocketConnectionListener.cpp
src/network/TcpConnection.cpp
)
target_include_directories(xtrpg_network PUBLIC include)
target_link_libraries(xtrpg_network PUBLIC
asio::asio
OpenSSL::SSL
OpenSSL::Crypto
)
if(WIN32)
# Windows-specific OS network primitives for raw sockets
# Define minimum Windows version (0x0601 = Windows 7, 0x0A00 = Windows 10)
# 0x0A00 unlocks modern Windows socket features for Asio
target_compile_definitions(xtrpg_network PUBLIC
_WIN32_WINNT=0x0A00
WINVER=0x0A00
)
target_link_libraries(xtrpg_network PUBLIC ws2_32 wsock32 crypt32)
elseif(UNIX AND NOT APPLE)
# Platform-specific OS network primitives for raw sockets
target_link_libraries(xtrpg_network PUBLIC pthread dl)
endif()

# XMPP LIB
add_library(xtrpg_xmpp STATIC
src/xmpp/Jid.cpp
Expand All @@ -101,7 +112,7 @@ target_include_directories(xtrpg_xmpp PUBLIC include)

# Executable Target
add_executable(xtrpg_cpp_server apps/main.cpp)
target_link_libraries(xtrpg_cpp_server PRIVATE xtrpg_config xtrpg_xmpp)
target_link_libraries(xtrpg_cpp_server PRIVATE xtrpg_config xtrpg_network xtrpg_xmpp)
target_include_directories(xtrpg_cpp_server PRIVATE ${CMAKE_BINARY_DIR}/generated)

# If modules produce targets registered via xmpp_register_user_module
Expand Down
69 changes: 45 additions & 24 deletions apps/main.cpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,56 @@
#include <fstream>
#include <iostream>

#include "version.hpp"
#include "xtrpg/config/ConfigManager.hpp"

#ifdef _WIN32
#define _WINSOCKAPI_
#include <windows.h>
#endif

int main(int argc, char *argv[]) {
#ifdef _WIN32
// Set console codepages to UTF-8 (65001)
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
#endif

try {

// Output preamble information about the application and its configuration
// system.
std::cout << "XTRPG: A XMPP Server" << std::endl
<< "Version: " << xtrpg::VERSION << std::endl
<< "Copyright (C) 2026 XTRPG Contributors" << std::endl
<< "License: MIT" << std::endl
<< " "
"<https://github.com/xtrpg/xtrpg-cpp-server/blob/main/LICENSE>"
<< std::endl
<< std::endl
<< "This is free and open-source software." << std::endl
<< "You are free to use, modify, and redistribute it under the "
"terms of the MIT License."
<< std::endl
<< "There is NO WARRANTY for this software." << std::endl
<< std::endl;

// Discover and register all modules' configuration schemas, then load the
// configuration file and parse command-line arguments.
xtrpg::config::ConfigManager configManager;
configManager.registerAllDiscoveredModules();
std::ifstream configFile("./config.toml");
if (configFile) {
configManager.loadTomlFile(configFile);
}
configManager.parseCLI(argc, argv);

// Output preamble information about the application and its configuration
// system.
std::cout << "XTRPG: A XMPP Server" << std::endl
<< "Version: 0.1.0" << std::endl
<< "Copyright (C) 2026 XTRPG Contributors" << std::endl
<< "License: MIT" << std::endl
<< " "
"<https://github.com/xtrpg/xtrpg-cpp-server/blob/main/LICENSE>"
<< std::endl
<< std::endl
<< "This is free and open-source software. You are free to use, "
"modify, and redistribute it under the terms of the MIT License."
<< std::endl
<< "There is NO WARRANTY for this software." << std::endl
<< std::endl;

// Discover and register all modules' configuration schemas, then load the
// configuration file and parse command-line arguments.
xtrpg::config::ConfigManager configManager;
configManager.registerAllDiscoveredModules();
std::ifstream configFile("./config.toml");
if (configFile) {
configManager.loadTomlFile(configFile);
} catch (const std::exception &e) {
std::cerr << "EXCEPTION OCCURRED" << std::endl
<< "Application closing die to \"" << e.what() << "\"."
<< std ::endl;
return 1;
}
configManager.parseCLI(argc, argv);

return 0;
}
12 changes: 6 additions & 6 deletions generated/version.hpp.in
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#pragma once

#include <string>
#include <string_view>

namespace xtprg {
namespace xtrpg {
constexpr std::string_view VERSION = "@PROJECT_VERSION@";
constexpr int VERSION_MAJOR = @PROJECT_VERSION_MAJOR @;
constexpr int VERSION_MINOR = @PROJECT_VERSION_MINOR @;
constexpr int VERSION_PATCH = @PROJECT_VERSION_PATCH @;
} // namespace xtprg
constexpr int VERSION_MAJOR = @CMAKE_PROJECT_VERSION_MAJOR@;
constexpr int VERSION_MINOR = @CMAKE_PROJECT_VERSION_MINOR@;
constexpr int VERSION_PATCH = @CMAKE_PROJECT_VERSION_PATCH@;
} // namespace xtrpg
57 changes: 57 additions & 0 deletions include/xtrpg/interface/Observable.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#pragma once

#include <iostream>
#include <memory>
#include <string_view>
#include <vector>

#include "xtrpg/interface/Observer.hpp"

namespace xtrpg::interface {
template <typename TContext> class Observable {
public:
virtual ~Observable() = default;

void addObserver(const std::shared_ptr<Observer<TContext>> &ptr) {
if (ptr) {
this->_observers.push_back(ptr);
}
}

void eraseObserver(const Observer<TContext> *pTarget) {
if (!pTarget) {
return;
}

std::erase_if(this->_observers,
[pTarget](const std::weak_ptr<Observer<TContext>> &wp) {
auto sp = wp.lock();
return !sp || sp.get() == pTarget;
});
}

void clearObservers() { this->_observers.clear(); }

protected:
void dispatchObservation(TContext &ctx) {
std::erase_if(this->_observers,
[&ctx](const std::weak_ptr<Observer<TContext>> &wp) {
// Attempt to gain temporary ownership of the current
// observer.
if (auto observer = wp.lock()) {
// Dispatch the observation.
observer->onObservation(ctx);

// Pointer is still valid, keep it in the vector.
return false;
}

// Pointer has expired, remove it from the observers vector.
return true;
});
}

private:
std::vector<std::weak_ptr<Observer<TContext>>> _observers;
};
} // namespace xtrpg
13 changes: 13 additions & 0 deletions include/xtrpg/interface/Observer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <string_view>

namespace xtrpg::interface {
template <typename TContext> class Observer {
public:
virtual ~Observer() = default;

// Generic handler callback
virtual void onObservation(TContext &ctx) = 0;
};
} // namespace xtrpg::interface
41 changes: 41 additions & 0 deletions include/xtrpg/network/SocketConnectionListener.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <asio.hpp>
#include <cstdint>
#include <iostream>
#include <memory>
#include <optional>
#include <string>

#include "xtrpg/interface/Observable.hpp"
#include "xtrpg/network/TcpConnection.hpp"

namespace xtrpg::network {
class SocketConnectionListener
: public interface::Observable<std::shared_ptr<TcpConnection>> {
public:
/**
* Instantiates a new listener instance.
*/
SocketConnectionListener(asio::io_context &ioContext, uint16_t port)
: _ioContext(ioContext), _port(port), _isStopped(true) {
this->initializeAcceptors();
}

~SocketConnectionListener() { this->stop(); }

void start();
void stop();

private:
void initializeAcceptors();
void acceptIPv4Connections();
void acceptIPv6Connections();

asio::io_context &_ioContext;
uint16_t _port;
std::optional<asio::ip::tcp::acceptor> _ipv4Acceptor;
std::optional<asio::ip::tcp::acceptor> _ipv6Acceptor;
bool _isStopped{true};
};
} // namespace xtrpg::network
Loading
Loading