mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-05-10 19:00:57 +08:00
Bug fixes: - Fix data race on client->width/height (now _Atomic int) - Persist join/leave system messages via message_save() - Make room_add_message static to enforce lock contract - Fix execute_command mutating command_input directly - Increase help_copy buffer from 4096 to 8192 for CJK safety New features: - Add :msg/:w whisper command for private messaging - Add command history with UP/DOWN arrows in command mode - Add Ctrl+D/U/F/B page scrolling in normal mode - Add :q/:quit/:exit Vim-style disconnect Unix community: - Add tnt.1 manpage (roff format) with full documentation - Add manpage install/uninstall to Makefile
151 lines
3.7 KiB
C
151 lines
3.7 KiB
C
#include "chat_room.h"
|
|
|
|
/* Global chat room instance */
|
|
chat_room_t *g_room = NULL;
|
|
|
|
static int room_capacity_from_env(void) {
|
|
const char *env = getenv("TNT_MAX_CONNECTIONS");
|
|
|
|
if (!env || env[0] == '\0') {
|
|
return MAX_CLIENTS;
|
|
}
|
|
|
|
char *end;
|
|
long capacity = strtol(env, &end, 10);
|
|
if (*end != '\0' || capacity < 1 || capacity > 1024) {
|
|
return MAX_CLIENTS;
|
|
}
|
|
|
|
return (int)capacity;
|
|
}
|
|
|
|
/* Initialize chat room */
|
|
chat_room_t* room_create(void) {
|
|
chat_room_t *room = calloc(1, sizeof(chat_room_t));
|
|
if (!room) return NULL;
|
|
|
|
pthread_rwlock_init(&room->lock, NULL);
|
|
|
|
room->client_capacity = room_capacity_from_env();
|
|
room->clients = calloc(room->client_capacity, sizeof(struct client *));
|
|
if (!room->clients) {
|
|
free(room);
|
|
return NULL;
|
|
}
|
|
|
|
/* Load messages from file */
|
|
room->message_count = message_load(&room->messages, MAX_MESSAGES);
|
|
|
|
return room;
|
|
}
|
|
|
|
/* Destroy chat room */
|
|
void room_destroy(chat_room_t *room) {
|
|
if (!room) return;
|
|
|
|
pthread_rwlock_wrlock(&room->lock);
|
|
|
|
free(room->clients);
|
|
free(room->messages);
|
|
|
|
pthread_rwlock_unlock(&room->lock);
|
|
pthread_rwlock_destroy(&room->lock);
|
|
|
|
free(room);
|
|
}
|
|
|
|
/* Add client to room */
|
|
int room_add_client(chat_room_t *room, struct client *client) {
|
|
pthread_rwlock_wrlock(&room->lock);
|
|
|
|
if (room->client_count >= room->client_capacity) {
|
|
pthread_rwlock_unlock(&room->lock);
|
|
return -1;
|
|
}
|
|
|
|
room->clients[room->client_count++] = client;
|
|
|
|
pthread_rwlock_unlock(&room->lock);
|
|
return 0;
|
|
}
|
|
|
|
/* Remove client from room */
|
|
void room_remove_client(chat_room_t *room, struct client *client) {
|
|
pthread_rwlock_wrlock(&room->lock);
|
|
|
|
for (int i = 0; i < room->client_count; i++) {
|
|
if (room->clients[i] == client) {
|
|
/* Shift remaining clients */
|
|
for (int j = i; j < room->client_count - 1; j++) {
|
|
room->clients[j] = room->clients[j + 1];
|
|
}
|
|
room->client_count--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pthread_rwlock_unlock(&room->lock);
|
|
}
|
|
|
|
/* Add message to room history (caller must hold write lock) */
|
|
static void room_add_message(chat_room_t *room, const message_t *msg) {
|
|
if (room->message_count >= MAX_MESSAGES) {
|
|
memmove(&room->messages[0], &room->messages[1],
|
|
(MAX_MESSAGES - 1) * sizeof(message_t));
|
|
room->message_count = MAX_MESSAGES - 1;
|
|
}
|
|
|
|
room->messages[room->message_count++] = *msg;
|
|
}
|
|
|
|
/* Broadcast message to all clients */
|
|
void room_broadcast(chat_room_t *room, const message_t *msg) {
|
|
pthread_rwlock_wrlock(&room->lock);
|
|
|
|
room_add_message(room, msg);
|
|
room->update_seq++;
|
|
|
|
pthread_rwlock_unlock(&room->lock);
|
|
}
|
|
|
|
/* Get message by index (thread-safe value copy) */
|
|
bool room_get_message(chat_room_t *room, int index, message_t *out) {
|
|
if (!room || !out) return false;
|
|
|
|
pthread_rwlock_rdlock(&room->lock);
|
|
|
|
bool found = false;
|
|
if (index >= 0 && index < room->message_count) {
|
|
*out = room->messages[index];
|
|
found = true;
|
|
}
|
|
|
|
pthread_rwlock_unlock(&room->lock);
|
|
return found;
|
|
}
|
|
|
|
/* Get total message count */
|
|
int room_get_message_count(chat_room_t *room) {
|
|
pthread_rwlock_rdlock(&room->lock);
|
|
int count = room->message_count;
|
|
pthread_rwlock_unlock(&room->lock);
|
|
return count;
|
|
}
|
|
|
|
/* Get online client count */
|
|
int room_get_client_count(chat_room_t *room) {
|
|
pthread_rwlock_rdlock(&room->lock);
|
|
int count = room->client_count;
|
|
pthread_rwlock_unlock(&room->lock);
|
|
return count;
|
|
}
|
|
|
|
uint64_t room_get_update_seq(chat_room_t *room) {
|
|
uint64_t seq;
|
|
|
|
pthread_rwlock_rdlock(&room->lock);
|
|
seq = room->update_seq;
|
|
pthread_rwlock_unlock(&room->lock);
|
|
|
|
return seq;
|
|
}
|