Add new features
- Add first (buggy and dirty) server implementation - Some bugfixes
This commit is contained in:
parent
d4a1a0da99
commit
5f0e7dd5fd
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[DEFAULT]
|
||||||
|
port=10024
|
||||||
|
backup_server=
|
||||||
|
backup_port=10024
|
||||||
|
|
||||||
|
[FRI]
|
||||||
|
server=master.freeradionetwork.it
|
||||||
|
|
||||||
|
[NL]
|
||||||
|
server=ham.freeradionetwork.nl
|
|
@ -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
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
||||||
|
# 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:
|
|
@ -3,7 +3,7 @@
|
||||||
# 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
|
||||||
|
|
||||||
from zope.interfaces import Interface
|
from zope.interface import Interface
|
||||||
|
|
||||||
|
|
||||||
class IManager(Interface):
|
class IManager(Interface):
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# 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
|
||||||
|
|
||||||
from zope.interfaces import implements
|
from zope.interface import implements
|
||||||
from frn.manager import IManager
|
from frn.manager import IManager
|
||||||
from frn.userstore.database import DatabaseUserStore
|
from frn.userstore.database import DatabaseUserStore
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# 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
|
||||||
|
|
||||||
from zope.interfaces import implements
|
from zope.interface import implements
|
||||||
from frn.manager import IManager
|
from frn.manager import IManager
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
|
@ -3,12 +3,56 @@
|
||||||
# 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
|
||||||
|
|
||||||
from zope.interfaces import implements
|
from zope.interface import implements
|
||||||
|
from twisted.internet.defer import Deferred, succeed
|
||||||
from frn.manager import IManager
|
from frn.manager import IManager
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
from frn.protocol.manager import FRNManagerClient, FRNManagerClientFactory
|
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):
|
class RemoteManager(object):
|
||||||
|
|
||||||
implements(IManager)
|
implements(IManager)
|
||||||
|
@ -17,34 +61,39 @@ class RemoteManager(object):
|
||||||
self.reactor = reactor
|
self.reactor = reactor
|
||||||
self.server = server
|
self.server = server
|
||||||
self.port = port
|
self.port = port
|
||||||
self.factory = FRNManagerClientFactory()
|
self.factory = None
|
||||||
self.factory.continueTrying = 0 # FIXME
|
|
||||||
|
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 serverLogin(self, user):
|
||||||
def connectionDone(conn):
|
self.factory = CustomManagerClientFactory(
|
||||||
log.msg("%s connected" % self.server)
|
user, self.onManagerConnect, self.onManagerDisconnect)
|
||||||
self.managerConnection = conn
|
return self.doConnect()
|
||||||
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))
|
|
||||||
|
|
||||||
def serverLogout(self, user):
|
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):
|
def clientLogin(self, user):
|
||||||
return self.managerConnection.sendClientLogin(user)
|
return self.factory.client.sendClientLogin(user)
|
||||||
|
|
||||||
def clientLogout(self, user):
|
def clientLogout(self, user):
|
||||||
return self.managerConnection.sendClientLogout(user)
|
return self.factory.client.sendClientLogout(user)
|
||||||
|
|
||||||
def getClientList(self):
|
def getClientList(self):
|
||||||
return self.managerConnection.getClientList()
|
return self.factory.client.getClientList()
|
||||||
|
|
||||||
def registerUser(self, user):
|
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:
|
# vim: set et ai sw=4 ts=4 sts=4:
|
||||||
|
|
|
@ -15,10 +15,13 @@ from frn.utility import *
|
||||||
|
|
||||||
class FRNManagerClient(LineOnlyReceiver):
|
class FRNManagerClient(LineOnlyReceiver):
|
||||||
|
|
||||||
|
PING_PERIOD = 3.0 # Seconds between ping requests
|
||||||
|
|
||||||
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???
|
if not self.factory.managerConnection.called: # FIXME: Why???
|
||||||
|
log.msg("Firing manager connection callback!")
|
||||||
self.factory.managerConnection.callback(self)
|
self.factory.managerConnection.callback(self)
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
|
@ -40,7 +43,7 @@ class FRNManagerClient(LineOnlyReceiver):
|
||||||
d.callback(result)
|
d.callback(result)
|
||||||
|
|
||||||
def lineReceived(self, line):
|
def lineReceived(self, line):
|
||||||
log.msg("notifications: %s" % str(self.notifications))
|
#log.msg("notifications: %s" % str(self.notifications))
|
||||||
if hasattr(self, 'serverlist'):
|
if hasattr(self, 'serverlist'):
|
||||||
# TODO
|
# TODO
|
||||||
pass
|
pass
|
||||||
|
@ -50,13 +53,16 @@ class FRNManagerClient(LineOnlyReceiver):
|
||||||
def sendServerLogin(self, user):
|
def sendServerLogin(self, user):
|
||||||
def loginDone(result):
|
def loginDone(result):
|
||||||
self.managerdata = parseSimpleXML(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:
|
if int(self.managerdata['mc']) > 2009004:
|
||||||
self.sendLine(responseToChallange(
|
self.sendLine(responseToChallange(
|
||||||
self.managerdata['kp']))
|
self.managerdata['kp']))
|
||||||
self.pingtimer = LoopingCall(self.sendPing)
|
if self.managerdata['al'] != '0':
|
||||||
self.pingtimer.start(3.0, False)
|
self.transport.loseConnection()
|
||||||
self.factory.resetDelay()
|
else:
|
||||||
|
self.pingtimer = LoopingCall(self.sendPing)
|
||||||
|
self.pingtimer.start(self.PING_PERIOD, False)
|
||||||
|
self.factory.resetDelay()
|
||||||
return self.managerdata
|
return self.managerdata
|
||||||
|
|
||||||
log.msg("Sending server login")
|
log.msg("Sending server login")
|
||||||
|
@ -98,7 +104,6 @@ class FRNManagerClientFactory(ReconnectingClientFactory):
|
||||||
|
|
||||||
def startFactory(self):
|
def startFactory(self):
|
||||||
self.managerConnection = Deferred()
|
self.managerConnection = Deferred()
|
||||||
ReconnectingClientFactory.startFactory(self)
|
|
||||||
|
|
||||||
|
|
||||||
class FRNManagerServer(LineOnlyReceiver):
|
class FRNManagerServer(LineOnlyReceiver):
|
||||||
|
|
|
@ -3,13 +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
|
||||||
|
|
||||||
from random import choice
|
|
||||||
from twisted.internet.defer import Deferred
|
from twisted.internet.defer import Deferred
|
||||||
from twisted.internet.protocol import ServerFactory
|
from twisted.internet.protocol import ServerFactory
|
||||||
from twisted.protocols.policies import TimeoutMixin
|
from twisted.protocols.policies import TimeoutMixin
|
||||||
from twisted.internet.task import LoopingCall
|
from twisted.internet.task import LoopingCall
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
from frn.user import FRNUser
|
from frn.user import FRNUser
|
||||||
|
from frn.clienttracker import ClientTracker
|
||||||
from frn.protocol import versions
|
from frn.protocol import versions
|
||||||
from frn.protocol.common import BufferingLineReceiver
|
from frn.protocol.common import BufferingLineReceiver
|
||||||
from frn.utility import *
|
from frn.utility import *
|
||||||
|
@ -34,22 +34,13 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
try:
|
try:
|
||||||
self.pingTimer.stop()
|
self.pingTimer.stop()
|
||||||
except AssertionError: pass
|
except AssertionError: pass
|
||||||
try:
|
if self.user is not None:
|
||||||
self.factory.clientList.remove(self)
|
if self.user.ID:
|
||||||
self.factory.manager.clientLogout(self.user)
|
log.msg("Logging out client %s" % self.user.ID)
|
||||||
self.factory.sendClientList([self.user.NT])
|
self.factory.manager.clientLogout(self.user)
|
||||||
except ValueError: pass
|
self.factory.tracker.logout(self)
|
||||||
BufferingLineReceiver.connectionLost(self, reason)
|
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):
|
def lineReceived(self, line):
|
||||||
self.resetTimeout()
|
self.resetTimeout()
|
||||||
sline = line.strip()
|
sline = line.strip()
|
||||||
|
@ -59,20 +50,13 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.waitingKey = False
|
self.waitingKey = False
|
||||||
if self.user.ID in self.factory.muteList:
|
self.factory.tracker.login(self)
|
||||||
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()
|
|
||||||
if self.role in ['OWNER', 'ADMIN']:
|
if self.role in ['OWNER', 'ADMIN']:
|
||||||
self.sendMuteList()
|
self.sendMuteList(self.factory.tracker.getMuteList())
|
||||||
self.sendBlockList()
|
self.sendBlockList(self.factory.tracker.getBlockList())
|
||||||
if self.role == 'OWNER':
|
if self.role == 'OWNER':
|
||||||
self.sendAccessFlags()
|
self.sendAccessFlags(None)
|
||||||
self.sendAccessList()
|
self.sendAccessList([])
|
||||||
self.pingCount += 1
|
self.pingCount += 1
|
||||||
self.pingTimer.start(0.5)
|
self.pingTimer.start(0.5)
|
||||||
self.setTimeout(10.0)
|
self.setTimeout(10.0)
|
||||||
|
@ -95,7 +79,7 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
handler(body)
|
handler(body)
|
||||||
else:
|
else:
|
||||||
self.unimplemented(command, body)
|
self.unimplemented(command, body)
|
||||||
self.transport.loseConnection() # ???
|
#self.transport.loseConnection() # ???
|
||||||
|
|
||||||
def expectedReceived(self, data):
|
def expectedReceived(self, data):
|
||||||
self.resetTimeout()
|
self.resetTimeout()
|
||||||
|
@ -105,15 +89,23 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
def unimplemented(self, command, body):
|
def unimplemented(self, command, body):
|
||||||
log.err("Unimplemented message: %s: %s" % (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 authenticate(self, user):
|
||||||
def loginReturned(userId):
|
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
|
return ("OK", userId) # FIXME: return OWNER or ADMIN eventually
|
||||||
else:
|
else:
|
||||||
return ("WRONG", "")
|
return (userId, "")
|
||||||
user.IP = self.clientAddress.host
|
user.IP = self.clientAddress.host
|
||||||
return self.factory.manager.clientLogin(user).addCallback(loginReturned)
|
return self.factory.manager.clientLogin(user).addCallback(loginReturned)
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
self.transport.loseConnection()
|
||||||
|
|
||||||
def decodeCT(self, body):
|
def decodeCT(self, body):
|
||||||
def authReturned(result):
|
def authReturned(result):
|
||||||
self.role, clientId = result
|
self.role, clientId = result
|
||||||
|
@ -121,12 +113,10 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
if self.role == 'OK':
|
if self.role == 'OK':
|
||||||
self.user = FRNUser(**body)
|
self.user = FRNUser(**body)
|
||||||
self.user.ID = clientId
|
self.user.ID = clientId
|
||||||
if self.role == 'OK':
|
|
||||||
if self.user.EA == self.factory.serverAuth.OW:
|
if self.user.EA == self.factory.serverAuth.OW:
|
||||||
self.role = 'OWNER'
|
self.role = 'OWNER'
|
||||||
elif self.user.EA in self.factory.adminList:
|
elif self.factory.tracker.isAdmin(self.user.EA):
|
||||||
self.role = 'ADMIN'
|
self.role = 'ADMIN'
|
||||||
# TODO: Blocklist
|
|
||||||
if versions.server > 2009004:
|
if versions.server > 2009004:
|
||||||
self.waitingKey = True
|
self.waitingKey = True
|
||||||
self.sendLine(str(versions.client))
|
self.sendLine(str(versions.client))
|
||||||
|
@ -146,7 +136,7 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
|
|
||||||
def decodeST(self, body):
|
def decodeST(self, body):
|
||||||
log.msg("Set status = %d" % int(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):
|
def decodeTM(self, body):
|
||||||
log.msg("TM: %s" % str(body))
|
log.msg("TM: %s" % str(body))
|
||||||
|
@ -154,30 +144,55 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
msgtype = 'A'
|
msgtype = 'A'
|
||||||
else:
|
else:
|
||||||
msgtype = 'P'
|
msgtype = 'P'
|
||||||
for c in self.factory.clientList:
|
for c in self.factory.tracker.getClientList(self.user.NT):
|
||||||
if msgtype == 'A' or c.user.ID == body['id']:
|
if msgtype == 'A' or c.ID == body['id']:
|
||||||
if c != self:
|
if c.ID != self.user.ID:
|
||||||
c.sendTextMessage(self.user.ID, body['ms'], msgtype)
|
client = self.factory.tracker.getClientProtocol(c.ID)
|
||||||
|
client.sendTextMessage(self.user.ID, body['ms'], msgtype)
|
||||||
|
|
||||||
def decodeTX(self, body):
|
def decodeTX(self, body):
|
||||||
if body == '0': # FIXME: Mute?
|
if body == '0':
|
||||||
log.msg("TX0")
|
if not self.factory.tracker.isMute(self.user.ID):
|
||||||
clientIdx = self.factory.clientList.index(self)+1
|
ih,il = divmod(self.getIndex(), 256)
|
||||||
ih,il = divmod(clientIdx, 256)
|
self.transport.write(chr(1)+chr(ih)+chr(il))
|
||||||
self.transport.write(chr(1)+chr(ih)+chr(il))
|
|
||||||
elif body == '1':
|
elif body == '1':
|
||||||
log.msg("TX1")
|
if self.pingTimer.running:
|
||||||
|
self.pingTimer.stop()
|
||||||
self.expectRawData(325)
|
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):
|
def audioFrameReceived(self, frame):
|
||||||
log.msg("audioFrameReceived")
|
#log.msg("audioFrameReceived")
|
||||||
clientIdx = self.factory.clientList.index(self)+1
|
if not self.factory.tracker.isMute(self.user.ID):
|
||||||
for c in self.factory.clientList:
|
clientIdx = self.getIndex()
|
||||||
if int(c.user.S) < 2 and c != self:
|
for c in self.factory.tracker.getClientList(self.user.NT):
|
||||||
log.msg("Sending to %s" % c.user.ON)
|
if int(c.S) < 2 and c.ID != self.user.ID:
|
||||||
c.sendAudioFrame(clientIdx, frame)
|
#log.msg("Sending to %s" % c.ON)
|
||||||
|
self.factory.tracker.getClientProtocol(c.ID).sendAudioFrame(clientIdx, frame)
|
||||||
|
|
||||||
def sendPing(self):
|
def sendPing(self):
|
||||||
if self.pingCount > 20:
|
if self.pingCount > 20:
|
||||||
|
@ -197,32 +212,42 @@ class FRNServer(BufferingLineReceiver, TimeoutMixin):
|
||||||
))
|
))
|
||||||
self.pingCount += 1
|
self.pingCount += 1
|
||||||
|
|
||||||
def sendNetworkList(self):
|
def sendNetworkList(self, networks):
|
||||||
log.msg("Send network list")
|
log.msg("Send network list")
|
||||||
self.transport.write(chr(5))
|
self.transport.write(chr(5))
|
||||||
nets = self.factory.getNetworkList()
|
self.sendLine(str(len(networks)))
|
||||||
self.sendLine(str(len(nets)))
|
for net in networks:
|
||||||
for net in nets:
|
|
||||||
self.sendLine(net)
|
self.sendLine(net)
|
||||||
self.pingCount += 1
|
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.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.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.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.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.transport.write(chr(10))
|
||||||
self.sendLine('2') # TODO
|
self.sendLine('2') # TODO
|
||||||
self.sendLine('o')
|
self.sendLine('o')
|
||||||
|
@ -251,11 +276,11 @@ class FRNServerFactory(ServerFactory):
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.serverAuth = serverAuth
|
self.serverAuth = serverAuth
|
||||||
self.talking = None
|
self.talking = None
|
||||||
self.clientList = []
|
|
||||||
self.adminList = []
|
|
||||||
self.muteList = []
|
|
||||||
self.blockList = []
|
|
||||||
self.officialNets = []
|
self.officialNets = []
|
||||||
|
self.tracker = ClientTracker(
|
||||||
|
self.sendClientList, self.sendNetworkList,
|
||||||
|
self.sendMuteList, self.sendBlockList,
|
||||||
|
self.sendAdminList)
|
||||||
|
|
||||||
def startFactory(self):
|
def startFactory(self):
|
||||||
ServerFactory.startFactory(self)
|
ServerFactory.startFactory(self)
|
||||||
|
@ -265,24 +290,29 @@ class FRNServerFactory(ServerFactory):
|
||||||
self.manager.serverLogout(self.serverAuth)
|
self.manager.serverLogout(self.serverAuth)
|
||||||
ServerFactory.stopFactory(self)
|
ServerFactory.stopFactory(self)
|
||||||
|
|
||||||
def getNetworkList(self):
|
def sendNetworkList(self, networks):
|
||||||
n = set([c.user.NT for c in self.clientList])
|
nets = self.officialNets+list(set(networks) - set(self.officialNets))
|
||||||
o = set(self.officialNets)
|
for c in self.tracker.getClientList():
|
||||||
return self.officialNets+list(n-o)
|
self.tracker.getClientProtocol(c.ID).sendNetworkList(nets)
|
||||||
|
|
||||||
def sendNetworkList(self):
|
def sendClientList(self, network, clients):
|
||||||
n = self.getNetworkList()
|
for c in clients:
|
||||||
for c in self.clientList:
|
self.tracker.getClientProtocol(c.ID).sendClientList(clients)
|
||||||
c.sendNetworkList(n)
|
|
||||||
|
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:
|
# vim: set et ai sw=4 ts=4 sts=4:
|
||||||
|
|
|
@ -25,7 +25,7 @@ class FRNUser(object):
|
||||||
self.set(attr, value)
|
self.set(attr, value)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return asXML(self)
|
return self.asXML()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "FRNUser(%s)" % \
|
return "FRNUser(%s)" % \
|
||||||
|
@ -52,6 +52,11 @@ class FRNUser(object):
|
||||||
for field, value in kw.items():
|
for field, value in kw.items():
|
||||||
self.set(field, value)
|
self.set(field, value)
|
||||||
|
|
||||||
|
def copy(self, **kw):
|
||||||
|
n = FRNUser(**self._fields)
|
||||||
|
n.update(**kw)
|
||||||
|
return n
|
||||||
|
|
||||||
def updateXML(self, xml):
|
def updateXML(self, xml):
|
||||||
self.update(dict(parseSimpleXML(xml)))
|
self.update(dict(parseSimpleXML(xml)))
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
def standardManagerFactory():
|
def standardManagerFactory():
|
||||||
log.msg("Building Manager")
|
log.msg("Building Manager")
|
||||||
return RemoteManager(reactor, '83.82.28.221')
|
return RemoteManager(reactor)
|
||||||
|
|
||||||
reactor.listenTCP(10025, FRNManagerServerFactory(
|
reactor.listenTCP(10025, FRNManagerServerFactory(
|
||||||
# DatabaseUserStore(
|
# DatabaseUserStore(
|
||||||
|
|
|
@ -46,8 +46,8 @@ if __name__ == '__main__':
|
||||||
# DatabaseUserStore(
|
# DatabaseUserStore(
|
||||||
# ConnectionPool("sqlite3", "frn_users.sqlite3",
|
# ConnectionPool("sqlite3", "frn_users.sqlite3",
|
||||||
# check_same_thread=False)),
|
# check_same_thread=False)),
|
||||||
# RemoteManager(reactor, '83.82.28.221'),
|
RemoteManager(reactor),
|
||||||
DummyManager(),
|
# DummyManager(),
|
||||||
FRNUser(
|
FRNUser(
|
||||||
SN=server,PT=port,
|
SN=server,PT=port,
|
||||||
BN=backup_server, BP=backup_port,
|
BN=backup_server, BP=backup_port,
|
||||||
|
|
Loading…
Reference in New Issue