Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/record.py
diff options
context:
space:
mode:
Diffstat (limited to 'record.py')
-rw-r--r--record.py906
1 files changed, 462 insertions, 444 deletions
diff --git a/record.py b/record.py
index 74df6e2..d5f5e19 100644
--- a/record.py
+++ b/record.py
@@ -27,17 +27,21 @@ import telepathy.client
import logging
import xml.dom.minidom
import time
+from xml.dom.minidom import parse
+
+import logging
+logger = logging.getLogger('record:record.py')
from sugar.activity import activity
from sugar.presence import presenceservice
from sugar.presence.tubeconn import TubeConnection
from sugar import util
+import port.json
from model import Model
from ui import UI
from recordtube import RecordTube
from glive import Glive
-from glivex import GliveX
from gplay import Gplay
from greplay import Greplay
from recorded import Recorded
@@ -49,472 +53,486 @@ import utils
class Record(activity.Activity):
- log = logging.getLogger('record-activity')
+ log = logging.getLogger('record-activity')
+
+ def __init__(self, handle):
+ activity.Activity.__init__(self, handle)
+ #flags for controlling the writing to the datastore
+ self.I_AM_CLOSING = False
+ self.I_AM_SAVED = False
+
+ self.props.enable_fullscreen_mode = False
+ Instance(self)
+ Constants(self)
+ self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+
+ #wait a moment so that our debug console capture mistakes
+ gobject.idle_add( self._initme, None )
+
+
+ def _initme( self, userdata=None ):
+ #totally tubular
+ self.meshTimeoutTime = 10000
+ self.recTube = None
+ self.connect( "shared", self._sharedCb )
+
+ #the main classes
+ self.m = Model(self)
+ self.glive = Glive(self)
+ self.gplay = Gplay(self)
+ self.ui = UI(self)
+
+ #CSCL
+ if self._shared_activity:
+ #have you joined or shared this activity yourself?
+ if self.get_shared():
+ self._meshJoinedCb( self )
+ else:
+ self.connect("joined", self._meshJoinedCb)
+
+ return False
+
+
+ def read_file(self, file):
+ try:
+ dom = parse(file)
+ except Exception, e:
+ logger.error('read_file: %s' % e)
+ return
+
+ serialize.fillMediaHash(dom, self.m.mediaHashs)
+
+ for i in dom.documentElement.getElementsByTagName('ui'):
+ for ui_el in i.childNodes:
+ self.ui.deserialize(port.json.loads(ui_el.data))
+
+
+ def write_file(self, file):
+ self.I_AM_SAVED = False
+
+ self.m.mediaHashs['ui'] = self.ui.serialize()
- def __init__(self, handle):
- activity.Activity.__init__(self, handle)
- #flags for controlling the writing to the datastore
- self.I_AM_CLOSING = False
- self.I_AM_SAVED = False
+ dom = serialize.saveMediaHash(self.m.mediaHashs)
- self.props.enable_fullscreen_mode = False
- Instance(self)
- Constants(self)
- self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ ui_data = port.json.dumps(self.ui.serialize())
+ ui_el = dom.createElement('ui')
+ ui_el.appendChild(dom.createTextNode(ui_data))
+ dom.documentElement.appendChild(ui_el)
- #wait a moment so that our debug console capture mistakes
- gobject.idle_add( self._initme, None )
+ xmlFile = open( file, "w" )
+ dom.writexml(xmlFile)
+ xmlFile.close()
+ allDone = True
+ for h in range (0, len(self.m.mediaHashs)-1):
+ mhash = self.m.mediaHashs[h]
+ for i in range (0, len(mhash)):
+ recd = mhash[i]
- def _initme( self, userdata=None ):
- #totally tubular
- self.meshTimeoutTime = 10000
- self.recTube = None
- self.connect( "shared", self._sharedCb )
+ if ( (not recd.savedMedia) or (not recd.savedXml) ):
+ allDone = False
- #the main classes
- self.m = Model(self)
- self.glive = Glive(self)
- self.glivex = GliveX(self)
- self.gplay = Gplay()
- self.ui = UI(self)
+ if (self.I_AM_CLOSING):
+ mediaObject = recd.datastoreOb
+ if (mediaObject != None):
+ recd.datastoreOb = None
+ mediaObject.destroy()
+ del mediaObject
- #CSCL
- if self._shared_activity:
- #have you joined or shared this activity yourself?
- if self.get_shared():
- self._meshJoinedCb( self )
- else:
- self.connect("joined", self._meshJoinedCb)
+ self.I_AM_SAVED = True
+ if (self.I_AM_SAVED and self.I_AM_CLOSING):
+ self.destroy()
- return False
+ def stopPipes(self):
+ self.ui.doMouseListener( False )
+ self.m.setUpdating( False )
- def read_file(self, file):
- serialize.fillMediaHash(file, self.m.mediaHashs)
+ if (self.ui.COUNTINGDOWN):
+ self.m.abandonRecording()
+ elif (self.m.RECORDING):
+ self.m.doShutter()
+ else:
+ self.glive.stop()
- def write_file(self, file):
- self.I_AM_SAVED = False
+ def restartPipes(self):
+ if (not self.ui.TRANSCODING):
+ self.ui.updateModeChange( )
+ self.ui.doMouseListener( True )
- dom = serialize.saveMediaHash(self.m.mediaHashs)
- xmlFile = open( file, "w" )
- dom.writexml(xmlFile)
- xmlFile.close()
- allDone = True
- for h in range (0, len(self.m.mediaHashs)):
- mhash = self.m.mediaHashs[h]
- for i in range (0, len(mhash)):
- recd = mhash[i]
+ def close( self ):
+ self.I_AM_CLOSING = True
- if ( (not recd.savedMedia) or (not recd.savedXml) ):
- allDone = False
+ self.m.UPDATING = False
+ if (self.ui != None):
+ self.ui.updateButtonSensitivities( )
+ self.ui.doMouseListener( False )
+ self.ui.hideAllWindows()
+ if (self.gplay != None):
+ self.gplay.stop( )
+ if (self.glive != None):
+ self.glive.stop( )
- if (self.I_AM_CLOSING):
- mediaObject = recd.datastoreOb
- if (mediaObject != None):
- recd.datastoreOb = None
- mediaObject.destroy()
- del mediaObject
+ #this calls write_file
+ activity.Activity.close( self )
- self.I_AM_SAVED = True
- if (self.I_AM_SAVED and self.I_AM_CLOSING):
- self.destroy()
+ def destroy( self ):
+ if self.I_AM_SAVED:
+ activity.Activity.destroy( self )
- def stopPipes(self):
- self.ui.doMouseListener( False )
- self.m.setUpdating( False )
- if (self.ui.COUNTINGDOWN):
- self.m.abandonRecording()
- elif (self.m.RECORDING):
- self.m.doShutter()
- else:
- self.glive.stop()
- self.glivex.stop()
+ def _sharedCb( self, activity ):
+ self._setup()
+ id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( Constants.SERVICE, {})
- def restartPipes(self):
- if (not self.ui.TRANSCODING):
- self.ui.updateModeChange( )
- self.ui.doMouseListener( True )
+ def _meshJoinedCb( self, activity ):
+ if not self._shared_activity:
+ return
+
+ self._setup()
- def close( self ):
- self.I_AM_CLOSING = True
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb)
- self.m.UPDATING = False
- if (self.ui != None):
- self.ui.updateButtonSensitivities( )
- self.ui.doMouseListener( False )
- self.ui.hideAllWindows()
- if (self.gplay != None):
- self.gplay.stop( )
- if (self.glive != None):
- self.glive.stop( )
- if (self.glivex != None):
- self.glivex.stop( )
- #this calls write_file
- activity.Activity.close( self )
-
-
- def destroy( self ):
- if self.I_AM_SAVED:
- activity.Activity.destroy( self )
-
-
- def _sharedCb( self, activity ):
- self._setup()
-
- id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( Constants.SERVICE, {})
-
-
- def _meshJoinedCb( self, activity ):
- if not self._shared_activity:
- return
-
- self._setup()
-
- self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb)
-
-
- def _list_tubes_reply_cb(self, tubes):
- for tube_info in tubes:
- self._newTubeCb(*tube_info)
-
-
- def _list_tubes_error_cb(self, e):
- self.__class__.log.error('ListTubes() failed: %s', e)
-
-
- def _setup(self):
- #sets up the tubes...
- if self._shared_activity is None:
- self.__class__.log.error('_setup: Failed to share or join activity')
- return
-
- pservice = presenceservice.get_instance()
- try:
- name, path = pservice.get_preferred_connection()
- self.conn = telepathy.client.Connection(name, path)
- except:
- self.__class__.log.error('_setup: Failed to get_preferred_connection')
-
- # Work out what our room is called and whether we have Tubes already
- bus_name, conn_path, channel_paths = self._shared_activity.get_channels()
- room = None
- tubes_chan = None
- text_chan = None
- for channel_path in channel_paths:
- channel = telepathy.client.Channel(bus_name, channel_path)
- htype, handle = channel.GetHandle()
- if htype == telepathy.HANDLE_TYPE_ROOM:
- self.__class__.log.debug('Found our room: it has handle#%d "%s"', handle, self.conn.InspectHandles(htype, [handle])[0])
- room = handle
- ctype = channel.GetChannelType()
- if ctype == telepathy.CHANNEL_TYPE_TUBES:
- self.__class__.log.debug('Found our Tubes channel at %s', channel_path)
- tubes_chan = channel
- elif ctype == telepathy.CHANNEL_TYPE_TEXT:
- self.__class__.log.debug('Found our Text channel at %s', channel_path)
- text_chan = channel
-
- if room is None:
- self.__class__.log.error("Presence service didn't create a room")
- return
- if text_chan is None:
- self.__class__.log.error("Presence service didn't create a text channel")
- return
-
- # Make sure we have a Tubes channel - PS doesn't yet provide one
- if tubes_chan is None:
- self.__class__.log.debug("Didn't find our Tubes channel, requesting one...")
- tubes_chan = self.conn.request_channel(telepathy.CHANNEL_TYPE_TUBES, telepathy.HANDLE_TYPE_ROOM, room, True)
-
- self.tubes_chan = tubes_chan
- self.text_chan = text_chan
-
- tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube', self._newTubeCb)
-
-
- def _newTubeCb(self, id, initiator, type, service, params, state):
- self.__class__.log.debug('New tube: ID=%d initator=%d type=%d service=%s params=%r state=%d', id, initiator, type, service, params, state)
- if (type == telepathy.TUBE_TYPE_DBUS and service == Constants.SERVICE):
- if state == telepathy.TUBE_STATE_LOCAL_PENDING:
- self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)
- tube_conn = TubeConnection(self.conn, self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
- self.recTube = RecordTube(tube_conn)
- self.recTube.connect("new-recd", self._newRecdCb)
- self.recTube.connect("recd-request", self._recdRequestCb)
- self.recTube.connect("recd-bits-arrived", self._recdBitsArrivedCb)
- self.recTube.connect("recd-unavailable", self._recdUnavailableCb)
-
-
- def _newRecdCb( self, objectThatSentTheSignal, recorder, xmlString ):
- self.__class__.log.debug('_newRecdCb')
- dom = None
- try:
- dom = xml.dom.minidom.parseString(xmlString)
- except:
- self.__class__.log.error('Unable to parse mesh xml')
- if (dom == None):
- return
-
- recd = Recorded()
- recd = serialize.fillRecdFromNode(recd, dom.documentElement)
- if (recd != None):
- self.__class__.log.debug('_newRecdCb: adding new recd thumb')
- recd.buddy = True
- recd.downloadedFromBuddy = False
- self.m.addMeshRecd( recd )
- else:
- self.__class__.log.debug('_newRecdCb: recd is None. Unable to parse XML')
-
-
- def requestMeshDownload( self, recd ):
- if (recd.meshDownloading):
- return True
-
- self.m.updateXoFullStatus()
- if (self.m.FULL):
- return True
-
- #this call will get the bits or request the bits if they're not available
- if (recd.buddy and (not recd.downloadedFromBuddy)):
- self.meshInitRoundRobin(recd)
- return True
-
- else:
- return False
-
-
- def meshInitRoundRobin( self, recd ):
- if (recd.meshDownloading):
- self.__class__.log.debug("meshInitRoundRobin: we are in midst of downloading this file...")
- return
-
- if (self.recTube == None):
- gobject.idle_add(self.ui.updateMeshProgress, False, recd)
- return
-
- #start with who took the photo
- recd.triedMeshBuddies = []
- recd.triedMeshBuddies.append(Instance.keyHashPrintable)
- self.meshReqRecFromBuddy( recd, recd.recorderHash, recd.recorderName )
-
-
- def meshNextRoundRobinBuddy( self, recd ):
- self.__class__.log.debug('meshNextRoundRobinBuddy')
- if (recd.meshReqCallbackId != 0):
- gobject.source_remove(recd.meshReqCallbackId)
- recd.meshReqCallbackId = 0
-
- #delete any stub of a partially downloaded file
- filepath = recd.getMediaFilepath()
- if (filepath != None):
- if (os.path.exists(filepath)):
- os.remove( filepath )
-
- goodBudObj = None
- buds = self._shared_activity.get_joined_buddies()
- for i in range (0, len(buds)):
- nextBudObj = buds[i]
- nextBud = util._sha_data(nextBudObj.props.key)
- nextBud = util.printable_hash(nextBud)
- if (recd.triedMeshBuddies.count(nextBud) > 0):
- self.__class__.log.debug('mnrrb: weve already tried bud ' + str(nextBudObj.props.nick))
- else:
- self.__class__.log.debug('mnrrb: ask next buddy: ' + str(nextBudObj.props.nick))
- goodBudObj = nextBudObj
- break
-
- if (goodBudObj != None):
- goodNick = goodBudObj.props.nick
- goodBud = util._sha_data(goodBudObj.props.key)
- goodBud = util.printable_hash(goodBud)
- self.meshReqRecFromBuddy(recd, goodBud, goodNick)
- else:
- self.__class__.log.debug('weve tried all buddies here, and no one has this recd')
- recd.meshDownloading = False
- recd.triedMeshBuddies = []
- recd.triedMeshBuddies.append(Instance.keyHashPrintable)
- self.ui.updateMeshProgress(False, recd)
-
-
- def meshReqRecFromBuddy( self, recd, fromWho, fromWhosNick ):
- recd.triedMeshBuddies.append( fromWho )
- recd.meshDownloadingFrom = fromWho
- recd.meshDownloadingFromNick = fromWhosNick
- recd.meshDownloadingProgress = False
- recd.meshDownloading = True
- recd.meshDownlodingPercent = 0.0
- self.ui.updateMeshProgress(True, recd)
- recd.meshReqCallbackId = gobject.timeout_add(self.meshTimeoutTime, self._meshCheckOnRecdRequest, recd)
- self.recTube.requestRecdBits( Instance.keyHashPrintable, fromWho, recd.mediaMd5 )
-
-
- def _meshCheckOnRecdRequest( self, recdRequesting ):
- #todo: add category for "not active activity, so go ahead and delete"
-
- if (recdRequesting.downloadedFromBuddy):
- self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.downloadedFromBuddy')
- if (recdRequesting.meshReqCallbackId != 0):
- gobject.source_remove(recdRequesting.meshReqCallbackId)
- recdRequesting.meshReqCallbackId = 0
- return False
- if (recdRequesting.deleted):
- self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.deleted')
- if (recdRequesting.meshReqCallbackId != 0):
- gobject.source_remove(recdRequesting.meshReqCallbackId)
- recdRequesting.meshReqCallbackId = 0
- return False
- if (recdRequesting.meshDownloadingProgress):
- self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.meshDownloadingProgress')
- #we've received some bits since last we checked, so keep waiting... they'll all get here eventually!
- recdRequesting.meshDownloadingProgress = False
- return True
- else:
- self.__class__.log.debug('_meshCheckOnRecdRequest: ! recdRequesting.meshDownloadingProgress')
- #that buddy we asked info from isn't responding; next buddy!
- #self.meshNextRoundRobinBuddy( recdRequesting )
- gobject.idle_add(self.meshNextRoundRobinBuddy, recdRequesting)
- return False
-
-
- def _recdRequestCb( self, objectThatSentTheSignal, whoWantsIt, md5sumOfIt ):
- #if we are here, it is because someone has been told we have what they want.
- #we need to send them that thing, whatever that thing is
- recd = self.m.getRecdByMd5( md5sumOfIt )
- if (recd == None):
- self.__class__.log.debug('_recdRequestCb: we dont have the recd they asked for')
- self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
- return
- if (recd.deleted):
- self.__class__.log.debug('_recdRequestCb: we have the recd, but it has been deleted, so we wont share')
- self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
- return
- if (recd.buddy and not recd.downloadedFromBuddy):
- self.__class__.log.debug('_recdRequestCb: we have an incomplete recd, so we wont share')
- self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
- return
-
- recd.meshUploading = True
- filepath = recd.getMediaFilepath()
-
- if (recd.type == Constants.TYPE_AUDIO):
- audioImgFilepath = recd.getAudioImageFilepath()
-
- destPath = os.path.join(Instance.instancePath, "audioBundle")
- destPath = utils.getUniqueFilepath(destPath, 0)
- cmd = "cat " + str(filepath) + " " + str(audioImgFilepath) + " > " + str(destPath)
- self.__class__.log.debug(cmd)
- os.system(cmd)
- filepath = destPath
-
- sent = self.recTube.broadcastRecd(recd.mediaMd5, filepath, whoWantsIt)
- recd.meshUploading = False
- #if you were deleted while uploading, now throw away those bits now
- if (recd.deleted):
- recd.doDeleteRecorded(recd)
-
-
- def _recdBitsArrivedCb( self, objectThatSentTheSignal, md5sumOfIt, part, numparts, bytes, fromWho ):
- #self.__class__.log.debug('_recdBitsArrivedCb: ' + str(part) + "/" + str(numparts))
- recd = self.m.getRecdByMd5( md5sumOfIt )
- if (recd == None):
- self.__class__.log.debug('_recdBitsArrivedCb: thx 4 yr bits, but we dont even have that photo')
- return
- if (recd.deleted):
- self.__class__.log.debug('_recdBitsArrivedCb: thx 4 yr bits, but we deleted that photo')
- return
- if (recd.downloadedFromBuddy):
- self.__class__.log.debug('_recdBitsArrivedCb: weve already downloadedFromBuddy')
- return
- if (not recd.buddy):
- self.__class__.log.debug('_recdBitsArrivedCb: uh, we took this photo, so dont need your bits')
- return
- if (recd.meshDownloadingFrom != fromWho):
- self.__class__.log.debug('_recdBitsArrivedCb: wrong bits ' + str(fromWho) + ", exp:" + str(recd.meshDownloadingFrom))
- return
-
- #update that we've heard back about this, reset the timeout
- gobject.source_remove(recd.meshReqCallbackId)
- recd.meshReqCallbackId = gobject.timeout_add(self.meshTimeoutTime, self._meshCheckOnRecdRequest, recd)
-
- #update the progress bar
- recd.meshDownlodingPercent = (part+0.0)/(numparts+0.0)
- recd.meshDownloadingProgress = True
- self.ui.updateMeshProgress(True, recd)
- f = open(recd.getMediaFilepath(), 'a+')
- f.write(bytes)
- f.close()
-
- if part == numparts:
- self.__class__.log.debug('Finished receiving %s' % recd.title)
- gobject.source_remove( recd.meshReqCallbackId )
- recd.meshReqCallbackId = 0
- recd.meshDownloading = False
- recd.meshDownlodingPercent = 1.0
- recd.downloadedFromBuddy = True
- if (recd.type == Constants.TYPE_AUDIO):
- filepath = recd.getMediaFilepath()
- bundlePath = os.path.join(Instance.instancePath, "audioBundle")
- bundlePath = utils.getUniqueFilepath(bundlePath, 0)
-
- cmd = "split -a 1 -b " + str(recd.mediaBytes) + " " + str(filepath) + " " + str(bundlePath)
- self.__class__.log.debug( cmd )
- os.system( cmd )
-
- bundleName = os.path.basename(bundlePath)
- mediaFilename = str(bundleName) + "a"
- mediaFilepath = os.path.join(Instance.instancePath, mediaFilename)
- mediaFilepathExt = os.path.join(Instance.instancePath, mediaFilename+".ogg")
- os.rename(mediaFilepath, mediaFilepathExt)
- audioImageFilename = str(bundleName) + "b"
- audioImageFilepath = os.path.join(Instance.instancePath, audioImageFilename)
- audioImageFilepathExt = os.path.join(Instance.instancePath, audioImageFilename+".png")
- os.rename(audioImageFilepath, audioImageFilepathExt)
-
- recd.mediaFilename = os.path.basename(mediaFilepathExt)
- recd.audioImageFilename = os.path.basename(audioImageFilepathExt)
-
- self.ui.showMeshRecd( recd )
- elif part > numparts:
- self.__class__.log.error('More parts than required have arrived')
-
-
- def _getAlbumArtCb( self, objectThatSentTheSignal, pixbuf, recd ):
-
- if (pixbuf != None):
- imagePath = os.path.join(Instance.instancePath, "audioPicture.png")
- imagePath = utils.getUniqueFilepath( imagePath, 0 )
- pixbuf.save( imagePath, "png", {} )
- recd.audioImageFilename = os.path.basename(imagePath)
-
- self.ui.showMeshRecd( recd )
- return False
-
-
- def _recdUnavailableCb( self, objectThatSentTheSignal, md5sumOfIt, whoDoesntHaveIt ):
- self.__class__.log.debug('_recdUnavailableCb: sux, we want to see that photo')
- recd = self.m.getRecdByMd5( md5sumOfIt )
- if (recd == None):
- self.__class__.log.debug('_recdUnavailableCb: actually, we dont even know about that one..')
- return
- if (recd.deleted):
- self.__class__.log.debug('_recdUnavailableCb: actually, since we asked, we deleted.')
- return
- if (not recd.buddy):
- self.__class__.log.debug('_recdUnavailableCb: uh, odd, we took that photo and have it already.')
- return
- if (recd.downloadedFromBuddy):
- self.__class__.log.debug('_recdUnavailableCb: we already downloaded it... you might have been slow responding.')
- return
- if (recd.meshDownloadingFrom != whoDoesntHaveIt):
- self.__class__.log.debug('_recdUnavailableCb: we arent asking you for a copy now. slow response, pbly.')
- return
-
- #self.meshNextRoundRobinBuddy( recd )
+ def _list_tubes_reply_cb(self, tubes):
+ for tube_info in tubes:
+ self._newTubeCb(*tube_info)
+
+
+ def _list_tubes_error_cb(self, e):
+ self.__class__.log.error('ListTubes() failed: %s', e)
+
+
+ def _setup(self):
+ #sets up the tubes...
+ if self._shared_activity is None:
+ self.__class__.log.error('_setup: Failed to share or join activity')
+ return
+
+ pservice = presenceservice.get_instance()
+ try:
+ name, path = pservice.get_preferred_connection()
+ self.conn = telepathy.client.Connection(name, path)
+ except:
+ self.__class__.log.error('_setup: Failed to get_preferred_connection')
+
+ # Work out what our room is called and whether we have Tubes already
+ bus_name, conn_path, channel_paths = self._shared_activity.get_channels()
+ room = None
+ tubes_chan = None
+ text_chan = None
+ for channel_path in channel_paths:
+ channel = telepathy.client.Channel(bus_name, channel_path)
+ htype, handle = channel.GetHandle()
+ if htype == telepathy.HANDLE_TYPE_ROOM:
+ self.__class__.log.debug('Found our room: it has handle#%d "%s"', handle, self.conn.InspectHandles(htype, [handle])[0])
+ room = handle
+ ctype = channel.GetChannelType()
+ if ctype == telepathy.CHANNEL_TYPE_TUBES:
+ self.__class__.log.debug('Found our Tubes channel at %s', channel_path)
+ tubes_chan = channel
+ elif ctype == telepathy.CHANNEL_TYPE_TEXT:
+ self.__class__.log.debug('Found our Text channel at %s', channel_path)
+ text_chan = channel
+
+ if room is None:
+ self.__class__.log.error("Presence service didn't create a room")
+ return
+ if text_chan is None:
+ self.__class__.log.error("Presence service didn't create a text channel")
+ return
+
+ # Make sure we have a Tubes channel - PS doesn't yet provide one
+ if tubes_chan is None:
+ self.__class__.log.debug("Didn't find our Tubes channel, requesting one...")
+ tubes_chan = self.conn.request_channel(telepathy.CHANNEL_TYPE_TUBES, telepathy.HANDLE_TYPE_ROOM, room, True)
+
+ self.tubes_chan = tubes_chan
+ self.text_chan = text_chan
+
+ tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube', self._newTubeCb)
+
+
+ def _newTubeCb(self, id, initiator, type, service, params, state):
+ self.__class__.log.debug('New tube: ID=%d initator=%d type=%d service=%s params=%r state=%d', id, initiator, type, service, params, state)
+ if (type == telepathy.TUBE_TYPE_DBUS and service == Constants.SERVICE):
+ if state == telepathy.TUBE_STATE_LOCAL_PENDING:
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)
+ tube_conn = TubeConnection(self.conn, self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
+ self.recTube = RecordTube(tube_conn)
+ self.recTube.connect("new-recd", self._newRecdCb)
+ self.recTube.connect("recd-request", self._recdRequestCb)
+ self.recTube.connect("recd-bits-arrived", self._recdBitsArrivedCb)
+ self.recTube.connect("recd-unavailable", self._recdUnavailableCb)
+
+
+ def _newRecdCb( self, objectThatSentTheSignal, recorder, xmlString ):
+ self.__class__.log.debug('_newRecdCb')
+ dom = None
+ try:
+ dom = xml.dom.minidom.parseString(xmlString)
+ except:
+ self.__class__.log.error('Unable to parse mesh xml')
+ if (dom == None):
+ return
+
+ recd = Recorded()
+ recd = serialize.fillRecdFromNode(recd, dom.documentElement)
+ if (recd != None):
+ self.__class__.log.debug('_newRecdCb: adding new recd thumb')
+ recd.buddy = True
+ recd.downloadedFromBuddy = False
+ self.m.addMeshRecd( recd )
+ else:
+ self.__class__.log.debug('_newRecdCb: recd is None. Unable to parse XML')
+
+
+ def requestMeshDownload( self, recd ):
+ if (recd.meshDownloading):
+ return True
+
+ self.m.updateXoFullStatus()
+ if (self.m.FULL):
+ return True
+
+ #this call will get the bits or request the bits if they're not available
+ if (recd.buddy and (not recd.downloadedFromBuddy)):
+ self.meshInitRoundRobin(recd)
+ return True
+
+ else:
+ return False
+
+
+ def meshInitRoundRobin( self, recd ):
+ if (recd.meshDownloading):
+ self.__class__.log.debug("meshInitRoundRobin: we are in midst of downloading this file...")
+ return
+
+ if (self.recTube == None):
+ gobject.idle_add(self.ui.updateMeshProgress, False, recd)
+ return
+
+ #start with who took the photo
+ recd.triedMeshBuddies = []
+ recd.triedMeshBuddies.append(Instance.keyHashPrintable)
+ self.meshReqRecFromBuddy( recd, recd.recorderHash, recd.recorderName )
+
+
+ def meshNextRoundRobinBuddy( self, recd ):
+ self.__class__.log.debug('meshNextRoundRobinBuddy')
+ if (recd.meshReqCallbackId != 0):
+ gobject.source_remove(recd.meshReqCallbackId)
+ recd.meshReqCallbackId = 0
+
+ #delete any stub of a partially downloaded file
+ filepath = recd.getMediaFilepath()
+ if (filepath != None):
+ if (os.path.exists(filepath)):
+ os.remove( filepath )
+
+ goodBudObj = None
+ buds = self._shared_activity.get_joined_buddies()
+ for i in range (0, len(buds)):
+ nextBudObj = buds[i]
+ nextBud = util._sha_data(nextBudObj.props.key)
+ nextBud = util.printable_hash(nextBud)
+ if (recd.triedMeshBuddies.count(nextBud) > 0):
+ self.__class__.log.debug('mnrrb: weve already tried bud ' + str(nextBudObj.props.nick))
+ else:
+ self.__class__.log.debug('mnrrb: ask next buddy: ' + str(nextBudObj.props.nick))
+ goodBudObj = nextBudObj
+ break
+
+ if (goodBudObj != None):
+ goodNick = goodBudObj.props.nick
+ goodBud = util._sha_data(goodBudObj.props.key)
+ goodBud = util.printable_hash(goodBud)
+ self.meshReqRecFromBuddy(recd, goodBud, goodNick)
+ else:
+ self.__class__.log.debug('weve tried all buddies here, and no one has this recd')
+ recd.meshDownloading = False
+ recd.triedMeshBuddies = []
+ recd.triedMeshBuddies.append(Instance.keyHashPrintable)
+ self.ui.updateMeshProgress(False, recd)
+
+
+ def meshReqRecFromBuddy( self, recd, fromWho, fromWhosNick ):
+ recd.triedMeshBuddies.append( fromWho )
+ recd.meshDownloadingFrom = fromWho
+ recd.meshDownloadingFromNick = fromWhosNick
+ recd.meshDownloadingProgress = False
+ recd.meshDownloading = True
+ recd.meshDownlodingPercent = 0.0
+ self.ui.updateMeshProgress(True, recd)
+ recd.meshReqCallbackId = gobject.timeout_add(self.meshTimeoutTime, self._meshCheckOnRecdRequest, recd)
+ self.recTube.requestRecdBits( Instance.keyHashPrintable, fromWho, recd.mediaMd5 )
+
+
+ def _meshCheckOnRecdRequest( self, recdRequesting ):
+ #todo: add category for "not active activity, so go ahead and delete"
+
+ if (recdRequesting.downloadedFromBuddy):
+ self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.downloadedFromBuddy')
+ if (recdRequesting.meshReqCallbackId != 0):
+ gobject.source_remove(recdRequesting.meshReqCallbackId)
+ recdRequesting.meshReqCallbackId = 0
+ return False
+ if (recdRequesting.deleted):
+ self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.deleted')
+ if (recdRequesting.meshReqCallbackId != 0):
+ gobject.source_remove(recdRequesting.meshReqCallbackId)
+ recdRequesting.meshReqCallbackId = 0
+ return False
+ if (recdRequesting.meshDownloadingProgress):
+ self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.meshDownloadingProgress')
+ #we've received some bits since last we checked, so keep waiting... they'll all get here eventually!
+ recdRequesting.meshDownloadingProgress = False
+ return True
+ else:
+ self.__class__.log.debug('_meshCheckOnRecdRequest: ! recdRequesting.meshDownloadingProgress')
+ #that buddy we asked info from isn't responding; next buddy!
+ #self.meshNextRoundRobinBuddy( recdRequesting )
+ gobject.idle_add(self.meshNextRoundRobinBuddy, recdRequesting)
+ return False
+
+
+ def _recdRequestCb( self, objectThatSentTheSignal, whoWantsIt, md5sumOfIt ):
+ #if we are here, it is because someone has been told we have what they want.
+ #we need to send them that thing, whatever that thing is
+ recd = self.m.getRecdByMd5( md5sumOfIt )
+ if (recd == None):
+ self.__class__.log.debug('_recdRequestCb: we dont have the recd they asked for')
+ self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
+ return
+ if (recd.deleted):
+ self.__class__.log.debug('_recdRequestCb: we have the recd, but it has been deleted, so we wont share')
+ self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
+ return
+ if (recd.buddy and not recd.downloadedFromBuddy):
+ self.__class__.log.debug('_recdRequestCb: we have an incomplete recd, so we wont share')
+ self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
+ return
+
+ recd.meshUploading = True
+ filepath = recd.getMediaFilepath()
+
+ if (recd.type == Constants.TYPE_AUDIO):
+ audioImgFilepath = recd.getAudioImageFilepath()
+
+ destPath = os.path.join(Instance.instancePath, "audioBundle")
+ destPath = utils.getUniqueFilepath(destPath, 0)
+ cmd = "cat " + str(filepath) + " " + str(audioImgFilepath) + " > " + str(destPath)
+ self.__class__.log.debug(cmd)
+ os.system(cmd)
+ filepath = destPath
+
+ sent = self.recTube.broadcastRecd(recd.mediaMd5, filepath, whoWantsIt)
+ recd.meshUploading = False
+ #if you were deleted while uploading, now throw away those bits now
+ if (recd.deleted):
+ recd.doDeleteRecorded(recd)
+
+
+ def _recdBitsArrivedCb( self, objectThatSentTheSignal, md5sumOfIt, part, numparts, bytes, fromWho ):
+ #self.__class__.log.debug('_recdBitsArrivedCb: ' + str(part) + "/" + str(numparts))
+ recd = self.m.getRecdByMd5( md5sumOfIt )
+ if (recd == None):
+ self.__class__.log.debug('_recdBitsArrivedCb: thx 4 yr bits, but we dont even have that photo')
+ return
+ if (recd.deleted):
+ self.__class__.log.debug('_recdBitsArrivedCb: thx 4 yr bits, but we deleted that photo')
+ return
+ if (recd.downloadedFromBuddy):
+ self.__class__.log.debug('_recdBitsArrivedCb: weve already downloadedFromBuddy')
+ return
+ if (not recd.buddy):
+ self.__class__.log.debug('_recdBitsArrivedCb: uh, we took this photo, so dont need your bits')
+ return
+ if (recd.meshDownloadingFrom != fromWho):
+ self.__class__.log.debug('_recdBitsArrivedCb: wrong bits ' + str(fromWho) + ", exp:" + str(recd.meshDownloadingFrom))
+ return
+
+ #update that we've heard back about this, reset the timeout
+ gobject.source_remove(recd.meshReqCallbackId)
+ recd.meshReqCallbackId = gobject.timeout_add(self.meshTimeoutTime, self._meshCheckOnRecdRequest, recd)
+
+ #update the progress bar
+ recd.meshDownlodingPercent = (part+0.0)/(numparts+0.0)
+ recd.meshDownloadingProgress = True
+ self.ui.updateMeshProgress(True, recd)
+ f = open(recd.getMediaFilepath(), 'a+')
+ f.write(bytes)
+ f.close()
+
+ if part == numparts:
+ self.__class__.log.debug('Finished receiving %s' % recd.title)
+ gobject.source_remove( recd.meshReqCallbackId )
+ recd.meshReqCallbackId = 0
+ recd.meshDownloading = False
+ recd.meshDownlodingPercent = 1.0
+ recd.downloadedFromBuddy = True
+ if (recd.type == Constants.TYPE_AUDIO):
+ filepath = recd.getMediaFilepath()
+ bundlePath = os.path.join(Instance.instancePath, "audioBundle")
+ bundlePath = utils.getUniqueFilepath(bundlePath, 0)
+
+ cmd = "split -a 1 -b " + str(recd.mediaBytes) + " " + str(filepath) + " " + str(bundlePath)
+ self.__class__.log.debug( cmd )
+ os.system( cmd )
+
+ bundleName = os.path.basename(bundlePath)
+ mediaFilename = str(bundleName) + "a"
+ mediaFilepath = os.path.join(Instance.instancePath, mediaFilename)
+ mediaFilepathExt = os.path.join(Instance.instancePath, mediaFilename+".ogg")
+ os.rename(mediaFilepath, mediaFilepathExt)
+ audioImageFilename = str(bundleName) + "b"
+ audioImageFilepath = os.path.join(Instance.instancePath, audioImageFilename)
+ audioImageFilepathExt = os.path.join(Instance.instancePath, audioImageFilename+".png")
+ os.rename(audioImageFilepath, audioImageFilepathExt)
+
+ recd.mediaFilename = os.path.basename(mediaFilepathExt)
+ recd.audioImageFilename = os.path.basename(audioImageFilepathExt)
+
+ self.ui.showMeshRecd( recd )
+ elif part > numparts:
+ self.__class__.log.error('More parts than required have arrived')
+
+
+ def _getAlbumArtCb( self, objectThatSentTheSignal, pixbuf, recd ):
+
+ if (pixbuf != None):
+ imagePath = os.path.join(Instance.instancePath, "audioPicture.png")
+ imagePath = utils.getUniqueFilepath( imagePath, 0 )
+ pixbuf.save( imagePath, "png", {} )
+ recd.audioImageFilename = os.path.basename(imagePath)
+
+ self.ui.showMeshRecd( recd )
+ return False
+
+
+ def _recdUnavailableCb( self, objectThatSentTheSignal, md5sumOfIt, whoDoesntHaveIt ):
+ self.__class__.log.debug('_recdUnavailableCb: sux, we want to see that photo')
+ recd = self.m.getRecdByMd5( md5sumOfIt )
+ if (recd == None):
+ self.__class__.log.debug('_recdUnavailableCb: actually, we dont even know about that one..')
+ return
+ if (recd.deleted):
+ self.__class__.log.debug('_recdUnavailableCb: actually, since we asked, we deleted.')
+ return
+ if (not recd.buddy):
+ self.__class__.log.debug('_recdUnavailableCb: uh, odd, we took that photo and have it already.')
+ return
+ if (recd.downloadedFromBuddy):
+ self.__class__.log.debug('_recdUnavailableCb: we already downloaded it... you might have been slow responding.')
+ return
+ if (recd.meshDownloadingFrom != whoDoesntHaveIt):
+ self.__class__.log.debug('_recdUnavailableCb: we arent asking you for a copy now. slow response, pbly.')
+ return
+
+ #self.meshNextRoundRobinBuddy( recd )