Implement Ctrl-C handling and fix a large number of small bugs

This commit is contained in:
Mark Veidemanis 2019-09-28 19:46:10 +01:00
parent 006f8db6f6
commit 15ca45e5df
12 changed files with 88 additions and 61 deletions

View File

@ -14,11 +14,11 @@ class AutoCommand:
if not spl[2].isdigit(): if not spl[2].isdigit():
failure("Must be integer, not %s" % spl[2]) failure("Must be integer, not %s" % spl[2])
return return
relayNum = int(spl[2])
id, alias = main.network[spl[1]].add_relay(int(spl[2])) id, alias = main.network[spl[1]].add_relay(relayNum)
success("Successfully created relay %s on network %s with alias %s" % (str(id), spl[1], alias)) success("Successfully created relay %s on network %s with alias %s" % (str(id), spl[1], alias))
main.saveConf("network") main.saveConf("network")
rtrn = provision.provisionRelay(int(spl[2]), spl[1]) rtrn = provision.provisionRelay(relayNum, spl[1])
success("Started provisioning network %s on relay %s for alias %s" % (spl[1], spl[2], rtrn)) success("Started provisioning network %s on relay %s for alias %s" % (spl[1], spl[2], rtrn))
return return

View File

@ -10,19 +10,23 @@ class DelCommand:
if not spl[1] in main.network.keys(): if not spl[1] in main.network.keys():
failure("No such network: %s" % spl[1]) failure("No such network: %s" % spl[1])
return return
if not spl[2].isdigit():
failure("Must be integer, not %s" % spl[2])
return
if not int(spl[2]) in main.network[spl[1]].relays.keys(): if not int(spl[2]) in main.network[spl[1]].relays.keys():
failure("No such relay: %s in network %s" % (spl[2], spl[1])) failure("No such relay: %s in network %s" % (spl[2], spl[1]))
return return
main.network[spl[1]].delete_relay(int(spl[2])) main.network[spl[1]].delete_relay(int(spl[2]))
if spl[1]+spl[2] in main.ReactorPool.keys(): name = spl[1]+spl[2]
if spl[1]+spl[2] in main.FactoryPool.keys(): if name in main.ReactorPool.keys():
main.FactoryPool[spl[1]+spl[2]].stopTrying() if name in main.FactoryPool.keys():
main.ReactorPool[spl[1]+spl[2]].disconnect() main.FactoryPool[name].stopTrying()
if spl[1]+spl[2] in main.IRCPool.keys(): main.ReactorPool[name].disconnect()
del main.IRCPool[spl[1]+spl[2]] if name in main.IRCPool.keys():
del main.ReactorPool[spl[1]+spl[2]] del main.IRCPool[name]
del main.FactoryPool[spl[1]+spl[2]] del main.ReactorPool[name]
del main.FactoryPool[name]
success("Successfully removed bot: %s" % spl[1]) success("Successfully removed bot: %s" % spl[1])
main.saveConf("network") main.saveConf("network")
return return

View File

@ -11,25 +11,31 @@ class DisableCommand:
if not spl[1] in main.network.keys(): if not spl[1] in main.network.keys():
failure("No such network: %s" % spl[1]) failure("No such network: %s" % spl[1])
return return
if not int(spl[2]) in main.network[spl[1]].relays.keys(): if not spl[2].isdigit():
failure("Must be integer, not %s" % spl[2])
return
relayNum = int(spl[2])
name = spl[1]+spl[2]
if not spl[1] in main.IRCPool.keys():
info("Note - instance not running, proceeding anyway")
if not relayNum in main.network[spl[1]].relays.keys():
failure("No such relay: %s in network %s" % (spl[2], spl[1])) failure("No such relay: %s in network %s" % (spl[2], spl[1]))
return return
main.network[spl[1]].relays[relayNum]["enabled"] = False
main.network[spl[1]].relays[int(spl[2])]["enabled"] = False user = main.network[spl[1]].aliases[relayNum]["nick"]
user = main.network[spl[1]].aliases[int(spl[2])]
network = spl[1] network = spl[1]
relay = main.network[spl[1]].relays[int(spl[2])] relay = main.network[spl[1]].relays[relayNum]
commands = {"status": ["Disconnect"]} commands = {"status": ["Disconnect"]}
deliverRelayCommands(relay, commands, user=user+"/"+network) deliverRelayCommands(relayNum, commands, user=user+"/"+network)
main.saveConf("network") main.saveConf("network")
if spl[1]+spl[2] in main.ReactorPool.keys(): if name in main.ReactorPool.keys():
if spl[1]+spl[2] in main.FactoryPool.keys(): if name in main.FactoryPool.keys():
main.FactoryPool[spl[1]+spl[2]].stopTrying() main.FactoryPool[name].stopTrying()
main.ReactorPool[spl[1]+spl[2]].disconnect() main.ReactorPool[name].disconnect()
if spl[1] in main.IRCPool.keys(): if spl[1] in main.IRCPool.keys():
del main.IRCPool[spl[1]+spl[2]] del main.IRCPool[name]
del main.ReactorPool[spl[1]+spl[2]] del main.ReactorPool[name]
del main.FactoryPool[spl[1]+spl[2]] del main.FactoryPool[name]
success("Successfully disabled bot %s on network %s" % (spl[2], spl[1])) success("Successfully disabled bot %s on network %s" % (spl[2], spl[1]))
return return
else: else:

View File

@ -17,7 +17,7 @@ class StatsCommand:
numChannels += len(main.IRCPool[i].channels) numChannels += len(main.IRCPool[i].channels)
numWhoEntries += userinfo.getNumTotalWhoEntries() numWhoEntries += userinfo.getNumTotalWhoEntries()
stats.append("Registered servers:") stats.append("Registered servers:")
stats.append(" Total: %s" % len(main.network.keys())) stats.append(" Unique: %s" % len(main.network.keys()))
stats.append("Online servers:") stats.append("Online servers:")
stats.append(" Total: %s" % len(main.IRCPool.keys())) stats.append(" Total: %s" % len(main.IRCPool.keys()))
stats.append(" Unique: %s" % len(main.liveNets())) stats.append(" Unique: %s" % len(main.liveNets()))

View File

@ -11,18 +11,21 @@ class SwhoCommand:
failure("Network does not exist: %s" % spl[1]) failure("Network does not exist: %s" % spl[1])
return return
for i in main.IRCPool.keys(): for i in main.IRCPool.keys():
if spl[1] in i: if spl[1] == main.IRCPool[i].net:
for x in main.IRCPool[i].channels: for x in main.IRCPool[i].channels:
main.IRCPool[i].who(x) main.IRCPool[i].who(x)
success("Sent WHO to all channels on all networks on %s" % spl[1]) success("Sent WHO to all channels on all networks for %s" % spl[1])
return return
elif length == 3: elif length == 3:
if not spl[1] in main.network.keys(): if not spl[1] in main.network.keys():
failure("Network does not exist: %s" % spl[1]) failure("Network does not exist: %s" % spl[1])
return return
matches = [] matches = []
# This loop gets all networks where the core network matches spl[1]
# where there is also a currently joined channel matching spl[2]
for i in main.IRCPool.keys(): for i in main.IRCPool.keys():
if spl[1] in i: if spl[1] == main.IRCPool[i].net:
for x in main.IRCPool[i].channels: for x in main.IRCPool[i].channels:
if x == spl[2]: if x == spl[2]:
main.IRCPool[i].who(x) main.IRCPool[i].who(x)

View File

@ -1,7 +1,7 @@
{ {
"pass": "pass <password>", "pass": "pass <password>",
"logout": "logout", "logout": "logout",
"del": "del <name>", "del": "del <name> <num>",
"mod": "mod <name> [<key>] [<value>]", "mod": "mod <name> [<key>] [<value>]",
"who": "who <query>", "who": "who <query>",
"join": "join <name> <num> <channel> [<key>]", "join": "join <name> <num> <channel> [<key>]",
@ -24,5 +24,6 @@
"cmd": "cmd <relay> <user> <entity> <text ...>", "cmd": "cmd <relay> <user> <entity> <text ...>",
"token": "token <add|del|list> [<key>] [<relay>]", "token": "token <add|del|list> [<key>] [<relay>]",
"all": "all <entity> <text ...>", "all": "all <entity> <text ...>",
"allc": "allc <network|alias> <(network)|(alias)> <entity> <text ...>" "allc": "allc <network|alias> <(network)|(alias)> <entity> <text ...>",
"swho": "swho <network> [<channel>]"
} }

View File

