Merge branch 'development'
[NeonServV5.git] / src / IRCQueue.c
index 939956e052e29b24d1b6433831a84130f0fa6f03..a7cc1a4d00fd52521ba0cc108a3db83c9dbf0d69 100644 (file)
@@ -1,5 +1,5 @@
-/* IRCQueue.c - NeonServ v5.1
- * Copyright (C) 2011  Philipp Kreil (pk910)
+/* IRCQueue.c - NeonServ v5.6
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
  * 
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,6 +16,9 @@
  */
 #include "IRCQueue.h"
 #include "ClientSocket.h"
+#include "IOHandler.h"
+#include "tools.h"
+#include "log.h"
 
 #define MAXPENALTY 8 /* 4 messages */
 
@@ -26,20 +29,25 @@ struct QueueEntry {
 
 struct BotQueue {
     struct ClientSocket *client;
-    int penalty;
+    struct IODescriptor *iofd;
+    int penalty : 8;
+    int rem_penalty : 8;
     struct QueueEntry *fastqueue_first, *fastqueue_last;
     struct QueueEntry *normalqueue_first, *normalqueue_last;
     struct QueueEntry *textqueue_first, *textqueue_last;
 };
 
+static IOHANDLER_CALLBACK(queue_callback);
+
 static struct BotQueue *initialize_queue(struct ClientSocket *client) {
     struct BotQueue *queue = malloc(sizeof(*queue));
     if (!queue) {
-        perror("malloc() failed");
+        printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
         return NULL;
     }
     queue->client = client;
     client->queue = queue;
+    queue->iofd = NULL;
     queue->penalty = 0;
     queue->fastqueue_first = NULL;
     queue->fastqueue_last = NULL;
@@ -50,12 +58,19 @@ static struct BotQueue *initialize_queue(struct ClientSocket *client) {
     return queue;
 }
 
+static int calculate_penalty(char *message) {
+    int msglen = strlen(message);
+    int penalty = (2 + msglen / 100);
+    return penalty;
+}
+
 int queue_add(struct ClientSocket *client, char* msg, int len) {
     if(!client->queue)
         client->queue = initialize_queue(client);
     struct BotQueue *queue = client->queue;
     char *args = strstr(msg, " ");
     int type;
+    int add_queue = 0;
     if(args) {
         *args = '\0';
         if(!stricmp(msg, "MODE")) 
@@ -75,47 +90,82 @@ int queue_add(struct ClientSocket *client, char* msg, int len) {
         *args = ' ';
     } else
         type = 2;
-    struct QueueEntry *entry = malloc(sizeof(*entry));
-    if (!entry) {
-        perror("malloc() failed");
-        return 0;
+    
+    //check if we need to queue
+    switch(type) {
+    case 1:
+        if(queue->textqueue_first) {
+            add_queue = 1;
+            break;
+        }
+    case 2:
+        if(queue->normalqueue_first) {
+            add_queue = 1;
+            break;
+        }
+    case 3:
+        if(queue->fastqueue_first) {
+            add_queue = 1;
+            break;
+        }
+    default:
+        if(queue->penalty >= MAXPENALTY)
+            add_queue = 1;
+        break;
     }
-    entry->msg = strdup(msg);
-    entry->next = NULL;
-    if(type == 1) { //low priority
-        if(queue->textqueue_last) {
-            queue->textqueue_last->next = entry;
-            queue->textqueue_last = entry;
-        } else {
-            queue->textqueue_last = entry;
-            queue->textqueue_first = entry;
+    
+    if(!add_queue) {
+        int penalty = calculate_penalty(msg);
+        write_socket_force(client, msg, len);
+        queue->penalty += penalty;
+        if(!queue->iofd) {
+            struct timeval timeout;
+            gettimeofday(&timeout, NULL);
+            if(queue->penalty >= MAXPENALTY)
+                queue->rem_penalty = (queue->penalty - MAXPENALTY)+1;
+            else
+                queue->rem_penalty = queue->penalty;
+            timeout.tv_sec += queue->rem_penalty;
+            queue->iofd = iohandler_timer(timeout, queue_callback);
+            queue->iofd->data = queue;
         }
-    } else if(type == 2) { //normal priority
-        if(queue->normalqueue_last) {
-            queue->normalqueue_last->next = entry;
-            queue->normalqueue_last = entry;
-        } else {
-            queue->normalqueue_last = entry;
-            queue->normalqueue_first = entry;
+    } else {
+        struct QueueEntry *entry = malloc(sizeof(*entry));
+        if (!entry) {
+            printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
+            return 0;
         }
-    } else if(type == 3) { //high priority
-        if(queue->fastqueue_last) {
-            queue->fastqueue_last->next = entry;
-            queue->fastqueue_last = entry;
-        } else {
-            queue->fastqueue_last = entry;
-            queue->fastqueue_first = entry;
+        entry->msg = strdup(msg);
+        entry->next = NULL;
+        if(type == 1) { //low priority
+            if(queue->textqueue_last) {
+                queue->textqueue_last->next = entry;
+                queue->textqueue_last = entry;
+            } else {
+                queue->textqueue_last = entry;
+                queue->textqueue_first = entry;
+            }
+        } else if(type == 2) { //normal priority
+            if(queue->normalqueue_last) {
+                queue->normalqueue_last->next = entry;
+                queue->normalqueue_last = entry;
+            } else {
+                queue->normalqueue_last = entry;
+                queue->normalqueue_first = entry;
+            }
+        } else if(type == 3) { //high priority
+            if(queue->fastqueue_last) {
+                queue->fastqueue_last->next = entry;
+                queue->fastqueue_last = entry;
+            } else {
+                queue->fastqueue_last = entry;
+                queue->fastqueue_first = entry;
+            }
         }
     }
     return 1;
 }
 
-static int calculate_penalty(char *message) {
-    int msglen = strlen(message);
-    int penalty = (2 + msglen / 100);
-    return penalty;
-}
-
 static void dequeue_bot(struct ClientSocket *client) {
     if(client->queue->penalty >= MAXPENALTY) return;
     int penalty;
@@ -183,37 +233,34 @@ void queue_destroy(struct ClientSocket *client) {
         free(entry->msg);
         free(entry);
     }
+    if(client->queue->iofd)
+        iohandler_close(client->queue->iofd);
     free(client->queue);
     client->queue = NULL;
 }
 
-static struct timeval lastloop;
-void queue_init() {
-    gettimeofday(&lastloop, NULL);
-}
-
-
-void queue_loop() {
-    struct ClientSocket *bot;
-    struct timeval now;
-    gettimeofday(&now, NULL);
-    long mtime, seconds, useconds;
-    seconds  = now.tv_sec  - lastloop.tv_sec;
-    useconds = now.tv_usec - lastloop.tv_usec;
-    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
-    int fullseconds = mtime/1000;
-    if(fullseconds) {
-        lastloop.tv_sec += fullseconds;
-        for(bot = getBots(0, NULL); bot; bot = getBots(0, bot)) {
-            if(bot->queue && bot->queue->penalty) {
-                bot->queue->penalty -= fullseconds;
-                if(bot->queue->penalty < 0)
-                    bot->queue->penalty = 0;
-            }
+static IOHANDLER_CALLBACK(queue_callback) {
+    struct BotQueue *queue = event->iofd->data;
+    switch(event->type) {
+    case IOEVENT_TIMEOUT:
+        queue->penalty -= queue->rem_penalty;
+        dequeue_bot(queue->client);
+        if(queue->penalty > 0) {
+            struct timeval timeout;
+            gettimeofday(&timeout, NULL);
+            if(queue->penalty >= MAXPENALTY)
+                queue->rem_penalty = (queue->penalty - MAXPENALTY)+1;
+            else
+                queue->rem_penalty = queue->penalty;
+            timeout.tv_sec += queue->rem_penalty;
+            queue->iofd = iohandler_timer(timeout, queue_callback);
+            queue->iofd->data = queue;
+        } else {
+            queue->iofd = NULL;
+            queue->penalty = 0;
         }
-    }
-    for(bot = getBots(0, NULL); bot; bot = getBots(0, bot)) {
-        if(bot->queue)
-            dequeue_bot(bot);
+        break;
+    default:
+        break;
     }
 }