From 5f0e7dd5fdb8395413d019379f949599df7265d2 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Sat, 21 Aug 2010 17:32:22 +0200 Subject: [PATCH] Add new features - Add first (buggy and dirty) server implementation - Some bugfixes --- docs/accounts.conf.sample | 18 ++++ docs/servers.conf.sample | 10 ++ docs/stations.conf.sample | 9 -- frn/clienttracker.py | 153 +++++++++++++++++++++++++++++ frn/manager/__init__.py | 2 +- frn/manager/database.py | 2 +- frn/manager/dummy.py | 2 +- frn/manager/remote.py | 83 ++++++++++++---- frn/protocol/manager.py | 17 ++-- frn/protocol/server.py | 202 ++++++++++++++++++++++---------------- frn/user.py | 7 +- manager.py | 2 +- server.py | 4 +- 13 files changed, 386 insertions(+), 125 deletions(-) create mode 100644 docs/accounts.conf.sample create mode 100644 docs/servers.conf.sample delete mode 100644 docs/stations.conf.sample create mode 100644 frn/clienttracker.py diff --git a/docs/accounts.conf.sample b/docs/accounts.conf.sample new file mode 100644 index 0000000..46fb57c --- /dev/null +++ b/docs/accounts.conf.sample @@ -0,0 +1,18 @@ +[DEFAULT] +; Settings in DEFAULT section are inherited by all other sections +city=City - LOCATOR +country=Country +transmission=PC Only +description= + +[testaccount] +operator=CALLSIGN, Operator name +email=testaccount@example.com +password=TOPSECRET + +[myaccount] +operator=CALLSIGN, Operator name +email=otheremail@example.com +transmission=Parrot +password=SUPERSECRET + diff --git a/docs/servers.conf.sample b/docs/servers.conf.sample new file mode 100644 index 0000000..5c5a2b2 --- /dev/null +++ b/docs/servers.conf.sample @@ -0,0 +1,10 @@ +[DEFAULT] +port=10024 +backup_server= +backup_port=10024 + +[FRI] +server=master.freeradionetwork.it + +[NL] +server=ham.freeradionetwork.nl diff --git a/docs/stations.conf.sample b/docs/stations.conf.sample deleted file mode 100644 index 2ac1d6e..0000000 --- a/docs/stations.conf.sample +++ /dev/null @@ -1,9 +0,0 @@ -[accountname] -operator=callsign, name -email=me@example.com -city=City - Locator -country=Your country -transmission=PC Only -description= -password=SECRET -network=Default network diff --git a/frn/clienttracker.py b/frn/clienttracker.py new file mode 100644 index 0000000..d348156 --- /dev/null +++ b/frn/clienttracker.py @@ -0,0 +1,153 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2010 Maurizio Porrato +# See LICENSE.txt for copyright info + +from twisted.python import log + + +class ClientTracker(object): + + def __init__(self, cbClient, cbNet, cbMute, cbBlock, cbAdmin): + self._clientData = {} + self._net = {} + self._mute = {} + self._block = {} + self._admin = {} + self.cbClient = cbClient + self.cbNet = cbNet + self.cbMute = cbMute + self.cbBlock = cbBlock + self.cbAdmin = cbAdmin + + 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 self._net.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, email): + return email in self._admin + + def login(self, client, status=0): + clientId = client.user.ID + if clientId not in self._clientData: + client.user.S = status + self._clientData[clientId] = client + net = client.user.NT + nc = self._net.get(net, []) + nc.append(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 clientId in self._block: + client.role = "BLOCK" + if client.user.EA in self._admin: + client.role = "ADMIN" + self._admin[client.user.EA].update(client.user.dict()) + 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.cbClient(net, self.getClientList(net)) + + def setStatus(self, clientId, status): + oldStatus = self._clientData[clientId].user.S + if oldStatus != str(status): + net = self._clientData[clientId].user.NT + self._clientData[clientId].user.S = status + self.cbClient(net, self.getClientList(net)) + + 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 + 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.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.cbBlock(self.getBlockList()) + + def unBlock(self, clientId): + if clientId in self._block: + del self._block[clientId] + self.cbBlock(self.getBlockList()) + + def admin(self, clientId): + if clientId not in self._admin: + self._admin[clientId] = self.getClient(clientId).copy() + self.cbAdmin(self.getAdminList()) + + def unAdmin(self, clientId): + if clientId in self._admin: + del self._admin[clientId] + self.cbAdmin(self.getAdminList()) + + +# vim: set et ai sw=4 ts=4 sts=4: diff --git a/frn/manager/__init__.py b/frn/manager/__init__.py index 29de6ab..006e692 100644 --- a/frn/manager/__init__.py +++ b/frn/manager/__init__.py @@ -3,7 +3,7 @@ # Copyright 2010 Maurizio Porrato # See LICENSE.txt for copyright info -from zope.interfaces import Interface +from zope.interface import Interface class IManager(Interface): diff --git a/frn/manager/database.py b/frn/manager/database.py index 74cf93c..c255b70 100644 --- a/frn/manager/database.py +++ b/frn/manager/database.py @@ -3,7 +3,7 @@ # Copyright 2010 Maurizio Porrato # See LICENSE.txt for copyright info -from zope.interfaces import implements +from zope.interface import implements from frn.manager import IManager from frn.userstore.database import DatabaseUserStore diff --git a/frn/manager/dummy.py b/frn/manager/dummy.py index 703b7ee..1c3cacb 100644 --- a/frn/manager/dummy.py +++ b/frn/manager/dummy.py @@ -3,7 +3,7 @@ # Copyright 2010 Maurizio Porrato # See LICENSE.txt for copyright info -from zope.interfaces import implements +from zope.interface import implements from frn.manager import IManager from twisted.internet import defer from random import randint diff --git a/frn/manager/remote.py b/frn/manager/remote.py index bde7eb0..5e28eb9 100644 --- a/frn/manager/remote.py +++ b/frn/manager/remote.py @@ -3,12 +3,56 @@ # Copyright 2010 Maurizio Porrato # See LICENSE.txt for copyright info -from zope.interfaces import implements +from zope.interface import implements +from twisted.internet.defer import Deferred, succeed from frn.manager import IManager from twisted.python import log from frn.protocol.manager import FRNManagerClient, FRNManagerClientFactory +class CustomManagerClientFactory(FRNManagerClientFactory): + + def __init__(self, user, onConnect, onDisconnect): + self.user = user + self.onConnect = onConnect + self.onDisconnect = onDisconnect + self.authResult = False + self.client = None + self.managerReady = Deferred() + self.client = None + + 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 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 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) + + class RemoteManager(object): implements(IManager) @@ -17,34 +61,39 @@ class RemoteManager(object): self.reactor = reactor self.server = server self.port = port - self.factory = FRNManagerClientFactory() - self.factory.continueTrying = 0 # FIXME + 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): - def connectionDone(conn): - log.msg("%s connected" % self.server) - self.managerConnection = conn - return conn - self.reactor.connectTCP(self.server, self.port, self.factory) - log.msg("RemoteManager started connecting %s" % self.server) - return self.factory.managerConnection.addCallback( - connectionDone).addCallback( - lambda _: self.managerConnection.sendServerLogin(user)) + self.factory = CustomManagerClientFactory( + user, self.onManagerConnect, self.onManagerDisconnect) + return self.doConnect() def serverLogout(self, user): - return self.managerConnection.sendServerLogout(user) + if self.factory.client is not None: + return self.factory.client.sendServerLogout(user) def clientLogin(self, user): - return self.managerConnection.sendClientLogin(user) + return self.factory.client.sendClientLogin(user) def clientLogout(self, user): - return self.managerConnection.sendClientLogout(user) + return self.factory.client.sendClientLogout(user) def getClientList(self): - return self.managerConnection.getClientList() + return self.factory.client.getClientList() def registerUser(self, user): - return self.managerConnection.registerUser(user) + return self.factory.client.registerUser(user) # vim: set et ai sw=4 ts=4 sts=4: diff --git a/frn/protocol/manager.py b/frn/protocol/manager.py index ca967d9..8fca71a 100644 --- a/frn/protocol/manager.py +++ b/frn/protocol/manager.py @@ -15,10 +15,13 @@ from frn.utility import * class FRNManagerClient(LineOnlyReceiver): + PING_PERIOD = 3.0 # Seconds between ping requests + 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) def connectionLost(self, reason): @@ -40,7 +43,7 @@ class FRNManagerClient(LineOnlyReceiver): d.callback(result) def lineReceived(self, line): - log.msg("notifications: %s" % str(self.notifications)) + #log.msg("notifications: %s" % str(self.notifications)) if hasattr(self, 'serverlist'): # TODO pass @@ -50,13 +53,16 @@ class FRNManagerClient(LineOnlyReceiver): def sendServerLogin(self, user): def loginDone(result): self.managerdata = parseSimpleXML(result) - log.msg("Server login succeeded: %s" % str(self.managerdata)) + log.msg("Server login results: %s" % str(self.managerdata)) if int(self.managerdata['mc']) > 2009004: self.sendLine(responseToChallange( self.managerdata['kp'])) - self.pingtimer = LoopingCall(self.sendPing) - self.pingtimer.start(3.0, False) - self.factory.resetDelay() + if self.managerdata['al'] != '0': + self.transport.loseConnection() + else: + self.pingtimer = LoopingCall(self.sendPing) + self.pingtimer.start(self.PING_PERIOD, False) + self.factory.resetDelay() return self.managerdata log.msg("Sending server login") @@ -98,7 +104,6 @@ class FRNManagerClientFactory(ReconnectingClientFactory): def startFactory(self): self.managerConnection = Deferred() - ReconnectingClientFactory.startFactory(self) class FRNManagerServer(LineOnlyReceiver): diff --git a/frn/protocol/server.py b/frn/protocol/server.py index e898862..d10f2ed 100644 --- a/frn/protocol/server.py +++ b/frn/protocol/server.py @@ -3,13 +3,13 @@ # Copyright 2010 Maurizio Porrato # See LICENSE.txt for copyright info -from random import choice from twisted.internet.defer import Deferred from twisted.internet.protocol import ServerFactory from twisted.protocols.policies import TimeoutMixin from twisted.internet.task import LoopingCall from twisted.python import log from frn.user import FRNUser +from frn.clienttracker import ClientTracker from frn.protocol import versions from frn.protocol.common import BufferingLineReceiver from frn.utility import * @@ -34,22 +34,13 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin): try: self.pingTimer.stop() except AssertionError: pass - try: - self.factory.clientList.remove(self) - self.factory.manager.clientLogout(self.user) - self.factory.sendClientList([self.user.NT]) - except ValueError: pass + if self.user is not None: + if self.user.ID: + log.msg("Logging out client %s" % self.user.ID) + self.factory.manager.clientLogout(self.user) + self.factory.tracker.logout(self) BufferingLineReceiver.connectionLost(self, reason) - def updateClient(self, **kw): - d = {} - for k, v in [(x.lower(), str(y)) for x,y in kw.items()]: - if self.user.get(k) != v: - d[k] = v - if len(d) > 0: - self.user.update(**d) - self.factory.sendClientList([self.user.NT]) - def lineReceived(self, line): self.resetTimeout() sline = line.strip() @@ -59,20 +50,13 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin): return else: self.waitingKey = False - if self.user.ID in self.factory.muteList: - self.user.M = 1 - else: - self.user.M = 0 - self.user.S = 0 - self.factory.clientList.append(self) - self.factory.sendClientList([self.user.NT]) # FIXME: older servers can't get here - self.sendNetworkList() + self.factory.tracker.login(self) if self.role in ['OWNER', 'ADMIN']: - self.sendMuteList() - self.sendBlockList() + self.sendMuteList(self.factory.tracker.getMuteList()) + self.sendBlockList(self.factory.tracker.getBlockList()) if self.role == 'OWNER': - self.sendAccessFlags() - self.sendAccessList() + self.sendAccessFlags(None) + self.sendAccessList([]) self.pingCount += 1 self.pingTimer.start(0.5) self.setTimeout(10.0) @@ -95,7 +79,7 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin): handler(body) else: self.unimplemented(command, body) - self.transport.loseConnection() # ??? + #self.transport.loseConnection() # ??? def expectedReceived(self, data): self.resetTimeout() @@ -105,15 +89,23 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin): def unimplemented(self, command, body): log.err("Unimplemented message: %s: %s" % (command, body)) + def getIndex(self): + return self.factory.tracker.getClientIndex(self.user.ID)+1 + def authenticate(self, user): def loginReturned(userId): - if userId != 'WRONG': + if userId not in ['WRONG', 'DUPL']: + if self.factory.tracker.isBlocked(userId): + return ("BLOCK", userId) return ("OK", userId) # FIXME: return OWNER or ADMIN eventually else: - return ("WRONG", "") + return (userId, "") user.IP = self.clientAddress.host return self.factory.manager.clientLogin(user).addCallback(loginReturned) + def disconnect(self): + self.transport.loseConnection() + def decodeCT(self, body): def authReturned(result): self.role, clientId = result @@ -121,12 +113,10 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin): if self.role == 'OK': self.user = FRNUser(**body) self.user.ID = clientId - if self.role == 'OK': if self.user.EA == self.factory.serverAuth.OW: self.role = 'OWNER' - elif self.user.EA in self.factory.adminList: + elif self.factory.tracker.isAdmin(self.user.EA): self.role = 'ADMIN' - # TODO: Blocklist if versions.server > 2009004: self.waitingKey = True self.sendLine(str(versions.client)) @@ -146,7 +136,7 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin): def decodeST(self, body): log.msg("Set status = %d" % int(body)) - self.updateClient(S=int(body)) + self.factory.tracker.setStatus(self.user.ID, int(body)) def decodeTM(self, body): log.msg("TM: %s" % str(body)) @@ -154,30 +144,55 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin): msgtype = 'A' else: msgtype = 'P' - for c in self.factory.clientList: - if msgtype == 'A' or c.user.ID == body['id']: - if c != self: - c.sendTextMessage(self.user.ID, body['ms'], msgtype) + for c in self.factory.tracker.getClientList(self.user.NT): + if msgtype == 'A' or c.ID == body['id']: + if c.ID != self.user.ID: + client = self.factory.tracker.getClientProtocol(c.ID) + client.sendTextMessage(self.user.ID, body['ms'], msgtype) def decodeTX(self, body): - if body == '0': # FIXME: Mute? - log.msg("TX0") - clientIdx = self.factory.clientList.index(self)+1 - ih,il = divmod(clientIdx, 256) - self.transport.write(chr(1)+chr(ih)+chr(il)) + if body == '0': + if not self.factory.tracker.isMute(self.user.ID): + ih,il = divmod(self.getIndex(), 256) + self.transport.write(chr(1)+chr(ih)+chr(il)) elif body == '1': - log.msg("TX1") + if self.pingTimer.running: + self.pingTimer.stop() self.expectRawData(325) - if self.pingTimer.running: - self.pingTimer.stop() + + def decodeMC(self, body): + if self.role in ["OWNER","ADMIN"]: + self.factory.tracker.mute(self.user, body['ip']) + + def decodeUM(self, body): + if self.role in ["OWNER","ADMIN"]: + self.factory.tracker.unMute(body['ip']) + + def decodeBC(self, body): + if self.role in ["OWNER","ADMIN"]: + self.factory.tracker.block(self.user, body['ip']) + self.factory.tracker.getClientProtocol(body['ip']).disconnect() + + def decodeUC(self, body): + if self.role in ["OWNER","ADMIN"]: + self.factory.tracker.unBlock(body['ip']) + + def decodeAA(self, body): + if self.role == "OWNER": + self.factory.tracker.admin(body['ip']) + + def decodeDA(self, body): + if self.role == "OWNER": + self.factory.tracker.unAdmin(body['ip']) def audioFrameReceived(self, frame): - log.msg("audioFrameReceived") - clientIdx = self.factory.clientList.index(self)+1 - for c in self.factory.clientList: - if int(c.user.S) < 2 and c != self: - log.msg("Sending to %s" % c.user.ON) - c.sendAudioFrame(clientIdx, frame) + #log.msg("audioFrameReceived") + if not self.factory.tracker.isMute(self.user.ID): + clientIdx = self.getIndex() + for c in self.factory.tracker.getClientList(self.user.NT): + if int(c.S) < 2 and c.ID != self.user.ID: + #log.msg("Sending to %s" % c.ON) + self.factory.tracker.getClientProtocol(c.ID).sendAudioFrame(clientIdx, frame) def sendPing(self): if self.pingCount > 20: @@ -197,32 +212,42 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin): )) self.pingCount += 1 - def sendNetworkList(self): + def sendNetworkList(self, networks): log.msg("Send network list") self.transport.write(chr(5)) - nets = self.factory.getNetworkList() - self.sendLine(str(len(nets))) - for net in nets: + self.sendLine(str(len(networks))) + for net in networks: self.sendLine(net) self.pingCount += 1 - def sendMuteList(self): + def sendMuteList(self, clients): + log.msg("Sending mute list to %s: %s" % (self.user.ON, str(clients))) self.transport.write(chr(9)) - self.sendLine('0') # TODO + self.sendLine(str(len(clients))) + for c in clients: + self.sendLine(c.asXML('AI','NN','CT','BC','ON','ID')) - def sendBlockList(self): + def sendBlockList(self, clients): + log.msg("Sending block list to %s: %s" % (self.user.ON, str(clients))) self.transport.write(chr(8)) - self.sendLine('0') # TODO + self.sendLine(str(len(clients))) + for c in clients: + self.sendLine(c.asXML('AI','NN','CT','BC','ON','ID')) - def sendAdminList(self): + def sendAdminList(self, clients): + log.msg("Sending admin list to %s: %s" % (self.user.ON, str(clients))) self.transport.write(chr(6)) - self.sendLine('0') # TODO + self.sendLine(str(len(clients))) + for c in clients: + self.sendLine(c.asXML('NN','CT','BC','ON','ID')) - def sendAccessList(self): + def sendAccessList(self, clients): self.transport.write(chr(7)) - self.sendLine('0') # TODO + self.sendLine(str(len(clients))) + for c in clients: # FIXME + self.sendLine(c.asXML('AI','NN','CT','BC','ON','ID')) - def sendAccessFlags(self): + def sendAccessFlags(self, flags): self.transport.write(chr(10)) self.sendLine('2') # TODO self.sendLine('o') @@ -251,11 +276,11 @@ class FRNServerFactory(ServerFactory): self.manager = manager self.serverAuth = serverAuth self.talking = None - self.clientList = [] - self.adminList = [] - self.muteList = [] - self.blockList = [] self.officialNets = [] + self.tracker = ClientTracker( + self.sendClientList, self.sendNetworkList, + self.sendMuteList, self.sendBlockList, + self.sendAdminList) def startFactory(self): ServerFactory.startFactory(self) @@ -265,24 +290,29 @@ class FRNServerFactory(ServerFactory): self.manager.serverLogout(self.serverAuth) ServerFactory.stopFactory(self) - def getNetworkList(self): - n = set([c.user.NT for c in self.clientList]) - o = set(self.officialNets) - return self.officialNets+list(n-o) + def sendNetworkList(self, networks): + nets = self.officialNets+list(set(networks) - set(self.officialNets)) + for c in self.tracker.getClientList(): + self.tracker.getClientProtocol(c.ID).sendNetworkList(nets) - def sendNetworkList(self): - n = self.getNetworkList() - for c in self.clientList: - c.sendNetworkList(n) + def sendClientList(self, network, clients): + for c in clients: + self.tracker.getClientProtocol(c.ID).sendClientList(clients) + + def sendMuteList(self, clients): + for c in self.tracker.getClientList(): + if self.tracker.isAdmin(c.ID) or c.EA == self.serverAuth.OW: + self.tracker.getClientProtocol(c.ID).sendMuteList(clients) + + def sendBlockList(self, clients): + for c in self.tracker.getClientList(): + if self.tracker.isAdmin(c.ID) or c.EA == self.serverAuth.OW: + self.tracker.getClientProtocol(c.ID).sendBlockList(clients) + + def sendAdminList(self, clients): + for c in self.tracker.getClientList(): + if c.EA == self.serverAuth.OW: + self.tracker.getClientProtocol(c.ID).sendAdminList(clients) - def sendClientList(self, networks=[]): - n = {} - for c in self.clientList: - l = n.get(c.user.NT, []) - l.append(c.user) - n[c.user.NT] = l - for c in self.clientList: - if (not networks) or (c.user.NT in networks): - c.sendClientList(n[c.user.NT]) # vim: set et ai sw=4 ts=4 sts=4: diff --git a/frn/user.py b/frn/user.py index c675be3..2726d3e 100644 --- a/frn/user.py +++ b/frn/user.py @@ -25,7 +25,7 @@ class FRNUser(object): self.set(attr, value) def __str__(self): - return asXML(self) + return self.asXML() def __repr__(self): return "FRNUser(%s)" % \ @@ -52,6 +52,11 @@ class FRNUser(object): for field, value in kw.items(): self.set(field, value) + def copy(self, **kw): + n = FRNUser(**self._fields) + n.update(**kw) + return n + def updateXML(self, xml): self.update(dict(parseSimpleXML(xml))) diff --git a/manager.py b/manager.py index d8155cb..a4dee64 100755 --- a/manager.py +++ b/manager.py @@ -19,7 +19,7 @@ if __name__ == '__main__': def standardManagerFactory(): log.msg("Building Manager") - return RemoteManager(reactor, '83.82.28.221') + return RemoteManager(reactor) reactor.listenTCP(10025, FRNManagerServerFactory( # DatabaseUserStore( diff --git a/server.py b/server.py index 8895a49..7f815be 100755 --- a/server.py +++ b/server.py @@ -46,8 +46,8 @@ if __name__ == '__main__': # DatabaseUserStore( # ConnectionPool("sqlite3", "frn_users.sqlite3", # check_same_thread=False)), - # RemoteManager(reactor, '83.82.28.221'), - DummyManager(), + RemoteManager(reactor), + # DummyManager(), FRNUser( SN=server,PT=port, BN=backup_server, BP=backup_port,