@ -72,7 +72,6 @@ class IRCRelay(IRCClient):
sendAll("[%s] %s -> %s" % (self.num, nick, msg)) sendAll("[%s] %s -> %s" % (self.num, nick, msg))
def irc_ERR_PASSWDMISMATCH(self, prefix, params): def irc_ERR_PASSWDMISMATCH(self, prefix, params):
print(', '.join("%s: %s" % item for item in vars(self).items()))
log("%s: relay password mismatch" % self.num) log("%s: relay password mismatch" % self.num)
sendAll("%s: relay password mismatch" % self.num) sendAll("%s: relay password mismatch" % self.num)
@ -113,7 +112,7 @@ class IRCBot(IRCClient):
self.versionEnv = None self.versionEnv = None
self.sourceURL = None self.sourceURL = None
self._who = {} self._tempWho = {}
self._getWho = {} self._getWho = {}
self._names = {} self._names = {}
@ -227,14 +226,17 @@ class IRCBot(IRCClient):
log("%s: password mismatch" % self.name) log("%s: password mismatch" % self.name)
sendAll("%s: password mismatch" % self.name) sendAll("%s: password mismatch" % self.name)
def who(self, channel): def _who(self, channel):
d = Deferred() d = Deferred()
if channel not in self._who: if channel not in self._tempWho:
self._who[channel] = ([], []) self._tempWho[channel] = ([], [])
self._who[channel][0].append(d) self._tempWho[channel][0].append(d)
self.sendLine("WHO %s" % channel) self.sendLine("WHO %s" % channel)
return d return d
def who(self, channel):
self._who(channel).addCallback(self.got_who)
def irc_RPL_WHOREPLY(self, prefix, params): def irc_RPL_WHOREPLY(self, prefix, params):
channel = params[1] channel = params[1]
ident = params[2] ident = params[2]
@ -243,20 +245,20 @@ class IRCBot(IRCClient):
nick = params[5] nick = params[5]
status = params[6] status = params[6]
realname = params[7] realname = params[7]
if channel not in self._who: if channel not in self._tempWho:
return return
n = self._who[channel][1] n = self._tempWho[channel][1]
n.append([nick, nick, host, server, status, realname]) n.append([nick, nick, host, server, status, realname])
self.event(type="who", nick=nick, ident=ident, host=host, realname=realname, target=channel, server=server, status=status) self.event(type="who", nick=nick, ident=ident, host=host, realname=realname, target=channel, server=server, status=status)
def irc_RPL_ENDOFWHO(self, prefix, params): def irc_RPL_ENDOFWHO(self, prefix, params):
channel = params[1] channel = params[1]
if channel not in self._who: if channel not in self._tempWho:
return return
callbacks, info = self._who[channel] callbacks, info = self._tempWho[channel]
for cb in callbacks: for cb in callbacks:
cb.callback((channel, info)) cb.callback((channel, info))
del self._who[channel] del self._tempWho[channel]
def got_who(self, whoinfo): def got_who(self, whoinfo):
userinfo.initialUsers(self.net, whoinfo[0], whoinfo[1]) userinfo.initialUsers(self.net, whoinfo[0], whoinfo[1])
@ -382,7 +384,8 @@ class IRCBot(IRCClient):
self.channels.append(channel) self.channels.append(channel)
self.names(channel).addCallback(self.got_names) self.names(channel).addCallback(self.got_names)
if main.config["Toggles"]["Who"]: if main.config["Toggles"]["Who"]:
self.who(channel).addCallback(self.got_who) #self.who(channel).addCallback(self.got_who)
#self.who(channel)
lc = LoopingCall(self.who, channel) lc = LoopingCall(self.who, channel)
self._getWho[channel] = lc self._getWho[channel] = lc
intrange = main.config["Tweaks"]["Delays"]["WhoRange"] intrange = main.config["Tweaks"]["Delays"]["WhoRange"]
@ -466,7 +469,7 @@ class IRCBotFactory(ReconnectingClientFactory):
self.relayCommands, self.user, self.stage2 = relayCommands, user, stage2 self.relayCommands, self.user, self.stage2 = relayCommands, user, stage2
def buildProtocol(self, addr): def buildProtocol(self, addr):
if self.net == None: if self.relay == None:
entry = IRCRelay(self.num, self.relayCommands, self.user, self.stage2) entry = IRCRelay(self.num, self.relayCommands, self.user, self.stage2)
else: else:
entry = IRCBot(self.net, self.num) entry = IRCBot(self.net, self.num)

View File

