def __init__(self, stream, bt1download, authconfig): self.stream = stream self.bt1download = bt1download self.exiting = False # shortcuts to the parts we use self.storagewrapper = bt1download.storagewrapper self.picker = bt1download.picker self.rawserver = bt1download.rawserver self.connecter = bt1download.connecter self.fileselector = bt1download.fileselector # generic video information self.videostatus = bt1download.videostatus # buffer to accumulate video data self.buffer = [] self.buflen = 0 self.bufferlock = RLock() self.handling_pieces = False # LIVESOURCEAUTH if authconfig.get_method() == LIVE_AUTHMETHOD_ECDSA: self.authenticator = ECDSAAuthenticator(self.videostatus.piecelen,self.bt1download.len_pieces,keypair=authconfig.get_keypair()) else: self.authenticator = NullAuthenticator(self.videostatus.piecelen,self.bt1download.len_pieces)
def __init__(self, stream, bt1download, authconfig, restartstatefilename): self.stream = stream self.bt1download = bt1download self.restartstatefilename = restartstatefilename self.exiting = False # shortcuts to the parts we use self.storagewrapper = bt1download.storagewrapper self.picker = bt1download.picker self.rawserver = bt1download.rawserver self.connecter = bt1download.connecter self.fileselector = bt1download.fileselector # generic video information self.videostatus = bt1download.videostatus # buffer to accumulate video data self.buffer = [] self.buflen = 0 self.bufferlock = RLock() self.handling_pieces = False self.readlastseqnum = False # LIVESOURCEAUTH if authconfig.get_method() == LIVE_AUTHMETHOD_ECDSA: self.authenticator = ECDSAAuthenticator( self.videostatus.piecelen, self.bt1download.len_pieces, keypair=authconfig.get_keypair()) elif authconfig.get_method() == LIVE_AUTHMETHOD_RSA: self.authenticator = RSAAuthenticator( self.videostatus.piecelen, self.bt1download.len_pieces, keypair=authconfig.get_keypair()) else: self.authenticator = NullAuthenticator(self.videostatus.piecelen, self.bt1download.len_pieces)
class VideoSourceTransporter: """ Reads data from an external source and turns it into BitTorrent chunks. """ def __init__(self, stream, bt1download, authconfig, restartstatefilename): self.stream = stream self.bt1download = bt1download self.restartstatefilename = restartstatefilename self.exiting = False # shortcuts to the parts we use self.storagewrapper = bt1download.storagewrapper self.picker = bt1download.picker self.rawserver = bt1download.rawserver self.connecter = bt1download.connecter self.fileselector = bt1download.fileselector # generic video information self.videostatus = bt1download.videostatus # buffer to accumulate video data self.buffer = [] self.buflen = 0 self.bufferlock = RLock() self.handling_pieces = False self.readlastseqnum = False # LIVESOURCEAUTH if authconfig.get_method() == LIVE_AUTHMETHOD_ECDSA: self.authenticator = ECDSAAuthenticator( self.videostatus.piecelen, self.bt1download.len_pieces, keypair=authconfig.get_keypair()) elif authconfig.get_method() == LIVE_AUTHMETHOD_RSA: self.authenticator = RSAAuthenticator( self.videostatus.piecelen, self.bt1download.len_pieces, keypair=authconfig.get_keypair()) else: self.authenticator = NullAuthenticator(self.videostatus.piecelen, self.bt1download.len_pieces) def start(self): """ Start transporting data. """ self.input_thread_handle = SimpleThread(self.input_thread) self.input_thread_handle.start() def _read(self, length): """ Called by input_thread. """ return self.stream.read(length) def input_thread(self): """ A thread reading the stream and buffering it. """ print >> sys.stderr, "VideoSource: started input thread" # we can't set the playback position from this thread, so # we assume all pieces are vs.piecelen in size. contentbs = self.authenticator.get_content_blocksize() try: while not self.exiting: data = self._read(contentbs) if not data: break if DEBUG: print >> sys.stderr, "VideoSource: read %d bytes" % len( data) self.process_data(data) except IOError: if DEBUG: print_exc() self.shutdown() def shutdown(self): """ Stop transporting data. """ print >> sys.stderr, "VideoSource: shutting down" if self.exiting: return self.exiting = True try: self.stream.close() except IOError: # error on closing, nothing we can do pass def process_data(self, data): """ Turn data into pieces and queue them for insertion. """ """ Called by input thread. """ vs = self.videostatus self.bufferlock.acquire() try: # add data to buffer self.buffer.append(data) self.buflen += len(data) if not self.handling_pieces: # signal to network thread that data has arrived self.rawserver.add_task(self.create_pieces) self.handling_pieces = True finally: self.bufferlock.release() def create_pieces(self): """ Process the buffer and create pieces when possible. Called by network thread """ def handle_one_piece(): vs = self.videostatus # LIVESOURCEAUTH # Arno: make room for source auth info contentbs = self.authenticator.get_content_blocksize() if self.buflen < contentbs: return False if len(self.buffer[0]) == contentbs: content = self.buffer[0] del self.buffer[0] else: if DEBUG: print >> sys.stderr, "VideoSource: JOIN ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" buffer = "".join(self.buffer) self.buffer = [buffer[contentbs:]] content = buffer[:contentbs] self.buflen -= contentbs datas = self.authenticator.sign(content) piece = "".join(datas) # add new piece self.add_piece(vs.playback_pos, piece) # invalidate old piece self.del_piece(vs.live_piece_to_invalidate()) try: lastseqnum = self.authenticator.get_source_seqnum() f = open(self.restartstatefilename, "wb") f.write(str(lastseqnum)) f.close() except: print_exc() # advance pointer vs.inc_playback_pos() return True if not self.readlastseqnum: self.readlastseqnum = True try: f = open(self.restartstatefilename, "rb") data = f.read() f.close() lastseqnum = int(data) print >> sys.stderr, "VideoSource: Restarting stream at abs.piece", lastseqnum # Set playback pos of source and absolute piece nr. lastpiecenum = lastseqnum % self.authenticator.get_npieces() self.authenticator.set_source_seqnum(lastseqnum + 1L) self.videostatus.set_live_startpos(lastpiecenum) self.videostatus.inc_playback_pos() except: print_exc() self.bufferlock.acquire() try: while handle_one_piece(): pass self.handling_pieces = False finally: self.bufferlock.release() def add_piece(self, index, piece): """ Push one piece into the BitTorrent system. """ # Modelled after BitTornado.BT1.Downloader.got_piece # We don't need most of that function, since this piece # was never requested from another peer. if DEBUG: print >> sys.stderr, "VideoSource: created piece #%d" % index # ECDSA #print >>sys.stderr,"VideoSource: sig",`piece[-64:]` #print >>sys.stderr,"VideoSource: dig",sha(piece[:-64]).hexdigest() # RSA, 768 bits #print >>sys.stderr,"VideoSource: sig",`piece[-96:]` #print >>sys.stderr,"VideoSource: dig",sha(piece[:-112]).hexdigest() # act as if the piece was requested and just came in # do this in chunks, as StorageWrapper expects to handle # a request for each chunk chunk_size = self.storagewrapper.request_size length = min(len(piece), self.storagewrapper._piecelen(index)) x = 0 while x < length: self.storagewrapper.new_request(index) self.storagewrapper.piece_came_in(index, x, [], piece[x:x + chunk_size], min(chunk_size, length - x)) x += chunk_size # also notify the piecepicker self.picker.complete(index) # notify our neighbours self.connecter.got_piece(index) def del_piece(self, piece): if DEBUG: print >> sys.stderr, "VideoSource: del_piece", piece # See Tribler/Core/Video/VideoOnDemand.py, live_invalidate_piece_globally self.picker.invalidate_piece(piece) self.picker.downloader.live_invalidate(piece)
class VideoSourceTransporter: """ Reads data from an external source and turns it into BitTorrent chunks. """ def __init__(self, stream, bt1download, authconfig): self.stream = stream self.bt1download = bt1download self.exiting = False # shortcuts to the parts we use self.storagewrapper = bt1download.storagewrapper self.picker = bt1download.picker self.rawserver = bt1download.rawserver self.connecter = bt1download.connecter self.fileselector = bt1download.fileselector # generic video information self.videostatus = bt1download.videostatus # buffer to accumulate video data self.buffer = [] self.buflen = 0 self.bufferlock = RLock() self.handling_pieces = False # LIVESOURCEAUTH if authconfig.get_method() == LIVE_AUTHMETHOD_ECDSA: self.authenticator = ECDSAAuthenticator(self.videostatus.piecelen,self.bt1download.len_pieces,keypair=authconfig.get_keypair()) else: self.authenticator = NullAuthenticator(self.videostatus.piecelen,self.bt1download.len_pieces) def start(self): """ Start transporting data. """ self.input_thread_handle = SimpleThread(self.input_thread) self.input_thread_handle.start() def _read(self,length): """ Called by input_thread. """ return self.stream.read(length) def input_thread(self): """ A thread reading the stream and buffering it. """ print >>sys.stderr,"VideoSource: started input thread" # we can't set the playback position from this thread, so # we assume all pieces are vs.piecelen in size. contentbs = self.authenticator.get_content_blocksize() try: while not self.exiting: data = self._read(contentbs) if not data: break if DEBUG: print >>sys.stderr,"VideoSource: read %d bytes" % len(data) self.process_data(data) except IOError: if DEBUG: print_exc() self.shutdown() def shutdown(self): """ Stop transporting data. """ print >>sys.stderr,"VideoSource: shutting down" if self.exiting: return self.exiting = True try: self.stream.close() except IOError: # error on closing, nothing we can do pass def process_data(self,data): """ Turn data into pieces and queue them for insertion. """ """ Called by input thread. """ vs = self.videostatus self.bufferlock.acquire() try: # add data to buffer self.buffer.append( data ) self.buflen += len( data ) if not self.handling_pieces: # signal to main thread that data has arrived self.rawserver.add_task( self.create_pieces ) self.handling_pieces = True finally: self.bufferlock.release() def create_pieces(self): """ Process the buffer and create pieces when possible. Called by network thread """ def handle_one_piece(): vs = self.videostatus # LIVESOURCEAUTH # Arno: make room for source auth info contentbs = self.authenticator.get_content_blocksize() if self.buflen < contentbs: return False if len(self.buffer[0]) == contentbs: content = self.buffer[0] del self.buffer[0] else: if DEBUG: print >>sys.stderr,"VideoSource: JOIN ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" buffer = "".join(self.buffer) self.buffer = [buffer[contentbs:]] content = buffer[:contentbs] self.buflen -= contentbs datas = self.authenticator.sign(content) piece = "".join(datas) # add new piece self.add_piece(vs.playback_pos,piece) # invalidate old piece self.del_piece( vs.live_piece_to_invalidate() ) # advance pointer vs.inc_playback_pos() return True self.bufferlock.acquire() try: while handle_one_piece(): pass self.handling_pieces = False finally: self.bufferlock.release() def add_piece(self,index,piece): """ Push one piece into the BitTorrent system. """ # Modelled after BitTornado.BT1.Downloader.got_piece # We don't need most of that function, since this piece # was never requested from another peer. if DEBUG: print >>sys.stderr,"VideoSource: created piece #%d" % index #print >>sys.stderr,"VideoSource: sig",`piece[-64:]` #print >>sys.stderr,"VideoSource: dig",sha(piece[:-64]).hexdigest() # act as if the piece was requested and just came in # do this in chunks, as StorageWrapper expects to handle # a request for each chunk chunk_size = self.storagewrapper.request_size length = min( len(piece), self.storagewrapper._piecelen(index) ) x = 0 while x < length: self.storagewrapper.new_request( index ) self.storagewrapper.piece_came_in( index, x, [], piece[x:x+chunk_size], min(chunk_size,length-x) ) x += chunk_size # also notify the piecepicker self.picker.complete( index ) # notify our neighbours self.connecter.got_piece( index ) def del_piece(self,piece): if DEBUG: print >>sys.stderr,"VideoSource: del_piece",piece # See Tribler/Core/Video/VideoOnDemand.py, live_invalidate_piece_globally self.picker.invalidate_piece(piece) self.picker.downloader.live_invalidate(piece)