mirror of
https://github.com/Mikaela/Limnoria.git
synced 2025-01-23 02:24:12 +01:00
Fixed bug #934240.
This commit is contained in:
parent
b82991609e
commit
5d8f0156fb
@ -98,6 +98,7 @@ class RSS(callbacks.Privmsg):
|
|||||||
self.locks = {}
|
self.locks = {}
|
||||||
self.lastRequest = {}
|
self.lastRequest = {}
|
||||||
self.cachedFeeds = {}
|
self.cachedFeeds = {}
|
||||||
|
self.gettingLockLock = threading.Lock()
|
||||||
for (name, url) in registry._cache.iteritems():
|
for (name, url) in registry._cache.iteritems():
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
if name.startswith('supybot.plugins.rss.feeds.'):
|
if name.startswith('supybot.plugins.rss.feeds.'):
|
||||||
@ -127,7 +128,7 @@ class RSS(callbacks.Privmsg):
|
|||||||
# the feed, because this thread may run for a number of bytecodes
|
# the feed, because this thread may run for a number of bytecodes
|
||||||
# before it switches to a thread that'll get the lock in
|
# before it switches to a thread that'll get the lock in
|
||||||
# _newHeadlines.
|
# _newHeadlines.
|
||||||
if self.locks[url].acquire(blocking=False):
|
if self.acquireLock(url, blocking=False):
|
||||||
try:
|
try:
|
||||||
t = threading.Thread(target=self._newHeadlines,
|
t = threading.Thread(target=self._newHeadlines,
|
||||||
name='Fetching <%s>' % url,
|
name='Fetching <%s>' % url,
|
||||||
@ -137,7 +138,7 @@ class RSS(callbacks.Privmsg):
|
|||||||
t.setDaemon(True)
|
t.setDaemon(True)
|
||||||
t.start()
|
t.start()
|
||||||
finally:
|
finally:
|
||||||
self.locks[url].release()
|
self.releaseLock(url)
|
||||||
time.sleep(0.1) # So other threads can run.
|
time.sleep(0.1) # So other threads can run.
|
||||||
|
|
||||||
def _newHeadlines(self, irc, channels, name, url):
|
def _newHeadlines(self, irc, channels, name, url):
|
||||||
@ -148,7 +149,7 @@ class RSS(callbacks.Privmsg):
|
|||||||
# want to sent their news messages to the appropriate channels.
|
# want to sent their news messages to the appropriate channels.
|
||||||
# Note that we're allowed to acquire this lock twice within the
|
# Note that we're allowed to acquire this lock twice within the
|
||||||
# same thread because it's an RLock and not just a normal Lock.
|
# same thread because it's an RLock and not just a normal Lock.
|
||||||
self.locks[url].acquire()
|
self.acquireLock(url)
|
||||||
try:
|
try:
|
||||||
oldresults = self.cachedFeeds[url]
|
oldresults = self.cachedFeeds[url]
|
||||||
oldheadlines = self.getHeadlines(oldresults)
|
oldheadlines = self.getHeadlines(oldresults)
|
||||||
@ -172,7 +173,7 @@ class RSS(callbacks.Privmsg):
|
|||||||
irc.replies(newheadlines, prefixer=pre, joiner=sep,
|
irc.replies(newheadlines, prefixer=pre, joiner=sep,
|
||||||
to=channel, prefixName=False, private=True)
|
to=channel, prefixName=False, private=True)
|
||||||
finally:
|
finally:
|
||||||
self.locks[url].release()
|
self.releaseLock(url)
|
||||||
|
|
||||||
def willGetNewFeed(self, url):
|
def willGetNewFeed(self, url):
|
||||||
now = time.time()
|
now = time.time()
|
||||||
@ -182,12 +183,27 @@ class RSS(callbacks.Privmsg):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def acquireLock(self, url, blocking=True):
|
||||||
|
try:
|
||||||
|
self.gettingLockLock.acquire()
|
||||||
|
try:
|
||||||
|
lock = self.locks[url]
|
||||||
|
except KeyError:
|
||||||
|
lock = threading.RLock()
|
||||||
|
self.locks[url] = lock
|
||||||
|
return lock.acquire(blocking=blocking)
|
||||||
|
finally:
|
||||||
|
self.gettingLockLock.release()
|
||||||
|
|
||||||
|
def releaseLock(self, url):
|
||||||
|
self.locks[url].release()
|
||||||
|
|
||||||
def getFeed(self, url):
|
def getFeed(self, url):
|
||||||
try:
|
try:
|
||||||
# This is the most obvious place to acquire the lock, because a
|
# This is the most obvious place to acquire the lock, because a
|
||||||
# malicious user could conceivably flood the bot with rss commands
|
# malicious user could conceivably flood the bot with rss commands
|
||||||
# and DoS the website in question.
|
# and DoS the website in question.
|
||||||
self.locks[url].acquire()
|
self.acquireLock(url)
|
||||||
if self.willGetNewFeed(url):
|
if self.willGetNewFeed(url):
|
||||||
try:
|
try:
|
||||||
self.log.info('Downloading new feed from <%s>', url)
|
self.log.info('Downloading new feed from <%s>', url)
|
||||||
@ -203,7 +219,7 @@ class RSS(callbacks.Privmsg):
|
|||||||
self.lastRequest[url] = 0
|
self.lastRequest[url] = 0
|
||||||
return {'items': [{'title': 'Unable to download feed.'}]}
|
return {'items': [{'title': 'Unable to download feed.'}]}
|
||||||
finally:
|
finally:
|
||||||
self.locks[url].release()
|
self.releaseLock(url)
|
||||||
|
|
||||||
def getHeadlines(self, feed):
|
def getHeadlines(self, feed):
|
||||||
return [utils.htmlToText(d['title'].strip()) for d in feed['items']]
|
return [utils.htmlToText(d['title'].strip()) for d in feed['items']]
|
||||||
@ -216,7 +232,8 @@ class RSS(callbacks.Privmsg):
|
|||||||
to 1800 (30 minutes) since that's what most websites prefer.
|
to 1800 (30 minutes) since that's what most websites prefer.
|
||||||
""" % (name, url)
|
""" % (name, url)
|
||||||
name = callbacks.canonicalName(name)
|
name = callbacks.canonicalName(name)
|
||||||
self.locks[url] = threading.RLock()
|
if url not in self.locks:
|
||||||
|
self.locks[url] = threading.RLock()
|
||||||
if hasattr(self, name):
|
if hasattr(self, name):
|
||||||
s = 'I already have a command in this plugin named %s' % name
|
s = 'I already have a command in this plugin named %s' % name
|
||||||
raise callbacks.Error, s
|
raise callbacks.Error, s
|
||||||
|
Loading…
Reference in New Issue
Block a user