Fix manager reconnection bug in server. Add ClientTracker persistence.
This commit is contained in:
parent
5f0e7dd5fd
commit
05894bb136
|
@ -5,3 +5,4 @@ servers.conf
|
||||||
recordings/*
|
recordings/*
|
||||||
sounds/*
|
sounds/*
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
|
*.shelve
|
||||||
|
|
|
@ -3,12 +3,13 @@
|
||||||
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
||||||
# See LICENSE.txt for copyright info
|
# See LICENSE.txt for copyright info
|
||||||
|
|
||||||
|
import shelve
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
|
|
||||||
|
|
||||||
class ClientTracker(object):
|
class ClientTracker(object):
|
||||||
|
|
||||||
def __init__(self, cbClient, cbNet, cbMute, cbBlock, cbAdmin):
|
def __init__(self, filename, cbClient, cbNet, cbMute, cbBlock, cbAdmin):
|
||||||
self._clientData = {}
|
self._clientData = {}
|
||||||
self._net = {}
|
self._net = {}
|
||||||
self._mute = {}
|
self._mute = {}
|
||||||
|
@ -19,6 +20,24 @@ class ClientTracker(object):
|
||||||
self.cbMute = cbMute
|
self.cbMute = cbMute
|
||||||
self.cbBlock = cbBlock
|
self.cbBlock = cbBlock
|
||||||
self.cbAdmin = cbAdmin
|
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']
|
||||||
|
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.close()
|
||||||
|
|
||||||
def getClient(self, clientId):
|
def getClient(self, clientId):
|
||||||
return self._clientData[clientId].user
|
return self._clientData[clientId].user
|
||||||
|
@ -76,7 +95,7 @@ class ClientTracker(object):
|
||||||
if clientId in self._mute:
|
if clientId in self._mute:
|
||||||
client.user.M = 1
|
client.user.M = 1
|
||||||
a = self._mute[clientId].AI
|
a = self._mute[clientId].AI
|
||||||
self._mute[clientId].update(client.user.dict())
|
self._mute[clientId].update(**client.user.dict())
|
||||||
self._mute[clientId].AI = a
|
self._mute[clientId].AI = a
|
||||||
else:
|
else:
|
||||||
client.user.M = 0
|
client.user.M = 0
|
||||||
|
@ -85,6 +104,7 @@ class ClientTracker(object):
|
||||||
if client.user.EA in self._admin:
|
if client.user.EA in self._admin:
|
||||||
client.role = "ADMIN"
|
client.role = "ADMIN"
|
||||||
self._admin[client.user.EA].update(client.user.dict())
|
self._admin[client.user.EA].update(client.user.dict())
|
||||||
|
self.save()
|
||||||
if len(nc) == 1:
|
if len(nc) == 1:
|
||||||
self.cbNet(self.getNetworkList())
|
self.cbNet(self.getNetworkList())
|
||||||
self.cbClient(net, self.getClientList(net))
|
self.cbClient(net, self.getClientList(net))
|
||||||
|
@ -101,6 +121,7 @@ class ClientTracker(object):
|
||||||
if not self._net[net]:
|
if not self._net[net]:
|
||||||
del self._net[net]
|
del self._net[net]
|
||||||
self.cbNet(self.getNetworkList())
|
self.cbNet(self.getNetworkList())
|
||||||
|
self.save()
|
||||||
self.cbClient(net, self.getClientList(net))
|
self.cbClient(net, self.getClientList(net))
|
||||||
|
|
||||||
def setStatus(self, clientId, status):
|
def setStatus(self, clientId, status):
|
||||||
|
@ -114,6 +135,7 @@ class ClientTracker(object):
|
||||||
if clientId not in self._mute:
|
if clientId not in self._mute:
|
||||||
self._mute[clientId] = self.getClient(clientId).copy(AI=admin.ON)
|
self._mute[clientId] = self.getClient(clientId).copy(AI=admin.ON)
|
||||||
self._clientData[clientId].user.M = 1
|
self._clientData[clientId].user.M = 1
|
||||||
|
self.save()
|
||||||
net = self.getClient(clientId).NT
|
net = self.getClient(clientId).NT
|
||||||
self.cbClient(net, self.getClientList(net))
|
self.cbClient(net, self.getClientList(net))
|
||||||
self.cbMute(self.getMuteList())
|
self.cbMute(self.getMuteList())
|
||||||
|
@ -125,6 +147,7 @@ class ClientTracker(object):
|
||||||
self._clientData[clientId].user.M = 0
|
self._clientData[clientId].user.M = 0
|
||||||
net = self._clientData[clientId].user.NT
|
net = self._clientData[clientId].user.NT
|
||||||
self.cbClient(net, self.getClientList(net))
|
self.cbClient(net, self.getClientList(net))
|
||||||
|
self.save()
|
||||||
self.cbMute(self.getMuteList())
|
self.cbMute(self.getMuteList())
|
||||||
|
|
||||||
def block(self, admin, clientId):
|
def block(self, admin, clientId):
|
||||||
|
@ -132,21 +155,25 @@ class ClientTracker(object):
|
||||||
self._block[clientId] = self.getClient(clientId).copy(AI=admin.ON)
|
self._block[clientId] = self.getClient(clientId).copy(AI=admin.ON)
|
||||||
if clientId in self._clientData:
|
if clientId in self._clientData:
|
||||||
net = self._clientData[clientId].user.NT
|
net = self._clientData[clientId].user.NT
|
||||||
|
self.save()
|
||||||
self.cbBlock(self.getBlockList())
|
self.cbBlock(self.getBlockList())
|
||||||
|
|
||||||
def unBlock(self, clientId):
|
def unBlock(self, clientId):
|
||||||
if clientId in self._block:
|
if clientId in self._block:
|
||||||
del self._block[clientId]
|
del self._block[clientId]
|
||||||
|
self.save()
|
||||||
self.cbBlock(self.getBlockList())
|
self.cbBlock(self.getBlockList())
|
||||||
|
|
||||||
def admin(self, clientId):
|
def admin(self, clientId):
|
||||||
if clientId not in self._admin:
|
if clientId not in self._admin:
|
||||||
self._admin[clientId] = self.getClient(clientId).copy()
|
self._admin[clientId] = self.getClient(clientId).copy()
|
||||||
|
self.save()
|
||||||
self.cbAdmin(self.getAdminList())
|
self.cbAdmin(self.getAdminList())
|
||||||
|
|
||||||
def unAdmin(self, clientId):
|
def unAdmin(self, clientId):
|
||||||
if clientId in self._admin:
|
if clientId in self._admin:
|
||||||
del self._admin[clientId]
|
del self._admin[clientId]
|
||||||
|
self.save()
|
||||||
self.cbAdmin(self.getAdminList())
|
self.cbAdmin(self.getAdminList())
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,45 +12,28 @@ from frn.protocol.manager import FRNManagerClient, FRNManagerClientFactory
|
||||||
|
|
||||||
class CustomManagerClientFactory(FRNManagerClientFactory):
|
class CustomManagerClientFactory(FRNManagerClientFactory):
|
||||||
|
|
||||||
def __init__(self, user, onConnect, onDisconnect):
|
def __init__(self, user):
|
||||||
self.user = user
|
self.user = user
|
||||||
self.onConnect = onConnect
|
|
||||||
self.onDisconnect = onDisconnect
|
|
||||||
self.authResult = False
|
self.authResult = False
|
||||||
self.client = None
|
self.client = None
|
||||||
self.managerReady = Deferred()
|
self.authDone = False
|
||||||
self.client = None
|
self.deferred = Deferred()
|
||||||
|
|
||||||
def clientConnectionFailed(self, connector, reason):
|
def managerConnected(self, connection):
|
||||||
self.authResult = False
|
def authReply(auth):
|
||||||
self.client = None
|
self.authResult = auth
|
||||||
self.managerReady = Deferred()
|
self.authDone = (auth['al'] == '0')
|
||||||
self.onDisconnect(self.protocol)
|
if self.authDone:
|
||||||
FRNManagerClientFactory.clientConnectionFailed(
|
self.deferred.callback(auth)
|
||||||
self, connector, reason)
|
connection.sendServerLogin(self.user).addCallback(authReply)
|
||||||
self.managerConnection.addCallback(self.connectionReady)
|
|
||||||
|
|
||||||
def clientConnectionLost(self, connector, reason):
|
def managerDisconnected(self, connection):
|
||||||
self.authResult = False
|
pass
|
||||||
self.client = None
|
|
||||||
self.managerReady = Deferred()
|
|
||||||
self.onDisconnect(self.protocol)
|
|
||||||
FRNManagerClientFactory.clientConnectionLost(
|
|
||||||
self, connector, reason)
|
|
||||||
self.managerConnection.addCallback(self.connectionReady)
|
|
||||||
|
|
||||||
def connectionReady(self, client):
|
def buildProtocol(self, addr):
|
||||||
def authDone(res):
|
p = FRNManagerClientFactory.buildProtocol(self, addr)
|
||||||
log.msg("Auth: %s" % str(res))
|
self.client = p
|
||||||
if res['al'] == '0':
|
return p
|
||||||
self.authResult = res
|
|
||||||
self.onConnect(client)
|
|
||||||
self.managerReady.callback(res)
|
|
||||||
else:
|
|
||||||
client.transport.loseConnection()
|
|
||||||
return res
|
|
||||||
self.client = client
|
|
||||||
self.client.sendServerLogin(self.user).addCallback(authDone)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoteManager(object):
|
class RemoteManager(object):
|
||||||
|
@ -63,21 +46,13 @@ class RemoteManager(object):
|
||||||
self.port = port
|
self.port = port
|
||||||
self.factory = None
|
self.factory = None
|
||||||
|
|
||||||
def onManagerConnect(self, protocol):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def onManagerDisconnect(self, protocol):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def doConnect(self):
|
def doConnect(self):
|
||||||
self.reactor.connectTCP(self.server, self.port, self.factory)
|
self.reactor.connectTCP(self.server, self.port, self.factory)
|
||||||
self.factory.managerConnection.addCallback(self.factory.connectionReady)
|
|
||||||
return self.factory.managerReady
|
|
||||||
|
|
||||||
def serverLogin(self, user):
|
def serverLogin(self, user):
|
||||||
self.factory = CustomManagerClientFactory(
|
self.factory = CustomManagerClientFactory(user)
|
||||||
user, self.onManagerConnect, self.onManagerDisconnect)
|
self.doConnect()
|
||||||
return self.doConnect()
|
return self.factory.deferred
|
||||||
|
|
||||||
def serverLogout(self, user):
|
def serverLogout(self, user):
|
||||||
if self.factory.client is not None:
|
if self.factory.client is not None:
|
||||||
|
|
|
@ -20,9 +20,7 @@ class FRNManagerClient(LineOnlyReceiver):
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
log.msg("Connected to manager [%s]" % self.transport.getPeer().host)
|
log.msg("Connected to manager [%s]" % self.transport.getPeer().host)
|
||||||
self.notifications = []
|
self.notifications = []
|
||||||
if not self.factory.managerConnection.called: # FIXME: Why???
|
self.factory.managerConnected(self)
|
||||||
log.msg("Firing manager connection callback!")
|
|
||||||
self.factory.managerConnection.callback(self)
|
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
log.msg("Manager disconnected")
|
log.msg("Manager disconnected")
|
||||||
|
@ -31,7 +29,7 @@ class FRNManagerClient(LineOnlyReceiver):
|
||||||
except: pass
|
except: pass
|
||||||
for d in self.notifications:
|
for d in self.notifications:
|
||||||
d.errback(reason)
|
d.errback(reason)
|
||||||
self.factory.managerConnection = Deferred()
|
self.factory.managerDisconnected(self)
|
||||||
|
|
||||||
def notifyFinish(self):
|
def notifyFinish(self):
|
||||||
self.notifications.append(Deferred())
|
self.notifications.append(Deferred())
|
||||||
|
@ -102,8 +100,11 @@ class FRNManagerClientFactory(ReconnectingClientFactory):
|
||||||
|
|
||||||
protocol = FRNManagerClient
|
protocol = FRNManagerClient
|
||||||
|
|
||||||
def startFactory(self):
|
def managerConnected(self, connection):
|
||||||
self.managerConnection = Deferred()
|
pass
|
||||||
|
|
||||||
|
def managerDisconnected(self, connection):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FRNManagerServer(LineOnlyReceiver):
|
class FRNManagerServer(LineOnlyReceiver):
|
||||||
|
|
|
@ -110,9 +110,9 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
def authReturned(result):
|
def authReturned(result):
|
||||||
self.role, clientId = result
|
self.role, clientId = result
|
||||||
log.msg("AUTH result: %s %s" % (self.role, clientId))
|
log.msg("AUTH result: %s %s" % (self.role, clientId))
|
||||||
|
self.user = FRNUser(**body)
|
||||||
|
self.user.ID = clientId
|
||||||
if self.role == 'OK':
|
if self.role == 'OK':
|
||||||
self.user = FRNUser(**body)
|
|
||||||
self.user.ID = clientId
|
|
||||||
if self.user.EA == self.factory.serverAuth.OW:
|
if self.user.EA == self.factory.serverAuth.OW:
|
||||||
self.role = 'OWNER'
|
self.role = 'OWNER'
|
||||||
elif self.factory.tracker.isAdmin(self.user.EA):
|
elif self.factory.tracker.isAdmin(self.user.EA):
|
||||||
|
@ -272,12 +272,13 @@ class FRNServerFactory(ServerFactory):
|
||||||
|
|
||||||
protocol = FRNServer
|
protocol = FRNServer
|
||||||
|
|
||||||
def __init__(self, manager, serverAuth):
|
def __init__(self, trackerfile, manager, serverAuth):
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.serverAuth = serverAuth
|
self.serverAuth = serverAuth
|
||||||
self.talking = None
|
self.talking = None
|
||||||
self.officialNets = []
|
self.officialNets = []
|
||||||
self.tracker = ClientTracker(
|
self.tracker = ClientTracker(
|
||||||
|
trackerfile,
|
||||||
self.sendClientList, self.sendNetworkList,
|
self.sendClientList, self.sendNetworkList,
|
||||||
self.sendMuteList, self.sendBlockList,
|
self.sendMuteList, self.sendBlockList,
|
||||||
self.sendAdminList)
|
self.sendAdminList)
|
||||||
|
|
|
@ -43,6 +43,7 @@ if __name__ == '__main__':
|
||||||
password = acfg.get(account_name, 'password')
|
password = acfg.get(account_name, 'password')
|
||||||
|
|
||||||
reactor.listenTCP(10024, FRNServerFactory(
|
reactor.listenTCP(10024, FRNServerFactory(
|
||||||
|
pjoin(basedir, 'tracker.shelve'),
|
||||||
# DatabaseUserStore(
|
# DatabaseUserStore(
|
||||||
# ConnectionPool("sqlite3", "frn_users.sqlite3",
|
# ConnectionPool("sqlite3", "frn_users.sqlite3",
|
||||||
# check_same_thread=False)),
|
# check_same_thread=False)),
|
||||||
|
|
Loading…
Reference in New Issue