major refactor of Client and Server

this refactor includes changes to TClient:

- all member fields are now public, but protected with Sync (an alias
  for boost::synchronized_value
- removed all (now) obsolete getters and setters

changes to TServer and TNetwork:

- thread-safe ID generation, previously it was possible for there to be
  ID duplicates. this is now solved by moving id generation and
  assignment into the same mutex locked context.
- deprecated ForEachClientWeak and replaced some usages of it with
  ForEachClient, getting rid of the weak_ptr shit in most places
- implemented a bunch of new functions for getting rid of more weak_ptr
  everywhere
This commit is contained in:
Lion Kortlepel
2024-01-08 14:55:53 +01:00
parent c6aa7776fc
commit b9f73f77c3
13 changed files with 375 additions and 388 deletions

View File

@@ -10,6 +10,8 @@
#include "BoostAliases.h"
#include "Common.h"
#include "Compat.h"
#include "RWMutex.h"
#include "Sync.h"
#include "VehicleData.h"
class TServer;
@@ -41,76 +43,47 @@ public:
void AddNewCar(int Ident, const std::string& Data);
void SetCarData(int Ident, const std::string& Data);
void SetCarPosition(int Ident, const std::string& Data);
TVehicleDataLockPair GetAllCars();
void SetName(const std::string& Name) { mName = Name; }
void SetRoles(const std::string& Role) { mRole = Role; }
void SetIdentifier(const std::string& key, const std::string& value) { mIdentifiers[key] = value; }
void SetName(const std::string& NewName) { Name = NewName; }
void SetRoles(const std::string& NewRole) { Role = NewRole; }
void SetIdentifier(const std::string& key, const std::string& value);
std::string GetCarData(int Ident);
std::string GetCarPositionRaw(int Ident);
void SetUDPAddr(const ip::udp::endpoint& Addr) { mUDPAddress = Addr; }
void SetDownSock(ip::tcp::socket&& CSock) { mDownSocket = std::move(CSock); }
void SetTCPSock(ip::tcp::socket&& CSock) { mSocket = std::move(CSock); }
void Disconnect(std::string_view Reason);
bool IsDisconnected() const { return !mSocket.is_open(); }
bool IsDisconnected() const { return !TCPSocket->is_open(); }
// locks
void DeleteCar(int Ident);
[[nodiscard]] const std::unordered_map<std::string, std::string>& GetIdentifiers() const { return mIdentifiers; }
[[nodiscard]] const ip::udp::endpoint& GetUDPAddr() const { return mUDPAddress; }
[[nodiscard]] ip::udp::endpoint& GetUDPAddr() { return mUDPAddress; }
[[nodiscard]] ip::tcp::socket& GetDownSock() { return mDownSocket; }
[[nodiscard]] const ip::tcp::socket& GetDownSock() const { return mDownSocket; }
[[nodiscard]] ip::tcp::socket& GetTCPSock() { return mSocket; }
[[nodiscard]] const ip::tcp::socket& GetTCPSock() const { return mSocket; }
[[nodiscard]] std::string GetRoles() const { return mRole; }
[[nodiscard]] std::string GetName() const { return mName; }
void SetUnicycleID(int ID) { mUnicycleID = ID; }
void SetID(int ID) { mID = ID; }
[[nodiscard]] int GetOpenCarID() const;
[[nodiscard]] int GetCarCount() const;
void ClearCars();
[[nodiscard]] int GetID() const { return mID; }
[[nodiscard]] int GetUnicycleID() const { return mUnicycleID; }
[[nodiscard]] bool IsConnected() const { return mIsConnected; }
[[nodiscard]] bool IsSynced() const { return mIsSynced; }
[[nodiscard]] bool IsSyncing() const { return mIsSyncing; }
[[nodiscard]] bool IsGuest() const { return mIsGuest; }
void SetIsGuest(bool NewIsGuest) { mIsGuest = NewIsGuest; }
void SetIsSynced(bool NewIsSynced) { mIsSynced = NewIsSynced; }
void SetIsSyncing(bool NewIsSyncing) { mIsSyncing = NewIsSyncing; }
void EnqueuePacket(const std::vector<uint8_t>& Packet);
[[nodiscard]] std::queue<std::vector<uint8_t>>& MissedPacketQueue() { return mPacketsSync; }
[[nodiscard]] const std::queue<std::vector<uint8_t>>& MissedPacketQueue() const { return mPacketsSync; }
[[nodiscard]] size_t MissedPacketQueueSize() const { return mPacketsSync.size(); }
[[nodiscard]] std::mutex& MissedPacketQueueMutex() const { return mMissedPacketsMutex; }
void SetIsConnected(bool NewIsConnected) { mIsConnected = NewIsConnected; }
void SetIsConnected(bool NewIsConnected) { IsConnected = NewIsConnected; }
[[nodiscard]] TServer& Server() const;
void UpdatePingTime();
int SecondsSinceLastPing();
Sync<bool> IsConnected = false;
Sync<bool> IsSynced = false;
Sync<bool> IsSyncing = false;
Sync<std::unordered_map<std::string, std::string>> Identifiers;
Sync<ip::tcp::socket> TCPSocket;
Sync<ip::tcp::socket> DownSocket;
Sync<ip::udp::endpoint> UDPAddress {};
Sync<int> UnicycleID = -1;
Sync<std::string> Role;
Sync<std::string> DID;
Sync<int> ID = -1;
Sync<bool> IsGuest = false;
Sync<std::string> Name = std::string("Unknown Client");
Sync<TSetOfVehicleData> VehicleData;
Sync<SparseArray<std::string>> VehiclePosition;
Sync<std::queue<std::vector<uint8_t>>> MissedPacketsQueue;
Sync<std::chrono::time_point<std::chrono::high_resolution_clock>> LastPingTime;
private:
void InsertVehicle(int ID, const std::string& Data);
TServer& mServer;
bool mIsConnected = false;
bool mIsSynced = false;
bool mIsSyncing = false;
mutable std::mutex mMissedPacketsMutex;
std::queue<std::vector<uint8_t>> mPacketsSync;
std::unordered_map<std::string, std::string> mIdentifiers;
bool mIsGuest = false;
mutable std::mutex mVehicleDataMutex;
mutable std::mutex mVehiclePositionMutex;
TSetOfVehicleData mVehicleData;
SparseArray<std::string> mVehiclePosition;
std::string mName = "Unknown Client";
ip::tcp::socket mSocket;
ip::tcp::socket mDownSocket;
ip::udp::endpoint mUDPAddress {};
int mUnicycleID = -1;
std::string mRole;
std::string mDID;
int mID = -1;
std::chrono::time_point<std::chrono::high_resolution_clock> mLastPingTime;
};
std::optional<std::weak_ptr<TClient>> GetClient(class TServer& Server, int ID);
std::optional<std::shared_ptr<TClient>> GetClient(class TServer& Server, int ID);

