286 lines
8.7 KiB
Python
286 lines
8.7 KiB
Python
from twisted.internet.threads import deferToThread
|
|
|
|
import main
|
|
from utils.logging.debug import trace
|
|
from utils.logging.log import warn
|
|
from utils.parsing import parsen
|
|
|
|
|
|
def getWhoSingle(name, query):
|
|
result = main.r.sscan("live.who." + name, 0, query, count=999999)
|
|
if result[1] == []:
|
|
return None
|
|
return (i.decode() for i in result[1])
|
|
|
|
|
|
def getWho(query):
|
|
result = {}
|
|
for i in main.network.keys():
|
|
f = getWhoSingle(i, query)
|
|
if f:
|
|
result[i] = f
|
|
return result
|
|
|
|
|
|
def getChansSingle(name, nick):
|
|
nick = ("live.chan." + name + "." + i for i in nick)
|
|
result = main.r.sinter(*nick)
|
|
if len(result) == 0:
|
|
return None
|
|
return (i.decode() for i in result)
|
|
|
|
|
|
def getChanList(name, nick):
|
|
chanspace = "live.chan." + name + "." + nick
|
|
result = main.r.smembers(chanspace)
|
|
if len(result) == 0:
|
|
return None
|
|
return (i.decode() for i in result)
|
|
|
|
|
|
def getUserNum(name, channels):
|
|
"""
|
|
Get the number of users on a list of channels.
|
|
"""
|
|
chanspace = ("live.who." + name + "." + i for i in channels)
|
|
results = {}
|
|
for channel, space in zip(channels, chanspace):
|
|
results[channel] = main.r.scard(space)
|
|
return results
|
|
|
|
|
|
def getChanNum(name, nicks):
|
|
"""
|
|
Get the number of channels a list of users are on.
|
|
"""
|
|
nickspace = ("live.chan." + name + "." + i for i in nicks)
|
|
results = {}
|
|
for nick, space in zip(nicks, nickspace):
|
|
results[nick] = main.r.scard(space)
|
|
return results
|
|
|
|
|
|
def getChans(nick):
|
|
result = {}
|
|
for i in main.network.keys():
|
|
f = getChansSingle(i, nick)
|
|
if f:
|
|
result[i] = f
|
|
return result
|
|
|
|
|
|
def getUsersSingle(name, nick):
|
|
nick = ("live.who." + name + "." + i for i in nick)
|
|
result = main.r.sinter(*nick)
|
|
if len(result) == 0:
|
|
return None
|
|
return (i.decode() for i in result)
|
|
|
|
|
|
def getUsers(nick):
|
|
result = {}
|
|
for i in main.network.keys():
|
|
f = getUsersSingle(i, nick)
|
|
if f:
|
|
result[i] = f
|
|
return result
|
|
|
|
|
|
def getNumWhoEntries(name):
|
|
return main.r.scard("live.who." + name)
|
|
|
|
|
|
def getNumTotalWhoEntries():
|
|
total = 0
|
|
for i in main.network.keys():
|
|
total += getNumWhoEntries(i)
|
|
return total
|
|
|
|
|
|
def getNamespace(name, channel, nick):
|
|
gnamespace = "live.who.%s" % name
|
|
namespace = "live.who.%s.%s" % (name, channel)
|
|
chanspace = "live.chan.%s.%s" % (name, nick)
|
|
mapspace = "live.map.%s" % name
|
|
return (gnamespace, namespace, chanspace, mapspace)
|
|
|
|
|
|
def _initialUsers(name, channel, users):
|
|
gnamespace = "live.who.%s" % name
|
|
mapspace = "live.map.%s" % name
|
|
p = main.r.pipeline()
|
|
for i in users:
|
|
user = i[0] + "!" + i[1] + "@" + i[2]
|
|
p.hset(mapspace, i[0], user)
|
|
p.sadd(gnamespace, user)
|
|
p.execute()
|
|
|
|
|
|
def initialUsers(name, channel, users):
|
|
trace("Initialising WHO records for %s on %s" % (channel, name))
|
|
deferToThread(_initialUsers, name, channel, users)
|
|
# d.addCallback(testCallback)
|
|
|
|
|
|
def _initialNames(name, channel, names):
|
|
namespace = "live.who.%s.%s" % (name, channel)
|
|
p = main.r.pipeline()
|
|
for mode, nick in names:
|
|
p.sadd(namespace, nick)
|
|
p.sadd("live.chan." + name + "." + nick, channel)
|
|
if mode:
|
|
p.hset("live.prefix." + name + "." + channel, nick, mode)
|
|
p.execute()
|
|
|
|
|
|
def initialNames(name, channel, names):
|
|
trace("Initialising NAMES records for %s on %s" % (channel, name))
|
|
deferToThread(_initialNames, name, channel, names)
|
|
# d.addCallback(testCallback)
|
|
|
|
|
|
def editUser(name, user):
|
|
gnamespace = "live.who.%s" % name
|
|
mapspace = "live.map.%s" % name
|
|
parsed = parsen(user)
|
|
p = main.r.pipeline()
|
|
p.sadd(gnamespace, user)
|
|
p.hset(mapspace, parsed[0], user) # add nick -> user mapping
|
|
p.execute()
|
|
|
|
|
|
def addUser(name, channel, nick, user):
|
|
gnamespace, namespace, chanspace, mapspace = getNamespace(name, channel, nick)
|
|
p = main.r.pipeline()
|
|
p.sadd(gnamespace, user)
|
|
p.sadd(namespace, nick)
|
|
p.sadd(chanspace, channel)
|
|
p.hset(mapspace, nick, user)
|
|
p.execute()
|
|
|
|
|
|
def delUser(name, channel, nick, user):
|
|
gnamespace, namespace, chanspace, mapspace = getNamespace(name, channel, nick)
|
|
p = main.r.pipeline()
|
|
channels = main.r.smembers(chanspace)
|
|
p.srem(namespace, nick)
|
|
if channels == {channel.encode()}: # can we only see them on this channel?
|
|
p.delete(chanspace) # remove channel tracking entry
|
|
p.hdel("live.prefix." + name + "." + channel, nick) # remove prefix tracking entry
|
|
p.hdel(mapspace, nick) # remove nick mapping entry
|
|
if user:
|
|
p.srem(gnamespace, user) # remove global userinfo entry
|
|
else:
|
|
warn("Attempt to delete nonexistent user: %s" % user)
|
|
else:
|
|
p.srem(chanspace, channel) # keep up - remove the channel from their list
|
|
p.execute()
|
|
|
|
|
|
def escape(text):
|
|
chars = ["[", "]", "^", "-", "*", "?"]
|
|
text = text.replace("\\", "\\\\")
|
|
for i in chars:
|
|
text = text.replace(i, "\\" + i)
|
|
return text
|
|
|
|
|
|
def getUserByNick(name, nick):
|
|
gnamespace = "live.who.%s" % name # "nick": "nick!ident@host"
|
|
mapspace = "live.map.%s" % name
|
|
if main.r.hexists(mapspace, nick):
|
|
return main.r.hget(mapspace, nick)
|
|
else:
|
|
warn("Entry doesn't exist: %s on %s - attempting auxiliary lookup" % (nick, mapspace))
|
|
# return False
|
|
# legacy code below - remove when map is reliable
|
|
usermatch = main.r.sscan(gnamespace, match=escape(nick) + "!*", count=999999999)
|
|
if usermatch[1] == []:
|
|
warn("No matches found for user query: %s on %s" % (nick, name))
|
|
return False
|
|
else:
|
|
if len(usermatch[1]) == 1:
|
|
user = usermatch[1][0]
|
|
return user
|
|
else:
|
|
warn("Auxiliary lookup failed: %s on %s" % (nick, gnamespace))
|
|
return False
|
|
|
|
|
|
def renameUser(name, oldnick, olduser, newnick, newuser):
|
|
gnamespace = "live.who.%s" % name
|
|
chanspace = "live.chan.%s.%s" % (name, oldnick)
|
|
mapspace = "live.map.%s" % name
|
|
newchanspace = "live.chan.%s.%s" % (name, newnick)
|
|
p = main.r.pipeline()
|
|
p.srem(gnamespace, olduser)
|
|
p.sadd(gnamespace, newuser)
|
|
for i in main.r.smembers(chanspace):
|
|
i = i.decode()
|
|
p.srem("live.who." + name + "." + i, oldnick)
|
|
p.sadd("live.who." + name + "." + i, newnick)
|
|
p.hdel(mapspace, oldnick)
|
|
p.hset(mapspace, newnick, newuser)
|
|
if main.r.exists("live.prefix." + name + "." + i): # if there's a prefix entry for the channel
|
|
if main.r.hexists("live.prefix." + name + "." + i, oldnick): # if the old nick is in it
|
|
mode = main.r.hget("live.prefix." + name + "." + i, oldnick) # retrieve old modes
|
|
p.hset("live.prefix." + name + "." + i, newnick, mode) # set old modes to new nickname
|
|
if main.r.exists(chanspace):
|
|
p.rename(chanspace, newchanspace)
|
|
else:
|
|
warn("Key doesn't exist: %s" % chanspace)
|
|
p.execute()
|
|
|
|
|
|
def delUserByNick(name, channel, nick): # kick
|
|
user = getUserByNick(name, nick)
|
|
if not user:
|
|
return
|
|
delUser(name, channel, nick, user)
|
|
|
|
|
|
def delUserByNetwork(name, nick, user): # quit
|
|
gnamespace = "live.who.%s" % name
|
|
chanspace = "live.chan.%s.%s" % (name, nick)
|
|
mapspace = "live.chan.%s" % name
|
|
p = main.r.pipeline()
|
|
p.srem(gnamespace, user)
|
|
for i in main.r.smembers(chanspace):
|
|
p.srem("live.who." + name + "." + i.decode(), nick)
|
|
p.hdel("live.prefix." + name + "." + i.decode(), nick)
|
|
|
|
p.delete(chanspace)
|
|
p.hdel(mapspace, nick)
|
|
p.execute()
|
|
|
|
|
|
def _delChannels(net, channels):
|
|
gnamespace = "live.who.%s" % net
|
|
mapspace = "live.map.%s" % net
|
|
p = main.r.pipeline()
|
|
for channel in channels:
|
|
namespace = "live.who.%s.%s" % (net, channel)
|
|
for i in main.r.smembers(namespace):
|
|
nick = i.decode()
|
|
# user = getUserByNick(net, nick) -- far too many function calls
|
|
user = main.r.hget(mapspace, nick)
|
|
if not user:
|
|
warn("User lookup failed: %s on %s" % (nick, net))
|
|
if main.r.smembers("live.chan." + net + "." + nick) == {channel.encode()}:
|
|
if user:
|
|
p.srem(gnamespace, user)
|
|
|
|
p.delete("live.chan." + net + "." + nick)
|
|
p.hdel(mapspace, nick) # remove map entry
|
|
else:
|
|
p.srem("live.chan." + net + "." + nick, channel)
|
|
p.delete(namespace)
|
|
p.delete("live.prefix." + net + "." + channel)
|
|
p.execute()
|
|
|
|
|
|
def delChannels(net, channels): # we have left a channel
|
|
trace("Purging channel %s for %s" % (", ".join(channels), net))
|
|
deferToThread(_delChannels, net, channels)
|
|
# d.addCallback(testCallback)
|