gnuradionetwork/frn/clienttracker.py

312 lines
9.7 KiB
Python

# -*- coding: utf-8 -*-
#
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
# See LICENSE.txt for copyright info
import shelve
from twisted.python import log
from frn.user import FRNUser
CLIENTS_ORDER = ['Crosslink', 'Parrot', 'Gateway', 'PC Only']
def client_cmp(a, b):
try:
ta = CLIENTS_ORDER.index(a.BC)
except:
ta = CLIENTS_ORDER.index('Gateway')
try:
tb = CLIENTS_ORDER.index(b.BC)
except:
tb = CLIENTS_ORDER.index('Gateway')
if ta < tb:
r = -1
elif ta > tb:
r = 1
else:
if a.ON < b.ON:
r = -1
elif a.ON > b.ON:
r = 1
else:
r = 0
return r
class ClientTracker(object):
def __init__(self, filename, cbClient, cbNet, cbMute, cbBlock, cbAdmin):
self._clientData = {}
self._net = {}
self._mute = {}
self._block = {}
self._admin = {}
self._acl = {}
self.cbClient = cbClient
self.cbNet = cbNet
self.cbMute = cbMute
self.cbBlock = cbBlock
self.cbAdmin = cbAdmin
self.filename = filename
self.load()
def load(self, filename=None):
s = shelve.open(filename or self.filename)
try:
self._mute = s['mute']
self._block = s['block']
self._admin = s['admin']
self._acl = s['acl']
except KeyError: pass
s.close()
def save(self, filename=None):
s = shelve.open(filename or self.filename)
s['mute'] = self._mute
s['block'] = self._block
s['admin'] = self._admin
s['acl'] = self._acl
s.close()
def isLoggedIn(self, clientId):
return clientId in self._clientData
def getClient(self, clientId):
return self._clientData[clientId].user
def getClientProtocol(self, clientId):
return self._clientData[clientId]
def getClientIndex(self, clientId):
net = self.getClient(clientId).NT
l = [x.ID for x in self.getClientList(net)]
return l.index(clientId)+1
def getNetworkList(self):
return sorted(set(self._net.keys())|set(self._acl.keys()))
def getClientList(self, network=[]):
if network:
allClients = self._net.get(network, [])
else:
allClients = self._clientData.keys()
return [self._clientData[x].user
for x in allClients]
def getMuteList(self, network=[]):
if network:
return [x for x in self._mute.values()
if self._mute[x.ID].NT in network]
else:
return [x for x in self._mute.values()]
def getBlockList(self):
return self._block.values()
def getAdminList(self):
return self._admin.values()
def isMute(self, clientId):
return clientId in self._mute
def isBlocked(self, clientId):
return clientId in self._block
def isAdmin(self, clientId):
return clientId in self._admin
def login(self, client, status=0):
clientId = client.user.ID
if clientId not in self._clientData:
if not self.aclTalkOk(client.user.NT, client.user.EA) and status < 1:
client.user.S = 1
else:
client.user.S = status
self._clientData[clientId] = client
net = client.user.NT
nc = self._net.get(net, [])
ni = None
for i, c in enumerate(nc):
if client_cmp(client.user, self._clientData[c].user) < 0:
ni = i
break
if ni is None:
ni = len(nc)
nc.insert(ni, clientId)
self._net[net] = nc
if clientId in self._mute:
client.user.M = 1
a = self._mute[clientId].AI
self._mute[clientId].update(**client.user.dict())
self._mute[clientId].AI = a
else:
client.user.M = 0
if not self.canLogin(client.user):
client.role = "BLOCK"
else:
self.aclUpdate(client.user)
if client.user.EA in self._admin:
client.role = "ADMIN"
self._admin[client.user.EA].update(client.user.dict())
self.save()
if len(nc) == 1:
self.cbNet(self.getNetworkList())
self.cbClient(net, self.getClientList(net))
def logout(self, client):
if client.user is None:
return
clientId = client.user.ID
log.msg("Client logout: %s" % (clientId,))
if clientId in self._clientData:
del self._clientData[clientId]
net = client.user.NT
self._net[net].remove(clientId)
if not self._net[net]:
del self._net[net]
self.cbNet(self.getNetworkList())
self.save()
self.cbClient(net, self.getClientList(net))
def setStatus(self, clientId, status):
user = self.getClient(clientId)
oldStatus = user.S
if not self.aclTalkOk(user.NT, user.EA) and status < 1:
status = 1
if oldStatus != str(status):
self._clientData[clientId].user.S = status
self.cbClient(user.NT, self.getClientList(user.NT))
def mute(self, admin, clientId):
if clientId not in self._mute:
self._mute[clientId] = self.getClient(clientId).copy(AI=admin.ON)
self._clientData[clientId].user.M = 1
self.save()
net = self.getClient(clientId).NT
self.cbClient(net, self.getClientList(net))
self.cbMute(self.getMuteList())
def unMute(self, clientId):
if clientId in self._mute:
del self._mute[clientId]
if clientId in self._clientData:
self._clientData[clientId].user.M = 0
net = self._clientData[clientId].user.NT
self.cbClient(net, self.getClientList(net))
self.save()
self.cbMute(self.getMuteList())
def block(self, admin, clientId):
if clientId not in self._block:
self._block[clientId] = self.getClient(clientId).copy(AI=admin.ON)
if clientId in self._clientData:
net = self._clientData[clientId].user.NT
self.save()
self.cbBlock(self.getBlockList())
def unBlock(self, clientId):
if clientId in self._block:
del self._block[clientId]
self.save()
self.cbBlock(self.getBlockList())
def admin(self, clientId):
if clientId not in self._admin:
self._admin[clientId] = self.getClient(clientId).copy()
self.save()
self.cbAdmin(self.getAdminList())
def unAdmin(self, clientId):
if clientId in self._admin:
del self._admin[clientId]
self.save()
self.cbAdmin(self.getAdminList())
def _getAcl(self, network):
return self._acl.get(network, (False, False, {}))
def _setAcl(self, network, ac, tx, l):
log.msg("Changing ACL for %s" % network)
if ac == tx == False and len(l) == 0:
log.msg("Default settings detected")
if network in self._acl:
log.msg("Deleting")
del self._acl[network]
else:
log.msg("Setting ACL for %s to %s" % (network, str((ac,tx,l))))
self._acl[network] = (ac, tx, l)
self.save()
def getAcl(self, network):
ac, tx, l = self._getAcl(network)
return l.values()
def getAclFlags(self, network):
ac, tx, l = self._getAcl(network)
return (ac, tx)
def setAclFlags(self, network, ac, tx):
oac, otx, l = self._getAcl(network)
self._setAcl(network, ac, tx, l)
def addAcl(self, network, email):
log.msg("Adding %s to ACL for %s" % (email, network))
ac, tx, l = self._getAcl(network)
if email not in l:
knownUsers = dict([(x.EA, x) for x in [y.user for y in self._clientData.values()] + self._mute.values() + self._block.values()])
user = knownUsers.get(email, FRNUser(EA=email)).copy(ID=email, AI=1)
l[email] = user
self._setAcl(network, ac, tx, l)
def delAcl(self, network, email):
log.msg("Removing %s from ACL for %s" % (email, network))
ac, tx, l = self._getAcl(network)
if email in l:
del l[email]
self._setAcl(network, ac, tx, l)
def setAclTx(self, network, email, tx):
oac, otx, l = self._getAcl(network)
if email in l:
if tx:
l[email].AI = 0
else:
l[email].AI = 1
self._setAcl(network, oac, otx, l)
def aclUpdate(self, user):
network = user.NT
email = user.EA
ac, tx, l = self._getAcl(network)
if email in l:
old = l[email]
new = user.copy(ID=email, AI=old.AI)
l[email] = new
self._setAcl(network, ac, tx, l)
def aclLoginOk(self, network, email):
ac, tx, l = self._getAcl(network)
if not ac:
return True
return email in l
def aclTalkOk(self, network, email):
ac, tx, l = self._getAcl(network)
if not tx:
return True
if email not in l:
return False
return l[email].AI == '0'
def canLogin(self, user):
if self.isBlocked(user.ID):
return False
return self.aclLoginOk(user.NT, user.EA)
def canTalk(self, clientId):
if self.isMute(clientId):
return False
u = self.getClient(clientId)
return self.aclTalkOk(u.NT, u.EA)
# vim: set et ai sw=4 ts=4 sts=4: