mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-07 07:43:13 +02:00
Move channel history sending from one layer to the other.
This so for example history_backend_mem() does not do any sending. Less efficient but needed for later when things get more complex.
This commit is contained in:
+4
-1
@@ -944,8 +944,11 @@ extern void free_message_tags(MessageTag *m);
|
||||
extern time_t server_time_to_unix_time(const char *tbuf);
|
||||
extern int history_set_limit(char *object, int max_lines, long max_t);
|
||||
extern int history_add(char *object, MessageTag *mtags, char *line);
|
||||
extern int history_request(Client *acptr, char *object, HistoryFilter *filter);
|
||||
extern HistoryResult *history_request(char *object, HistoryFilter *filter);
|
||||
extern int history_destroy(char *object);
|
||||
extern int can_receive_history(Client *client);
|
||||
extern void history_send_result(Client *client, HistoryResult *r);
|
||||
extern void free_history_result(HistoryResult *r);
|
||||
extern void special_delayed_unloading(void);
|
||||
extern int write_int64(FILE *fd, uint64_t t);
|
||||
extern int write_int32(FILE *fd, uint32_t t);
|
||||
|
||||
+18
-2
@@ -493,6 +493,22 @@ struct HistoryFilter {
|
||||
int last_seconds;
|
||||
};
|
||||
|
||||
/** History log lines, used by HistoryResult among others */
|
||||
typedef struct HistoryLogLine HistoryLogLine;
|
||||
struct HistoryLogLine {
|
||||
HistoryLogLine *prev, *next;
|
||||
time_t t;
|
||||
MessageTag *mtags;
|
||||
char line[1];
|
||||
};
|
||||
|
||||
typedef struct HistoryResult HistoryResult;
|
||||
struct HistoryResult {
|
||||
char *object; /**< Name of the history object, eg '#test' */
|
||||
HistoryLogLine *log; /**< The resulting log lines */
|
||||
HistoryLogLine *log_tail; /**< Last entry in the log lines */
|
||||
};
|
||||
|
||||
/** History Backend */
|
||||
typedef struct HistoryBackend HistoryBackend;
|
||||
struct HistoryBackend {
|
||||
@@ -500,7 +516,7 @@ struct HistoryBackend {
|
||||
char *name; /**< The name of the history backend (eg: "mem") */
|
||||
int (*history_set_limit)(char *object, int max_lines, long max_time); /**< Impose a limit on a history object */
|
||||
int (*history_add)(char *object, MessageTag *mtags, char *line); /**< Add to history */
|
||||
int (*history_request)(Client *acptr, char *object, HistoryFilter *filter); /**< Request history */
|
||||
HistoryResult *(*history_request)(char *object, HistoryFilter *filter); /**< Request history */
|
||||
int (*history_destroy)(char *object); /**< Destroy history of this object completely */
|
||||
Module *owner; /**< Module introducing this */
|
||||
char unloaded; /**< Internal flag to indicate module is being unloaded */
|
||||
@@ -513,7 +529,7 @@ typedef struct {
|
||||
char *name;
|
||||
int (*history_set_limit)(char *object, int max_lines, long max_time);
|
||||
int (*history_add)(char *object, MessageTag *mtags, char *line);
|
||||
int (*history_request)(Client *acptr, char *object, HistoryFilter *filter);
|
||||
HistoryResult *(*history_request)(char *object, HistoryFilter *filter);
|
||||
int (*history_destroy)(char *object);
|
||||
} HistoryBackendInfo;
|
||||
|
||||
|
||||
@@ -166,14 +166,21 @@ int history_add(char *object, MessageTag *mtags, char *line)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int history_request(Client *client, char *object, HistoryFilter *filter)
|
||||
HistoryResult *history_request(char *object, HistoryFilter *filter)
|
||||
{
|
||||
HistoryBackend *hb;
|
||||
HistoryBackend *hb = historybackends;
|
||||
HistoryResult *r;
|
||||
HistoryLogLine *l;
|
||||
|
||||
for (hb = historybackends; hb; hb=hb->next)
|
||||
hb->history_request(client, object, filter);
|
||||
if (!hb)
|
||||
return 0; /* no history backend loaded */
|
||||
|
||||
return 1;
|
||||
/* Right now we return whenever the first backend has a result. */
|
||||
for (hb = historybackends; hb; hb = hb->next)
|
||||
if ((r = hb->history_request(object, filter)))
|
||||
return r;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int history_destroy(char *object)
|
||||
@@ -195,3 +202,74 @@ int history_set_limit(char *object, int max_lines, long max_t)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Free a HistoryResult object that was returned from request_result() earlier */
|
||||
void free_history_result(HistoryResult *r)
|
||||
{
|
||||
HistoryLogLine *l, *l_next;
|
||||
for (l = r->log; l; l = l_next)
|
||||
{
|
||||
l_next = l->next;
|
||||
free_message_tags(l->mtags);
|
||||
safe_free(l);
|
||||
}
|
||||
safe_free(r->object);
|
||||
safe_free(r);
|
||||
}
|
||||
|
||||
/** Returns 1 if the client can receive channel history, 0 if not.
|
||||
* @param client The client to check.
|
||||
* @note It is recommend to call this function BEFORE trying to
|
||||
* retrieve channel history via history_request(),
|
||||
* as to not waste useless resources.
|
||||
*/
|
||||
int can_receive_history(Client *client)
|
||||
{
|
||||
if (HasCapability(client, "server-time"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void history_send_result_line(Client *client, HistoryLogLine *l, char *batchid)
|
||||
{
|
||||
if (BadPtr(batchid))
|
||||
{
|
||||
sendto_one(client, l->mtags, "%s", l->line);
|
||||
} else {
|
||||
MessageTag *m = safe_alloc(sizeof(MessageTag));
|
||||
m->name = "batch";
|
||||
m->value = batchid;
|
||||
AddListItem(m, l->mtags);
|
||||
sendto_one(client, l->mtags, "%s", l->line);
|
||||
DelListItem(m, l->mtags);
|
||||
safe_free(m);
|
||||
}
|
||||
}
|
||||
|
||||
/** Send the result of a history_request() to the client.
|
||||
* @param client The client to send to.
|
||||
* @param r The history result retrieved via history_request().
|
||||
*/
|
||||
void history_send_result(Client *client, HistoryResult *r)
|
||||
{
|
||||
char batch[BATCHLEN+1];
|
||||
HistoryLogLine *l;
|
||||
|
||||
if (!can_receive_history(client))
|
||||
return;
|
||||
|
||||
batch[0] = '\0';
|
||||
if (HasCapability(client, "batch"))
|
||||
{
|
||||
/* Start a new batch */
|
||||
generate_batch_id(batch);
|
||||
sendto_one(client, NULL, ":%s BATCH +%s chathistory %s", me.name, batch, r->object);
|
||||
}
|
||||
|
||||
for (l = r->log; l; l = l->next)
|
||||
history_send_result_line(client, l, batch);
|
||||
|
||||
/* End of batch */
|
||||
if (*batch)
|
||||
sendto_one(client, NULL, ":%s BATCH -%s", me.name, batch);
|
||||
}
|
||||
|
||||
@@ -534,13 +534,19 @@ int history_join(Client *client, Channel *channel, MessageTag *mtags, char *parv
|
||||
if (!HistoryEnabled(channel))
|
||||
return 0;
|
||||
|
||||
if (MyUser(client))
|
||||
if (MyUser(client) && can_receive_history(client))
|
||||
{
|
||||
HistoryFilter filter;
|
||||
HistoryResult *r;
|
||||
memset(&filter, 0, sizeof(filter));
|
||||
filter.last_lines = cfg.playback_on_join.lines;
|
||||
filter.last_seconds = cfg.playback_on_join.time;
|
||||
history_request(client, channel->chname, &filter);
|
||||
r = history_request(channel->chname, &filter);
|
||||
if (r)
|
||||
{
|
||||
history_send_result(client, r);
|
||||
free_history_result(r);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -72,6 +72,7 @@ void history_usage(Client *client)
|
||||
CMD_FUNC(cmd_history)
|
||||
{
|
||||
HistoryFilter filter;
|
||||
HistoryResult *r;
|
||||
Channel *channel;
|
||||
int lines = HISTORY_LINES_DEFAULT;
|
||||
|
||||
@@ -122,5 +123,10 @@ CMD_FUNC(cmd_history)
|
||||
|
||||
memset(&filter, 0, sizeof(filter));
|
||||
filter.last_lines = lines;
|
||||
history_request(client, channel->chname, &filter);
|
||||
|
||||
if ((r = history_request(channel->chname, &filter)))
|
||||
{
|
||||
history_send_result(client, r);
|
||||
free_history_result(r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,14 +41,6 @@ ModuleHeader MOD_HEADER
|
||||
#define HISTORY_TIMER_EVERY (HISTORY_MAX_OFF_SECS/HISTORY_SPREAD)
|
||||
|
||||
/* Definitions (structs, etc.) */
|
||||
typedef struct HistoryLogLine HistoryLogLine;
|
||||
struct HistoryLogLine {
|
||||
HistoryLogLine *prev, *next;
|
||||
time_t t;
|
||||
MessageTag *mtags;
|
||||
char line[1];
|
||||
};
|
||||
|
||||
typedef struct HistoryLogObject HistoryLogObject;
|
||||
struct HistoryLogObject {
|
||||
HistoryLogObject *prev, *next;
|
||||
@@ -68,7 +60,7 @@ HistoryLogObject *history_hash_table[HISTORY_BACKEND_MEM_HASH_TABLE_SIZE];
|
||||
/* Forward declarations */
|
||||
int hbm_history_add(char *object, MessageTag *mtags, char *line);
|
||||
int hbm_history_cleanup(HistoryLogObject *h);
|
||||
int hbm_history_request(Client *client, char *object, HistoryFilter *filter);
|
||||
HistoryResult *hbm_history_request(char *object, HistoryFilter *filter);
|
||||
int hbm_history_destroy(char *object);
|
||||
int hbm_history_set_limit(char *object, int max_lines, long max_time);
|
||||
EVENT(history_mem_clean);
|
||||
@@ -263,53 +255,27 @@ int hbm_history_add(char *object, MessageTag *mtags, char *line)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int can_receive_history(Client *client)
|
||||
HistoryLogLine *duplicate_log_line(HistoryLogLine *l)
|
||||
{
|
||||
if (HasCapability(client, "server-time"))
|
||||
return 1;
|
||||
return 0;
|
||||
HistoryLogLine *n = safe_alloc(sizeof(HistoryLogLine) + strlen(l->line));
|
||||
strcpy(n->line, l->line); /* safe, see memory allocation above ^ */
|
||||
hbm_duplicate_mtags(n, l->mtags);
|
||||
return n;
|
||||
}
|
||||
|
||||
void hbm_send_line(Client *client, HistoryLogLine *l, char *batchid)
|
||||
{
|
||||
if (can_receive_history(client))
|
||||
{
|
||||
if (BadPtr(batchid))
|
||||
{
|
||||
sendto_one(client, l->mtags, "%s", l->line);
|
||||
} else {
|
||||
MessageTag *m = safe_alloc(sizeof(MessageTag));
|
||||
m->name = "batch";
|
||||
m->value = batchid;
|
||||
AddListItem(m, l->mtags);
|
||||
sendto_one(client, l->mtags, "%s", l->line);
|
||||
DelListItem(m, l->mtags);
|
||||
safe_free(m);
|
||||
}
|
||||
} else {
|
||||
/* without server-time, log playback is a bit annoying, so skip it? */
|
||||
}
|
||||
}
|
||||
|
||||
int hbm_history_request(Client *client, char *object, HistoryFilter *filter)
|
||||
HistoryResult *hbm_history_request(char *object, HistoryFilter *filter)
|
||||
{
|
||||
HistoryResult *r;
|
||||
HistoryLogObject *h = hbm_find_object(object);
|
||||
HistoryLogLine *l;
|
||||
char batch[BATCHLEN+1];
|
||||
long redline; /* Imaginary timestamp. Before the red line, history is too old. */
|
||||
int lines_sendable = 0, lines_to_skip = 0, cnt = 0;
|
||||
|
||||
if (!h || !can_receive_history(client))
|
||||
return 0;
|
||||
if (!h)
|
||||
return NULL; /* nothing found */
|
||||
|
||||
batch[0] = '\0';
|
||||
|
||||
if (HasCapability(client, "batch"))
|
||||
{
|
||||
/* Start a new batch */
|
||||
generate_batch_id(batch);
|
||||
sendto_one(client, NULL, ":%s BATCH +%s chathistory %s", me.name, batch, object);
|
||||
}
|
||||
r = safe_alloc(sizeof(HistoryResult));
|
||||
safe_strdup(r->object, object);
|
||||
|
||||
/* Decide on red line, under this the history is too old.
|
||||
* Filter can be more strict than history object (but not the other way around):
|
||||
@@ -336,13 +302,24 @@ int hbm_history_request(Client *client, char *object, HistoryFilter *filter)
|
||||
* taken into account in hbm_history_add.
|
||||
*/
|
||||
if (l->t >= redline && (++cnt > lines_to_skip))
|
||||
hbm_send_line(client, l, batch);
|
||||
{
|
||||
/* Add to result */
|
||||
HistoryLogLine *n = duplicate_log_line(l);
|
||||
if (!r->log)
|
||||
{
|
||||
/* First item */
|
||||
r->log = r->log_tail = n;
|
||||
} else
|
||||
{
|
||||
/* Quick append to tail */
|
||||
r->log_tail->next = n;
|
||||
n->prev = r->log_tail;
|
||||
r->log_tail = n; /* we are the new tail */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* End of batch */
|
||||
if (*batch)
|
||||
sendto_one(client, NULL, ":%s BATCH -%s", me.name, batch);
|
||||
return 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Clean up expired entries */
|
||||
|
||||
@@ -22,7 +22,7 @@ ModuleHeader MOD_HEADER
|
||||
/* Forward declarations */
|
||||
int hbn_history_set_limit(char *object, int max_lines, long max_time);
|
||||
int hbn_history_add(char *object, MessageTag *mtags, char *line);
|
||||
int hbn_history_request(Client *client, char *object, HistoryFilter *filter);
|
||||
HistoryResult *hbn_history_request(char *object, HistoryFilter *filter);
|
||||
int hbn_history_destroy(char *object);
|
||||
|
||||
MOD_INIT()
|
||||
@@ -59,9 +59,9 @@ int hbn_history_add(char *object, MessageTag *mtags, char *line)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hbn_history_request(Client *client, char *object, HistoryFilter *filter)
|
||||
HistoryResult *hbn_history_request(char *object, HistoryFilter *filter)
|
||||
{
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hbn_history_set_limit(char *object, int max_lines, long max_time)
|
||||
|
||||
Reference in New Issue
Block a user