Fix manager reconnection bug in server. Add ClientTracker persistence.

This commit is contained in:
Maurizio Porrato 2010-08-21 20:32:56 +02:00
부모 5f0e7dd5fd
커밋 05894bb136
6개의 변경된 파일61개의 추가작업 그리고 55개의 파일을 삭제

1
.gitignore vendored
파일 보기

@ -5,3 +5,4 @@ servers.conf
recordings/*
sounds/*
*.sqlite3
*.shelve

파일 보기

@ -3,12 +3,13 @@
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
# See LICENSE.txt for copyright info
import shelve
from twisted.python import log
class ClientTracker(object):
def __init__(self, cbClient, cbNet, cbMute, cbBlock, cbAdmin):
def __init__(self, filename, cbClient, cbNet, cbMute, cbBlock, cbAdmin):
self._clientData = {}
self._net = {}
self._mute = {}
@ -19,6 +20,24 @@ class ClientTracker(object):
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']
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):
return self._clientData[clientId].user
@ -76,7 +95,7 @@ class ClientTracker(object):
if clientId in self._mute:
client.user.M = 1
a = self._mute[clientId].AI
self._mute[clientId].update(client.user.dict())
self._mute[clientId].update(**client.user.dict())
self._mute[clientId].AI = a
else:
client.user.M = 0
@ -85,6 +104,7 @@ class ClientTracker(object):
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))
@ -101,6 +121,7 @@ class ClientTracker(object):
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):
@ -114,6 +135,7 @@ class ClientTracker(object):
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())
@ -125,6 +147,7 @@ class ClientTracker(object):
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):
@ -132,21 +155,25 @@ class ClientTracker(object):
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())

파일 보기

@ -12,45 +12,28 @@ from frn.protocol.manager import FRNManagerClient, FRNManagerClientFactory
class CustomManagerClientFactory(FRNManagerClientFactory):
def __init__(self, user, onConnect, onDisconnect):
def __init__(self, user):
self.user = user
self.onConnect = onConnect
self.onDisconnect = onDisconnect
self.authResult = False
self.client = None
self.managerReady = Deferred()
self.client = None
self.authDone = False
self.deferred = Deferred()
def clientConnectionFailed(self, connector, reason):
self.authResult = False
self.client = None
self.managerReady = Deferred()
self.onDisconnect(self.protocol)
FRNManagerClientFactory.clientConnectionFailed(
self, connector, reason)
self.managerConnection.addCallback(self.connectionReady)
def managerConnected(self, connection):
def authReply(auth):
self.authResult = auth
self.authDone = (auth['al'] == '0')
if self.authDone:
self.deferred.callback(auth)
connection.sendServerLogin(self.user).addCallback(authReply)
def clientConnectionLost(self, connector, reason):
self.authResult = False
self.client = None
self.managerReady = Deferred()
self.onDisconnect(self.protocol)
FRNManagerClientFactory.clientConnectionLost(
self, connector, reason)
self.managerConnection.addCallback(self.connectionReady)
def managerDisconnected(self, connection):
pass
def connectionReady(self, client):
def authDone(res):
log.msg("Auth: %s" % str(res))
if res['al'] == '0':
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)
def buildProtocol(self, addr):
p = FRNManagerClientFactory.buildProtocol(self, addr)
self.client = p
return p
class RemoteManager(object):
@ -63,21 +46,13 @@ class RemoteManager(object):
self.port = port
self.factory = None
def onManagerConnect(self, protocol):
pass
def onManagerDisconnect(self, protocol):
pass
def doConnect(self):
self.reactor.connectTCP(self.server, self.port, self.factory)
self.factory.managerConnection.addCallback(self.factory.connectionReady)
return self.factory.managerReady
def serverLogin(self, user):
self.factory = CustomManagerClientFactory(
user, self.onManagerConnect, self.onManagerDisconnect)
return self.doConnect()
self.factory = CustomManagerClientFactory(user)
self.doConnect()
return self.factory.deferred
def serverLogout(self, user):
if self.factory.client is not None:

파일 보기

@ -20,9 +20,7 @@ class FRNManagerClient(LineOnlyReceiver):
def connectionMade(self):
log.msg("Connected to manager [%s]" % self.transport.getPeer().host)
self.notifications = []
if not self.factory.managerConnection.called: # FIXME: Why???
log.msg("Firing manager connection callback!")
self.factory.managerConnection.callback(self)
self.factory.managerConnected(self)
def connectionLost(self, reason):
log.msg("Manager disconnected")
@ -31,7 +29,7 @@ class FRNManagerClient(LineOnlyReceiver):
except: pass
for d in self.notifications:
d.errback(reason)
self.factory.managerConnection = Deferred()
self.factory.managerDisconnected(self)
def notifyFinish(self):
self.notifications.append(Deferred())
@ -102,8 +100,11 @@ class FRNManagerClientFactory(ReconnectingClientFactory):
protocol = FRNManagerClient
def startFactory(self):
self.managerConnection = Deferred()
def managerConnected(self, connection):
pass
def managerDisconnected(self, connection):
pass
class FRNManagerServer(LineOnlyReceiver):

파일 보기

@ -110,9 +110,9 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
def authReturned(result):
self.role, clientId = result
log.msg("AUTH result: %s %s" % (self.role, clientId))
self.user = FRNUser(**body)
self.user.ID = clientId
if self.role == 'OK':
self.user = FRNUser(**body)
self.user.ID = clientId
if self.user.EA == self.factory.serverAuth.OW:
self.role = 'OWNER'
elif self.factory.tracker.isAdmin(self.user.EA):
@ -272,12 +272,13 @@ class FRNServerFactory(ServerFactory):
protocol = FRNServer
def __init__(self, manager, serverAuth):
def __init__(self, trackerfile, manager, serverAuth):
self.manager = manager
self.serverAuth = serverAuth
self.talking = None
self.officialNets = []
self.tracker = ClientTracker(
trackerfile,
self.sendClientList, self.sendNetworkList,
self.sendMuteList, self.sendBlockList,
self.sendAdminList)

파일 보기

@ -43,6 +43,7 @@ if __name__ == '__main__':
password = acfg.get(account_name, 'password')
reactor.listenTCP(10024, FRNServerFactory(
pjoin(basedir, 'tracker.shelve'),
# DatabaseUserStore(
# ConnectionPool("sqlite3", "frn_users.sqlite3",
# check_same_thread=False)),