|
|
|
@ -1,7 +1,10 @@
|
|
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
|
|
from Queue import Queue |
|
|
|
|
from twisted.internet.protocol import ClientFactory |
|
|
|
|
from twisted.protocols.basic import LineReceiver |
|
|
|
|
from twisted.internet.task import LoopingCall |
|
|
|
|
from twisted.python import log |
|
|
|
|
from frn.utility import * |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -10,6 +13,7 @@ class FRNClient(LineReceiver):
|
|
|
|
|
client_version = 2010002 |
|
|
|
|
|
|
|
|
|
def connectionMade(self): |
|
|
|
|
self.txq = Queue() |
|
|
|
|
self.login() |
|
|
|
|
|
|
|
|
|
def ready(self): |
|
|
|
@ -34,7 +38,7 @@ class FRNClient(LineReceiver):
|
|
|
|
|
self.msgbuffer.append(line) |
|
|
|
|
self.phase += 1 |
|
|
|
|
if self.phase >= self.expected_lines: |
|
|
|
|
handler = getattr(self, 'on_'+self.status, self.on_unimplemented) |
|
|
|
|
handler = getattr(self, 'decode'+self.status, self.unimplemented) |
|
|
|
|
message = self.msgbuffer |
|
|
|
|
self.ready() |
|
|
|
|
handler(message) |
|
|
|
@ -54,7 +58,7 @@ class FRNClient(LineReceiver):
|
|
|
|
|
audio_data = self.msgbuffer |
|
|
|
|
source = ord(audio_data[0])*256+ord(audio_data[1]) |
|
|
|
|
self.ready() |
|
|
|
|
self.on_AUDIO(source, audio_data[2:]) |
|
|
|
|
self.decodeAUDIO(source, audio_data[2:]) |
|
|
|
|
if len(data) > needed: |
|
|
|
|
self.dataReceived(data[needed:]) |
|
|
|
|
|
|
|
|
@ -65,7 +69,7 @@ class FRNClient(LineReceiver):
|
|
|
|
|
self.phase = 1 |
|
|
|
|
else: |
|
|
|
|
self.serverdata = parseSimpleXML(line.strip()) |
|
|
|
|
print self.serverdata |
|
|
|
|
self.loginResponse(self.serverdata) |
|
|
|
|
if int(self.serverdata['sv']) > 2009004: |
|
|
|
|
self.sendLine(makeAuthKey(self.serverdata['kp'])) |
|
|
|
|
self.ready() |
|
|
|
@ -76,9 +80,9 @@ class FRNClient(LineReceiver):
|
|
|
|
|
if self.status == 'READY': |
|
|
|
|
packet_type = ord(data[0]) |
|
|
|
|
if packet_type == 0: # Keepalive |
|
|
|
|
self.sendLine('P') |
|
|
|
|
self.pong() |
|
|
|
|
elif packet_type == 1: # TX ack |
|
|
|
|
self.status == 'TX' |
|
|
|
|
self.status = 'TX' |
|
|
|
|
self.phase = 0 |
|
|
|
|
if len(data) > 1: |
|
|
|
|
self.dataReceived(data[1:]) |
|
|
|
@ -86,18 +90,21 @@ class FRNClient(LineReceiver):
|
|
|
|
|
self.startAudioMessage(data[1:]) |
|
|
|
|
elif packet_type == 3: # Client list |
|
|
|
|
self.startMultiLineMessage('CLIENTS', data[1:]) |
|
|
|
|
elif packet_type == 4: # SMS |
|
|
|
|
self.startMultiLineMessage('SMS', data[1:]) |
|
|
|
|
elif packet_type == 4: # Text |
|
|
|
|
self.startMultiLineMessage('TEXT', data[1:]) |
|
|
|
|
elif packet_type == 5: # Channel list |
|
|
|
|
self.startMultiLineMessage('CHANNELS', data[1:]) |
|
|
|
|
self.startMultiLineMessage('NETWORKS', data[1:]) |
|
|
|
|
else: |
|
|
|
|
print "Unknown packet type %d" % packet_type |
|
|
|
|
log.err("Unknown packet type %d" % packet_type) |
|
|
|
|
elif self.status == 'AUDIO': |
|
|
|
|
self.collectAudioMessage(data) |
|
|
|
|
elif self.status == 'TX': |
|
|
|
|
if self.phase == 0: |
|
|
|
|
self.phase = 1 |
|
|
|
|
self.on_TX(ord(data[0])*256+ord(data[1])) |
|
|
|
|
self.decodeTX(ord(data[0])*256+ord(data[1])) |
|
|
|
|
self.ready() |
|
|
|
|
if len(data) > 2: |
|
|
|
|
self.dataReceived(data[2:]) |
|
|
|
|
|
|
|
|
|
def login(self): |
|
|
|
|
d = self.factory.client_id |
|
|
|
@ -116,31 +123,82 @@ class FRNClient(LineReceiver):
|
|
|
|
|
self.status = 'AUTH' |
|
|
|
|
self.phase = 0 |
|
|
|
|
self.sendLine(ap) |
|
|
|
|
#self.request_rx() |
|
|
|
|
|
|
|
|
|
def set_status(self, status): |
|
|
|
|
def pong(self): |
|
|
|
|
self.sendLine('P') |
|
|
|
|
|
|
|
|
|
def setStatus(self, status): |
|
|
|
|
self.sendLine('ST:%s' % str(status)) |
|
|
|
|
|
|
|
|
|
def request_rx(self): |
|
|
|
|
def stopTransmission(self): |
|
|
|
|
self.sendLine('RX0') |
|
|
|
|
|
|
|
|
|
def request_tx(self): |
|
|
|
|
def startTransmission(self): |
|
|
|
|
self.sendLine('TX0') |
|
|
|
|
|
|
|
|
|
def send_audio(self, frame): |
|
|
|
|
def sendAudioFrame(self, frame): |
|
|
|
|
self.sendLine('TX1') |
|
|
|
|
self.transport.write(frame) |
|
|
|
|
|
|
|
|
|
def send_SMS(self, dest, text): |
|
|
|
|
def streamStep(self, count): |
|
|
|
|
if count > 1: |
|
|
|
|
log.msg("WARNING: lost %d ticks" % (count-1)) |
|
|
|
|
for i in range(count): |
|
|
|
|
self.sendAudioFrame(self.txq.get_nowait()) |
|
|
|
|
|
|
|
|
|
def stopStreaming(self): |
|
|
|
|
self.txtimer.stop() |
|
|
|
|
|
|
|
|
|
def _streamAck(self): |
|
|
|
|
self.txtimer = LoopingCall.withCount(self.streamStep) |
|
|
|
|
self.txtimer.start(0.20).addCallback( |
|
|
|
|
lambda _: self.stopTransmission()).addErrback( |
|
|
|
|
lambda _: self.stopTransmission()) |
|
|
|
|
|
|
|
|
|
def feedStreaming(self, frames): |
|
|
|
|
if type(frames) == list: |
|
|
|
|
for frame in frames: |
|
|
|
|
self.txq.put_nowait(frame) |
|
|
|
|
else: |
|
|
|
|
self.txq.put_nowait(frames) |
|
|
|
|
|
|
|
|
|
def startStreaming(self): |
|
|
|
|
self.startTransmission() |
|
|
|
|
|
|
|
|
|
def sendTextMessage(self, dest, text): |
|
|
|
|
self.sendLine('TM:'+formatSimpleXML(dict(ID=dest, MS=text))) |
|
|
|
|
|
|
|
|
|
def on_unimplemented(self, msg): |
|
|
|
|
print msg |
|
|
|
|
def unimplemented(self, msg): |
|
|
|
|
log.msg("Unimplemented: %s" % msg) |
|
|
|
|
|
|
|
|
|
def decodeAUDIO(self, from_id, frames): |
|
|
|
|
self.audioFrameReceived(from_id, frames) |
|
|
|
|
|
|
|
|
|
def decodeTX(self, my_id): |
|
|
|
|
self._streamAck() |
|
|
|
|
|
|
|
|
|
def decodeTEXT(self, msg): |
|
|
|
|
self.textMessageReceived(msg[0], msg[1], msg[2]) |
|
|
|
|
|
|
|
|
|
def decodeCLIENTS(self, msg): |
|
|
|
|
self.clientsListUpdated([parseSimpleXML(x) for x in msg]) |
|
|
|
|
|
|
|
|
|
def decodeNETWORKS(self, msg): |
|
|
|
|
self.networksListUpdated(msg) |
|
|
|
|
|
|
|
|
|
def loginResponse(self, info): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
def audioFrameReceived(self, from_id, frame): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
def textMessageReceived(self, client, message, target): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
def on_AUDIO(self, from_id, frames): |
|
|
|
|
def clientsListUpdated(self, clients): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
def on_TX(self, my_id): |
|
|
|
|
def networksListUpdated(self, networks): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -152,16 +210,16 @@ class FRNClientFactory(ClientFactory):
|
|
|
|
|
self.client_id = kw |
|
|
|
|
|
|
|
|
|
def startedConnecting(self, connector): |
|
|
|
|
print 'Started to connect.' |
|
|
|
|
log.msg('Started to connect') |
|
|
|
|
|
|
|
|
|
def buildProtocol(self, addr): |
|
|
|
|
print 'Connected.' |
|
|
|
|
log.msg('Connected') |
|
|
|
|
return ClientFactory.buildProtocol(self, addr) |
|
|
|
|
|
|
|
|
|
def clientConnectionLost(self, connector, reason): |
|
|
|
|
print 'Lost connection. Reason:', reason |
|
|
|
|
log.msg('Lost connection. Reason: %s' % reason) |
|
|
|
|
|
|
|
|
|
def clientConnectionFailed(self, connector, reason): |
|
|
|
|
print 'Connection failed. Reason:', reason |
|
|
|
|
log.err('Connection failed. Reason: %s' % reason) |
|
|
|
|
|
|
|
|
|
# vim: set et ai sw=4 ts=4 sts=4: |
|
|
|
|