#pragma once #include #include #include #include "Definitions.h" namespace ts { namespace server { class VirtualServer; } namespace stats { struct StatisticEntry { std::atomic use_count{0}; std::chrono::time_point timestamp; uint16_t size = 0; }; struct DataSummery { uint32_t send_minute; uint32_t send_second; uint32_t recv_minute; uint32_t recv_second; uint32_t file_recv; uint32_t file_send; }; struct FullReport { uint64_t connection_packets_sent[4]{0, 0, 0, 0}; uint64_t connection_bytes_sent[4]{0, 0, 0, 0}; uint64_t connection_packets_received[4]{0, 0, 0, 0}; uint64_t connection_bytes_received[4]{0, 0, 0, 0}; uint64_t file_bytes_sent = 0; uint64_t file_bytes_received = 0; }; class ConnectionStatistics { public: struct category { enum value { COMMAND, ACK, VOICE, UNKNOWN }; constexpr static std::array lookup_table{ VOICE, /* Voice */ VOICE, /* VoiceWhisper */ COMMAND, /* Command */ COMMAND, /* CommandLow */ ACK, /* Ping */ ACK, /* Pong */ ACK, /* Ack */ ACK, /* AckLow */ COMMAND, /* */ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN }; /* much faster than a switch */ inline static category::value from_type(uint8_t type){ return lookup_table[type & 0xFU]; } inline static category::value from_type(const protocol::PacketTypeInfo& type){ return from_type(type.type()); } }; explicit ConnectionStatistics(const std::shared_ptr& /* root */, bool /* spawn properties */); ~ConnectionStatistics(); std::shared_ptr statistics(); inline void logIncomingPacket(const protocol::ClientPacket& packet) { this->logIncomingPacket(category::from_type(packet.type()), packet.length()); } void logIncomingPacket(const category::value& /* category */, size_t /* length */); inline void logOutgoingPacket(const protocol::ServerPacket& packet) { this->logOutgoingPacket(category::from_type(packet.type()), packet.length()); } void logOutgoingPacket(const category::value& /* category */, size_t /* length */); void logFileTransferIn(uint64_t); void logFileTransferOut(uint64_t); void tick(); DataSummery dataReport(); FullReport full_report(); std::pair mark_file_bytes(); inline bool measure_bandwidths() { return this->_measure_bandwidths; } void measure_bandwidths(bool flag) { this->_measure_bandwidths = flag; } inline bool has_properties() { return !!this->properties; } private: bool _measure_bandwidths = true; std::shared_ptr handle; std::shared_ptr properties; std::atomic connection_packets_sent[4]{0, 0, 0, 0}; std::atomic connection_bytes_sent[4]{0, 0, 0, 0}; std::atomic connection_packets_received[4]{0, 0, 0, 0}; std::atomic connection_bytes_received[4]{0, 0, 0, 0}; std::atomic file_bytes_sent = 0; std::atomic file_bytes_received = 0; std::atomic mark_file_bytes_sent = 0; std::atomic mark_file_bytes_received = 0; spin_lock history_lock_outgoing; spin_lock history_lock_incoming; std::deque history_file_incoming{}; std::deque history_file_outgoing{}; std::deque history_incoming{}; std::deque history_outgoing{}; void _log_incoming_packet(StatisticEntry */* statistics */, int8_t /* type index */); void _log_outgoing_packet(StatisticEntry* /* statistics */, int8_t /* type index */); void _log_incoming_file_packet(StatisticEntry */* statistics */); void _log_outgoing_file_packet(StatisticEntry* /* statistics */); }; } }