@ -39,14 +39,6 @@ lastMinuteSample = 0
hashKey = urandom(16) hashKey = urandom(16)
lastEvents = {} lastEvents = {}
def nets():
if not "pool" in globals():
return
networks = set()
for i in pool.keys():
networks.add("".join([x for x in i if not x in digits]))
return networks
def liveNets(): def liveNets():
networks = set() networks = set()
for i in IRCPool.keys(): for i in IRCPool.keys():

View File

@ -13,7 +13,7 @@ def getWhoSingle(name, query):
def getWho(query): def getWho(query):
result = {} result = {}
for i in main.nets(): for i in main.network.keys():
f = getWhoSingle(i, query) f = getWhoSingle(i, query)
if f: if f:
result[i] = f result[i] = f
@ -35,7 +35,7 @@ def getChanList(name, nick):
def getChans(nick): def getChans(nick):
result = {} result = {}
for i in main.nets(): for i in main.network.keys():
f = getChansSingle(i, nick) f = getChansSingle(i, nick)
if f: if f:
result[i] = f result[i] = f
@ -50,7 +50,7 @@ def getUsersSingle(name, nick):
def getUsers(nick): def getUsers(nick):
result = {} result = {}
for i in main.nets(): for i in main.network.keys():
f = getUsersSingle(i, nick) f = getUsersSingle(i, nick)
if f: if f:
result[i] = f result[i] = f
@ -61,7 +61,7 @@ def getNumWhoEntries(name):
def getNumTotalWhoEntries(): def getNumTotalWhoEntries():
total = 0 total = 0
for i in main.nets(): for i in main.network.keys():
total += getNumWhoEntries(i) total += getNumWhoEntries(i)
return total return total

View File

@ -1,18 +1,21 @@
#!/usr/bin/env python #!/usr/bin/env python
from twisted.internet import reactor from twisted.internet import reactor
from twisted.internet.ssl import DefaultOpenSSLContextFactory from twisted.internet.ssl import DefaultOpenSSLContextFactory
from sys import argv, stdout, stderr import sys
from signal import signal, SIGINT
#from twisted.python import log #from twisted.python import log
#from sys import stdout #from sys import stdout
#log.startLogging(stdout) #log.startLogging(stdout)
from sys import stdout, stderr # Import again because we want to override
from codecs import getwriter # fix printing odd shit to the terminal from codecs import getwriter # fix printing odd shit to the terminal
stdout = getwriter("utf8")(stdout) # this is a generic fix but we all know stdout = getwriter("utf8")(stdout) # this is a generic fix but we all know
stderr = getwriter("utf8")(stderr) # it's just for the retards on Rizon using stderr = getwriter("utf8")(stderr) # it's just for the retards on Rizon using
# unicode quit messages for no reason # unicode quit messages for no reason
import main import main
main.initMain() main.initMain()
if "--debug" in argv: # yes really from utils.cleanup import handler
signal(SIGINT, handler) # Handle Ctrl-C and run the cleanup routine
if "--debug" in sys.argv: # yes really
main.config["Debug"] = True main.config["Debug"] = True
from utils.logging.log import * from utils.logging.log import *
from utils.loaders.command_loader import loadCommands from utils.loaders.command_loader import loadCommands

15
utils/cleanup.py Normal file
View File

@ -0,0 +1,15 @@
import main
from twisted.internet import reactor
from utils.logging.debug import debug
from utils.logging.log import *
import sys
def handler(sig, frame):
log("Received SIGINT, cleaning up")
cleanup()
def cleanup():
debug("Flushing Redis database")
main.r.flushdb()
reactor.stop()
#sys.exit(1)

View File

@ -1,6 +1,6 @@
from os import listdir from os import listdir
from importlib import reload from importlib import reload
from sys import modules import sys
from utils.logging.debug import debug from utils.logging.debug import debug
from utils.logging.log import * from utils.logging.log import *
@ -13,8 +13,8 @@ def loadSingle(commandName):
className = commandName.capitalize()+"Command" className = commandName.capitalize()+"Command"
try: try:
if commandName in CommandMap.keys(): if commandName in CommandMap.keys():
reload(modules["commands."+commandName]) reload(sys.modules["commands."+commandName])
CommandMap[commandName] = getattr(modules["commands."+commandName], className) CommandMap[commandName] = getattr(sys.modules["commands."+commandName], className)
debug("Reloaded command: %s" % commandName) debug("Reloaded command: %s" % commandName)
return "RELOAD" return "RELOAD"
module = __import__('commands.%s' % commandName) module = __import__('commands.%s' % commandName)