<commit_before>/**
 * cbot.c: core CBot implementation
 */

#include <ctype.h>
#include <dlfcn.h>
#include <libconfig.h>
#include <openssl/evp.h>
#include <sc-collections.h>
#include <sqlite3.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "cbot/cbot.h"
#include "cbot_private.h"
#include "sc-lwt.h"
#include "sc-regex.h"

struct cbot_backend_ops *all_ops[] = {
	&irc_ops,
	&cli_ops,
	&signal_ops,
};

struct cbot_qmsg {
	char *msg;
	char *dest;
	struct sc_list_head list;
};

/********
 * Functions which plugins can call to perform actions. These are generally
 * delegated to the backends.
 ********/

void cbot_send(const struct cbot *cbot, const char *dest, const char *format,
               ...)
{
	va_list va;
	struct sc_charbuf cb;
	va_start(va, format);
	sc_cb_init(&cb, 1024);
	sc_cb_vprintf(&cb, (char *)format, va);
	cbot->backend_ops->send(cbot, dest, cb.buf);
	sc_cb_destroy(&cb);
	va_end(va);
}

static void cbot_sender_thread(void *arg)
{
	struct cbot *bot = arg;
	struct cbot_qmsg *qm, *tmp;
	struct sc_lwt *tsk = sc_lwt_current();
	struct timespec to;

	for (;;) {
		to.tv_nsec = 1000 * 1000 * 200; /* 5 per secnd */
		to.tv_sec = 0;
		/* only queue us up if we have queued messages */
		if (bot->msgq.next != &bot->msgq)
			sc_lwt_settimeout(tsk, &to);
		sc_lwt_set_state(tsk, SC_LWT_BLOCKED);
		sc_lwt_yield();
		if (sc_lwt_shutting_down())
			break;

		qm = NULL;
		sc_list_for_each_entry(tmp, &bot->msgq, list, struct cbot_qmsg)
		{
			qm = tmp;
			break;
		}
		if (!qm)
			continue;
		sc_list_remove(&qm->list);
		/* clang-tidy can't handle this, thinks i freed qm */
		cbot_send(bot, qm->dest, "%s", qm->msg); // NOLINT
		printf("Send queued message\n");
		free(qm->msg);
		free(qm->dest);
		free(qm);
	}
}

void cbot_send_rl(struct cbot *cbot, const char *dest, const char *format, ...)
{
	va_list va;
	struct sc_charbuf cb;
	struct cbot_qmsg *qm = calloc(1, sizeof(*qm));
	sc_list_init(&qm->list);
	va_start(va, format);
	sc_cb_init(&cb, 1024);
	sc_cb_vprintf(&cb, (char *)format, va);
	va_end(va);
	qm->dest = strdup(dest);
	qm->msg = cb.buf;
	// do not destroy cb!
	sc_list_insert_end(&cbot->msgq, &qm->list);
	sc_lwt_set_state(cbot->msgq_thread, SC_LWT_RUNNABLE);
}

void cbot_me(const struct cbot *cbot, const char *dest, const char *format, ...)<commit_msg>cbot: Use logging for queued message<commit_after>/**
 * cbot.c: core CBot implementation
 */

#include <ctype.h>
#include <dlfcn.h>
#include <libconfig.h>
#include <openssl/evp.h>
#include <sc-collections.h>
#include <sqlite3.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "cbot/cbot.h"
#include "cbot_private.h"
#include "sc-lwt.h"
#include "sc-regex.h"

struct cbot_backend_ops *all_ops[] = {
	&irc_ops,
	&cli_ops,
	&signal_ops,
};

struct cbot_qmsg {
	char *msg;
	char *dest;
	struct sc_list_head list;
};

/********
 * Functions which plugins can call to perform actions. These are generally
 * delegated to the backends.
 ********/

void cbot_send(const struct cbot *cbot, const char *dest, const char *format,
               ...)
{
	va_list va;
	struct sc_charbuf cb;
	va_start(va, format);
	sc_cb_init(&cb, 1024);
	sc_cb_vprintf(&cb, (char *)format, va);
	cbot->backend_ops->send(cbot, dest, cb.buf);
	sc_cb_destroy(&cb);
	va_end(va);
}

static void cbot_sender_thread(void *arg)
{
	struct cbot *bot = arg;
	struct cbot_qmsg *qm, *tmp;
	struct sc_lwt *tsk = sc_lwt_current();
	struct timespec to;

	for (;;) {
		to.tv_nsec = 1000 * 1000 * 200; /* 5 per secnd */
		to.tv_sec = 0;
		/* only queue us up if we have queued messages */
		if (bot->msgq.next != &bot->msgq)
			sc_lwt_settimeout(tsk, &to);
		sc_lwt_set_state(tsk, SC_LWT_BLOCKED);
		sc_lwt_yield();
		if (sc_lwt_shutting_down())
			break;

		qm = NULL;
		sc_list_for_each_entry(tmp, &bot->msgq, list, struct cbot_qmsg)
		{
			qm = tmp;
			break;
		}
		if (!qm)
			continue;
		sc_list_remove(&qm->list);
		/* clang-tidy can't handle this, thinks i freed qm */
		cbot_send(bot, qm->dest, "%s", qm->msg); // NOLINT
		CL_DEBUG("Sent queued message\n");
		free(qm->msg);
		free(qm->dest);
		free(qm);
	}
}

void cbot_send_rl(struct cbot *cbot, const char *dest, const char *format, ...)
{
	va_list va;
	struct sc_charbuf cb;
	struct cbot_qmsg *qm = calloc(1, sizeof(*qm));
	sc_list_init(&qm->list);
	va_start(va, format);
	sc_cb_init(&cb, 1024);
	sc_cb_vprintf(&cb, (char *)format, va);
	va_end(va);
	qm->dest = strdup(dest);
	qm->msg = cb.buf;
	// do not destroy cb!
	sc_list_insert_end(&cbot->msgq, &qm->list);
	sc_lwt_set_state(cbot->msgq_thread, SC_LWT_RUNNABLE);
}

void cbot_me(const struct cbot *cbot, const char *dest, const char *format, ...)
{'fraction_non_alphanumeric': 0.16712098972530928, 'fraction_numerical': 0.009645628014258754, 'mean_word_length': 4.129032258064516, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1937630', 'n_tokens_mistral': 2161, 'n_tokens_neox': 2032, 'n_words': 467}