9
include/Sync.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include <boost/thread/synchronized_value.hpp>
/// This header provides convenience aliases for synchronization primitives.
template<typename T>
using Sync = boost::synchronized_value<T>;

View File

@@ -220,6 +220,8 @@ private:
// Debug functions, slow
std::queue<std::pair<TLuaChunk, std::shared_ptr<TLuaResult>>> Debug_GetStateExecuteQueue();
std::vector<TLuaEngine::QueuedFunction> Debug_GetStateFunctionQueue();
sol::table Lua_JsonDecode(const std::string& str);
private:
sol::table Lua_TriggerGlobalEvent(const std::string& EventName, sol::variadic_args EventArgs);
@@ -230,7 +232,6 @@ private:
sol::table Lua_GetPlayerVehicles(int ID);
std::pair<sol::table, std::string> Lua_GetPositionRaw(int PID, int VID);
sol::table Lua_HttpCreateConnection(const std::string& host, uint16_t port);
sol::table Lua_JsonDecode(const std::string& str);
int Lua_GetPlayerIDByName(const std::string& Name);
sol::table Lua_FS_ListFiles(const std::string& Path);
sol::table Lua_FS_ListDirectories(const std::string& Path);

View File

@@ -43,8 +43,9 @@ private:
void OnConnect(const std::weak_ptr<TClient>& c);
void TCPClient(const std::weak_ptr<TClient>& c);
void Looper(const std::weak_ptr<TClient>& c);
int OpenID();
void OnDisconnect(const std::shared_ptr<TClient>& ClientPtr);
void OnDisconnect(const std::weak_ptr<TClient>& ClientPtr);
void OnDisconnect(TClient& Client);
void Parse(TClient& c, const std::vector<uint8_t>& Packet);
void SendFile(TClient& c, const std::string& Name);
static bool TCPSendRaw(TClient& C, ip::tcp::socket& socket, const uint8_t* Data, size_t Size);

View File

@@ -22,14 +22,19 @@ public:
void InsertClient(const std::shared_ptr<TClient>& Ptr);
void RemoveClient(const std::weak_ptr<TClient>&);
void RemoveClient(TClient&);
// in Fn, return true to continue, return false to break
void ForEachClient(const std::function<bool(std::weak_ptr<TClient>)>& Fn);
[[deprecated("Use ForEachClient instead")]] void ForEachClientWeak(const std::function<bool(std::weak_ptr<TClient>)>& Fn);
void ForEachClient(const std::function<bool(const std::shared_ptr<TClient>&)> Fn);
size_t ClientCount() const;
void GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uint8_t>&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network);
static void HandleEvent(TClient& c, const std::string& Data);
RWMutex& GetClientMutex() const { return mClientsMutex; }
// thread-safe ID lookup & claim
void ClaimFreeIDFor(TClient& Client);
const TScopedTimer UptimeTimer;
// asio io context