When a driver's run() method crashes, supybot.drivers.run() marks it
as dead and sets its 'irc' attribute to None.
This would be fine for "normal" independent drivers (like Socket used
to be), because this driver would never be called again.
But now that we use select(), some other thread may hold a reference
to this driver in a select() call frame, and call the dead driver's
'_read()' method when there is data to be read from the socket.
There is already a safeguard in '_read()' in the case the socket could
be read from, but this safeguard was missing from _handleSocketError.
This caused the "live" driver's select() to crash, which propagagated
to its run(), which caused the driver to be marked as dead, etc.
Eventually, all drivers could die, and we end up with the dreadful
"Schedule is the only remaining driver, why do we continue to live?"
in an infinite loop.
* Fix joins to many channels
If you have enough channels that the 512 byte message limit on the JOIN
message is hit then limnoria was losing the channel that put it over the
limit and not including it in the next JOIN message. This resulted in
losing one channel for every JOIN message that pushed us over 512 bytes.
We fix this by generating the JOIN message immediately after resetting
the channels list to ensure we include the channel that pushed us over
the limit. Then the next time through our JOIN msg construction we'll
add subsequent channels without forgetting the one that pushed us over.
* Add test for channel join lists
This adds a test for the issue that is fixed in the previous commit. We
ensure that when JOINs are split over multiple messages we JOIN to all
channels that were part of the input list and don't forget any of them.
When the number of hostmasks exceeds 1000 (the hardcoded size of
_patternCache and _hostmaskPatternEqualCache), this triggers
a pathological case in the LRU caches, that causes all calls to be
a cache miss.
This means that on every IRC message received, ircdb.checkIgnored triggers
a recompilation of *all* user hostmasks, which is very expensive
computationally.
This commit stores them in their own cache to prevent them from
expiring.
It mistakenly used the bot's nick as target when the message is in private,
so 'more' after a private message always answered the user did not send
a command before (because said command was attributed to the bot)
This dict was filled with IrcString keys, which is hashed
as lowercase, so when queried with a non-lowercase string,
the key would not be found, and lead to very confusing errors.
If throttle time is set to 0.0 (e.g. in tests) and the reported time
since last dequeue is also 0.0 (maybe because the timer resolution is
too low), takeMsg would throttle. This would make tests fail because
they expect messages immediately.
This issue was observed on Windows 10 20H2 with both a mingw-w64 Python
v3.8.9 from MSYS2 and several version of official Python v3.x.
Confirmed at least as far back as
aa98d987a7.
Since it's a non-integer comparison, the change shouldn't have any
observable effect in normal operation.
ChannelPluginTestCase#setUp accepts the same parameters as its
super-method PluginTestCase#setUp, but it didn't pass the arguments down
the line. Now it does.
by moving the 'smart' reply() method from NestedCommandsIrcProxy
to ReplyIrcProxy.
There is no reason only commands should have a paginated output
and not snarfers defined in PluginRegexp.
1. it binds the port, which is useless while documenting
2. in some circumstances, it prevents supybot-plugin-doc from exiting
(because the server threads are still running)