Add output queue
This commit is contained in:
parent
2643883a88
commit
640e3fd3a9
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import queue
|
||||||
import socket
|
import socket
|
||||||
import asynchat
|
import asynchat
|
||||||
import asyncore
|
import asyncore
|
||||||
|
@ -14,6 +15,8 @@ import traceback
|
||||||
import sys
|
import sys
|
||||||
from inspect import getargspec
|
from inspect import getargspec
|
||||||
from socket import SHUT_RDWR
|
from socket import SHUT_RDWR
|
||||||
|
from threading import Thread
|
||||||
|
from time import sleep,time
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
@ -44,6 +47,12 @@ class IRCCore(asynchat.async_chat):
|
||||||
self.ipv6 = False
|
self.ipv6 = False
|
||||||
"""Use IPv6?"""
|
"""Use IPv6?"""
|
||||||
|
|
||||||
|
self.OUTPUT_BUFFER_SIZE = 1000
|
||||||
|
self.SEND_WAIT = 0.800
|
||||||
|
self.outputQueue = queue.PriorityQueue(self.OUTPUT_BUFFER_SIZE)
|
||||||
|
self.outputQueueRunner = OutputQueueRunner(self)
|
||||||
|
self.outputQueueRunner.start()
|
||||||
|
|
||||||
# IRC Messages are terminated with \r\n
|
# IRC Messages are terminated with \r\n
|
||||||
self.set_terminator(b"\r\n")
|
self.set_terminator(b"\r\n")
|
||||||
|
|
||||||
|
@ -57,8 +66,18 @@ class IRCCore(asynchat.async_chat):
|
||||||
asyncore.loop(map=self.asynmap)
|
asyncore.loop(map=self.asynmap)
|
||||||
|
|
||||||
def kill(self):
|
def kill(self):
|
||||||
"""TODO close the socket"""
|
"""Send quit message and close the socket"""
|
||||||
|
# Pauses output queue
|
||||||
|
self.outputQueueRunner.paused = True
|
||||||
|
# Clear any pending messages
|
||||||
|
self.outputQueueRunner.clear()
|
||||||
|
# Send quit message and flush queue
|
||||||
self.act_QUIT("Help! Another thread is killing me :(")
|
self.act_QUIT("Help! Another thread is killing me :(")
|
||||||
|
self.outputQueueRunner.flush()
|
||||||
|
# Signal disconnection
|
||||||
|
self.alive=False
|
||||||
|
# Close socket
|
||||||
|
self.close()
|
||||||
|
|
||||||
" Net related code here on down "
|
" Net related code here on down "
|
||||||
|
|
||||||
|
@ -126,16 +145,13 @@ class IRCCore(asynchat.async_chat):
|
||||||
self.fire_hook("_CONNECT")
|
self.fire_hook("_CONNECT")
|
||||||
self.log.debug("handle_connect: complete")
|
self.log.debug("handle_connect: complete")
|
||||||
|
|
||||||
def sendRaw(self, text):
|
def sendRaw(self, text, prio=2):
|
||||||
"""Send a raw string to the IRC server
|
"""Queue messages (raw string) to be sent to the IRC server
|
||||||
|
|
||||||
:param text: the string to send
|
:param text: the string to send
|
||||||
:type text: str"""
|
:type text: str"""
|
||||||
if self.connected:
|
text = (text+"\r\n").encode("UTF-8").decode().encode("UTF-8")
|
||||||
#self.log.debug(">> "+text)
|
self.outputQueue.put((prio, text), block=False)
|
||||||
self.send( (text+"\r\n").encode("UTF-8").decode().encode("UTF-8"))
|
|
||||||
else:
|
|
||||||
self.log.warning("Send attempted while disconnected. >> "+text)
|
|
||||||
|
|
||||||
def process_data(self, data):
|
def process_data(self, data):
|
||||||
"""Process one line of tet irc sent us
|
"""Process one line of tet irc sent us
|
||||||
|
@ -413,5 +429,59 @@ class IRCCore(asynchat.async_chat):
|
||||||
|
|
||||||
:param message: quit message
|
:param message: quit message
|
||||||
:type message: str"""
|
:type message: str"""
|
||||||
self.sendRaw("QUIT :%s" % message)
|
self.sendRaw("QUIT :%s" % message, prio=0)
|
||||||
|
|
||||||
|
class OutputQueueRunner(Thread):
|
||||||
|
"""Rate-limited output queue"""
|
||||||
|
def __init__(self, bot):
|
||||||
|
Thread.__init__(self, daemon=True)
|
||||||
|
self.bot = bot #reference to main bot thread
|
||||||
|
self.log = logging.getLogger('OutputQueueRunner')
|
||||||
|
self.paused = False
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Constantly sends messages unless bot is disconnecting/ed"""
|
||||||
|
lastSend = time()
|
||||||
|
while True:
|
||||||
|
# Rate limit
|
||||||
|
sinceLast = time() - lastSend
|
||||||
|
if sinceLast < self.bot.SEND_WAIT:
|
||||||
|
toSleep = self.bot.SEND_WAIT - sinceLast
|
||||||
|
sleep(toSleep)
|
||||||
|
|
||||||
|
# Pop item and execute
|
||||||
|
if self.bot.connected and not self.paused:
|
||||||
|
try:
|
||||||
|
self.process_queue_item()
|
||||||
|
lastSend = time()
|
||||||
|
except queue.Empty:
|
||||||
|
#self.log.debug("Queue is empty")
|
||||||
|
pass
|
||||||
|
sleep(0) # yield
|
||||||
|
|
||||||
|
def process_queue_item(self):
|
||||||
|
"""Remove 1 item from queue and process it"""
|
||||||
|
prio,text = self.bot.outputQueue.get(block=True, timeout=10)
|
||||||
|
#self.log.debug("%s>> %s" % (prio,text))
|
||||||
|
self.bot.outputQueue.task_done()
|
||||||
|
self.bot.send(text)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Discard all items from queue"""
|
||||||
|
length = self.bot.outputQueue.qsize()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
self.bot.outputQueue.get(block=False)
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
#self.log.debug("output queue cleared")
|
||||||
|
return length
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
"""Process all items in queue"""
|
||||||
|
for i in range(0, self.bot.outputQueue.qsize()):
|
||||||
|
try:
|
||||||
|
self.process_queue_item()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
#self.log.debug("output queue flushed")
|
||||||
|
|
Loading…
Reference in New Issue