You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
6.7 KiB

# -*- coding: utf-8 -*-
# Copyright 2010 Maurizio Porrato <>
# See LICENSE.txt for copyright info
from twisted.application.service import MultiService
from zope.interface import implements
from twisted.plugin import IPlugin
from twisted.application.service import IServiceMaker
from twisted.application import internet
from twisted.python import usage
from ConfigParser import ConfigParser
from frn.protocol.client import FRNClient, FRNClientFactory
from frn.user import FRNUser
from twisted.python import log
from os.path import curdir, join as pjoin
cType = {'PC Only': 'O', 'Crosslink': 'C', 'Parrot': 'P'}
cStatus = {'0': 'T', '1': 'R', '2': 'N'}
clients = []
talking = None
class FRNCrosslinkClient(FRNClient):
def connectionMade(self):
self.txOk = False
self.txReq = False
self.clientId = None
from twisted.internet import reactor
self.reactor = reactor
def getClientName(self, client_id):
if self.clientsById.has_key(client_id):
return self.clientsById[client_id]['on']
return client_id
def textMessageReceived(self, client, message, target):
global clients
if target == 'A':
msg = "[%s] %s" % (self.getClientName(client), message)
if client != self.clientId:
for _, _, _, factory in clients:
if factory != self.factory:
factory.connection.sendTextMessage('', msg)
if message.startswith('!'):
cmd = message[1:]
if cmd == "who":
for server, port, u, factory in clients:
cl = []
cl.append("<u>%s@%s:%d</u>" % (u.NT,server,port))
for c in factory.connection.clients:
ss = cStatus.get(c['s'], '?')
if c['m'] != '0':
ss = ss.lower()
cl.append(" %s%s %s " % (
cType.get(c['bc'], 'G'),
c['on'].replace('<', '&lt;'),
sm = [cl[i*15:(i+1)*15]
for i in range((len(cl)+14)/15)]
for m in sm:
reply = '<br>'.join(m)
self.sendTextMessage(client, reply)
def decodeTX(self, my_id):
log.msg("Got TX ack for %s" % self.user.ON)
self.txOk = True
def stopTransmission(self):
log.msg("Stopped TX on %s" % self.user.ON)
def goIdle(self):
global talking
self.txReq = False
self.txOk = False
talking = None
def audioFrameReceived(self, from_id, frames):
global clients, talking
if talking is None or talking == self:
talking = self
for _, _, _, factory in clients:
conn = factory.connection
if conn != self:
role = conn.serverdata.get('al', None)
if role in ['OK', 'ADMIN', 'OWNER']:
if conn.txOk:
conn.txReq = False
if not conn.txReq:
log.msg("Requesting TX for %s" % conn.user.ON)
conn.txReq = True
conn.busyTimer = self.reactor.callLater(
5.0, conn.goIdle)
def loginResponse(self, info):
log.msg("%s login: %s" % (self.user.ON, info['al']))
def clientsListUpdated(self, clients):
self.clients = clients
self.clientsById = dict([(i['id'], i) for i in clients])
if self.clientId is None:
for c in clients:
if c['on'] == self.user.ON and c['bc'] == self.user.BC:
self.clientId = c['id']
class FRNCrosslinkClientFactory(FRNClientFactory):
protocol = FRNCrosslinkClient
def buildProtocol(self, addr):
p = FRNClientFactory.buildProtocol(self, addr)
self.connection = p
return p
class Options(usage.Options):
optParameters = [
["confdir", "c", curdir, "Directory containing config files"]
def parseArgs(self, *serverdefs):
basedir = self['confdir']
acfg = ConfigParser()['/etc/grn/accounts.conf',
pjoin(basedir,'accounts.conf'), 'accounts.conf'])
scfg = ConfigParser()['/etc/grn/servers.conf',
pjoin(basedir,'servers.conf'), 'servers.conf'])
clients = []
for serverdef in serverdefs:
account_name, server_name, network_name = serverdef.split(':', 2)
sd = {}
sd['server'] = scfg.get(server_name, 'server')
sd['port'] = scfg.getint(server_name, 'port')
sd['backup_server'] = scfg.get(server_name, 'backup_server')
sd['backup_port'] = scfg.getint(server_name, 'backup_port')
sd['operator'] = acfg.get(account_name, 'operator')
sd['email'] = acfg.get(account_name, 'email')
sd['password'] = acfg.get(account_name, 'password')
sd['description'] = acfg.get(account_name, 'description')
sd['country'] = acfg.get(account_name, 'country')
sd['city'] = acfg.get(account_name, 'city')
sd['network'] = network_name
self['clients'] = clients
class FRNCrosslinkServiceMaker(object):
implements(IServiceMaker, IPlugin)
tapname = "frncrosslink"
description = "Freeradionetwork crosslink"
options = Options
def makeService(self, options):
s = MultiService()
global clients # FIXME: Get rid of this hack
for c in options['clients']:
user = FRNUser(
PW=c['password'], ON=c['operator'],
# BC=c['transmission'], DS=c['description'],
BC="Crosslink", DS=c['description'],
NN=c['country'], CT=c['city'], NT=c['network'])
factory = FRNCrosslinkClientFactory(user)
clients.append((c['server'], c['port'], user, factory))
internet.TCPClient(c['server'], c['port'], factory))
return s
serviceMaker = FRNCrosslinkServiceMaker()
# vim: set et ai sw=4 ts=4 sts=4: