/* * Petit daemon qui va envoyer des notifications aux horaires des tâches * il vérifie si la base de données change par l'intermédiaire d'un socket, * (implémenté par un fichier stocké dans /tmp/takl.$USER), qui contient le pid * de ce daemon afin de pouvoir déterminer si un autre daemon tourne. * (Le cas où deux daemons sont lancés en même temps n'est pas traité.) */ #include #include #include #include #include #include #include #include #include #include #include "log/log.h" #include "main/include/db.h" #include "main/include/tasks.h" #include "main/include/utils.h" #include "main/include/colors.h" #include "main/include/config.h" #include "main/include/notification.h" #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) bool has_changed = false; task_list_t* tasks; pthread_mutex_t tasks_lock = PTHREAD_MUTEX_INITIALIZER; // locks tasks and has_changed at the same time void* inotify_check_changes(void* sk_path) { char* socket_path = (char*)sk_path; char buffer[EVENT_BUF_LEN]; while (1) { // Regarde si /tmp/takl.$USER a changé (donc si la BDD a changé et doit être rechargée) int fd = inotify_init(); if (fd < 0) { log_fatal("Impossible d'initialiser inotify"); free(socket_path); exit(1); } int wd = inotify_add_watch(fd, socket_path, IN_ACCESS); int length = read(fd, buffer, EVENT_BUF_LEN); if (length < 0) { log_fatal("inotify: lecture impossible"); free(socket_path); exit(1); } log_debug("Base de données changée"); pthread_mutex_lock(&tasks_lock); free_task_list(tasks); tasks = get_task_list(false, false); has_changed = true; pthread_mutex_unlock(&tasks_lock); inotify_rm_watch(fd, wd); close(fd); } return NULL; } int existing_takl_daemon(char* socket_path) { if (!access(socket_path, F_OK)) { // tmp file exists FILE* fp = fopen(socket_path, "r+"); int daemon_pid; fscanf(fp, "%d", &daemon_pid); fclose(fp); if(!kill(daemon_pid, 0)) { free(socket_path); return true; // The process is running } } FILE* fp = fopen(socket_path, "w"); fprintf(fp, "%d", getpid()); fclose(fp); return false; } int main() { bool notified_no_change = false; char* socket_path = get_socket_path(); log_debug("Socket path:%s", socket_path); if (!existing_takl_daemon(socket_path)) { log_info("TaKl " VERSION " -- Daemon started"); } else { log_info("TaKl Daemon déjà en cours d'exécution. Arrêt"); return 1; } tasks = get_task_list(false, false); pthread_t inotify_id = 0; // Lancement d'inotify dans un autre fil pthread_create(&inotify_id, NULL, inotify_check_changes, (void*)socket_path); while (1) { pthread_mutex_lock(&tasks_lock); task_t next = next_task(tasks); pthread_mutex_unlock(&tasks_lock); if (next.due_to == 0) { if (!notified_no_change) log_debug("Plus de tâches avec échéance dans la liste"); notified_no_change = true; while (1) { // sleep until change sleep(5); pthread_mutex_lock(&tasks_lock); if (has_changed) { log_debug("Changement détecté"); has_changed = false; pthread_mutex_unlock(&tasks_lock); break; } pthread_mutex_unlock(&tasks_lock); } } else { time_t now = time(0); double wait = difftime(next.due_to, now) + 5; log_debug("Prochaine tâche dans %0.1lfs", wait); notified_no_change = false; while (difftime(next.due_to, now) >= 5) { sleep(5); pthread_mutex_lock(&tasks_lock); if (has_changed) { log_debug("Changement détecté"); has_changed = false; pthread_mutex_unlock(&tasks_lock); break; } pthread_mutex_unlock(&tasks_lock); now = time(0); } if (difftime(next.due_to, now) < 5) { // Exit not du e to the break statement log_debug("Envoi de la notification tâche [%d]", next.id); desktop_notification(next); } //! si deux tâches sont à la même date à moins de 0.1s près, //! l'une des deux seulement sera affichée sleep(3); // Attendre un peu pour ne pas reconsidérer la même tâche 1063 fois. } } pthread_join(inotify_id, NULL); free_task_list(tasks); free(socket_path); return 0; }