Changeset 290 for indytube/trunk

Show
Ignore:
Timestamp:
11/26/07 10:56:05 (14 months ago)
Author:
andy
Message:

More work on the bittorrent indytube server

We have a perspective broker immplementation working, which can asyncrolously download, transcode and make a torrent file now.
We dont have an integrated tracker yet.

Location:
indytube/trunk/indytube/bittorrent
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • indytube/trunk/indytube/bittorrent/README

    r249 r290  
    11This is the implementation using perspective broker from twisted  
    22 
    3  
    4 Run the server , like so , one directory up: 
    5 $python -ny bittorrent/server.py 
     3Run the server using Twistd server, like so , one directory up: 
     4$twistd -ny bittorrent/server.py 
    65 
    76then you can test with the main() method , in the client , like so: 
    87$python bittorrent/client.py 
    98 
     9 
     10The server needs to be running continously in normal operation. 
     11 
     12Plumi/Plone (one possible client) will connect when it needs file downloading and transcoding done. 
     13 
  • indytube/trunk/indytube/bittorrent/client.py

    r249 r290  
    2020from twisted.spread import pb 
    2121 
    22 class IndyTubeClient: 
     22class IndyTubePBClient: 
    2323        hostname = 'localhost' 
    2424        portnumber = 9119 
     
    7979def main(): 
    8080        # test a simple connection to the server, on the localhost 
    81         client = IndyTubeClient('localhost',9119) 
    82         client.setupOperation('http://localhost/download/video','filename.ogg') 
     81        client = IndyTubePBClient('localhost',9119) 
     82        client.setupOperation('http://www.engagemedia.org/Members/jamyoung/videos/cold-world.mov/download','cold-world.mov') 
    8383        client.connectToServer() 
    8484        client.runReactor() 
  • indytube/trunk/indytube/bittorrent/server.py

    r249 r290  
    77# 
    88# This uses BitTorrent 5.0.8 to implement the bittorrent functionality 
     9# see http://download.bittorrent.com/dl/ 
    910 
    1011# Copyright Andy Nicholson 2007 
     
    3132from thread import get_ident,allocate_lock 
    3233from operator import mod 
     34import xmlrpclib 
    3335 
    3436#bittorrent 
     
    5557 
    5658#standard location for configuration file 
    57 from indytube import CONF_FILE_DEFAULT 
     59from config import CONF_FILE_DEFAULT 
     60from indytube import IndyTubeTranscoder 
    5861 
    5962## from launchmany-console 
     
    7679## end from launchmany-console 
    7780 
    78 class IndyTubeServer(pb.Root): 
    79     ''' IndyTubeServer is a perspective broker service that implements file downloading,   
     81class IndyTubePBServer(pb.Root): 
     82    ''' IndyTubePBServer is a Twisted Perspective Broker service that implements media-file downloading,   
    8083        mencoder and ffmpeg2theora transcoding, bittorrent meta-file creation 
    8184        and bittorrent seeding and tracking ''' 
     85 
     86    #points to the filepath of the latest incoming media file downloaded 
     87    _incoming_fp = '' 
     88    #point to the latest incoming media file download URL 
     89    _bootstrapURL = '' 
     90    # the filename of the media file downloaded 
     91    _filename = '' 
     92    # torrent filename 
     93    _torrent_filepath = '' 
     94    # the logger object 
     95    logger = None 
    8296 
    8397    def parse_config(self,conf_file): 
     
    87101 
    88102        self.pb_protocolPort = config.get('pb-server', 'PROTOCOL_PORT') 
    89         self.pb_torrentDir = config.get('pb-server', 'TORRENT_DIR') 
     103        self.pb_torrentDir = unicode(config.get('pb-server', 'TORRENT_DIR')) 
    90104        self.pb_downloadDir = config.get('pb-server', 'DOWNLOAD_DIR') 
    91105        self.pb_serverName = config.get('pb-server', 'SERVER_NAME') 
    92106        self.pb_trackerUrl = config.get('pb-server', 'TRACKER_URL') 
    93107 
    94         print "I have %s %s %s %s %s " % ( self.pb_protocolPort , self.pb_torrentDir , self.pb_downloadDir, self.pb_serverName, self.pb_trackerUrl ) 
     108        # XXX check that these directories exist! 
     109 
     110        self.logger.info("I have %s %s %s %s %s " % ( self.pb_protocolPort , self.pb_torrentDir , self.pb_downloadDir, self.pb_serverName, self.pb_trackerUrl )) 
    95111 
    96112    def __init__(self): 
     113        injectLogger(use_syslog = False, capture_output = True, verbose = True, 
     114                 log_level = logging.DEBUG, log_twisted = False ) 
     115        logging.getLogger('').removeHandler(console)  # remove handler installed by BitTorrent.__init__. 
     116        self.logger = logging.getLogger("") 
     117 
     118        #XXX torrent seeder/tracker 
    97119        #start the torrent seeder, in a separate thread! 
    98         threads.deferToThread(self.initaliseLaunchManyCore) 
     120        #threads.deferToThread(self.initaliseLaunchManyCore) 
     121 
     122    def _doOperations(self): 
     123        ''' private function - just download the media at bootstrapULR into file filename''' 
     124        # if each chain succeeds, then go to next step, else go to error handler 
     125        # 
     126        # the chain is: 
     127        #1. Download the media file to a local file.  
     128        #2. Call indytube to transcode it. 
     129        #3. Bittorrent - create torrent file of original video file. 
     130        #       -- Seeding and tracking - happens automatically when the xyz.torrent file is created 
     131        #4. Call back to Plumi/Plone to make content objects relating to these new files.  
     132        #       -- create a object representing any transcoded versions of the file 
     133        #               just send URL links to these files 
     134        #       -- create a object representing the torrent file of the original video 
     135        #               send the actual torrent file info 
     136 
     137        self.logger.info("downloading media file from url %s, doing encoding on %s " % (self._bootstrapURL,self._filename)) 
     138        self._incoming_fp = self.pb_downloadDir + '/' + self._filename 
     139        self._torrent_filepath = self.pb_torrentDir + '/' + self._filename + ".torrent" 
     140        filename,headers = urllib.urlretrieve(self._bootstrapURL, self._incoming_fp) 
     141        #we are now free to process the file .. we have downloaded it all. 
     142        # downloading complete! 
     143        self.logger.info("downloading complete!") 
     144        # carrying on the chain of operations.. 
     145        self._doTranscoding() 
     146        self._doBittorrentOperation() 
     147        self._doPloneObjectCreation() 
     148 
     149    def _doTranscoding(self): 
     150        ''' do the transcoding via Indytube itself ''' 
     151        # TODO - via XMLRPC ?? 
     152 
     153        self.logger.info("doing transcoding of video file")      
     154        # just using the python library directly 
     155        transcoder = IndyTubeTranscoder() 
     156        transcoder.parse_config(CONF_FILE_DEFAULT) 
     157        transcoder.attempt_transcode_file(self._incoming_fp) 
     158 
     159    def _doBittorrentOperation(self): 
     160        ''' Make the torrent file from the original video file ''' 
     161        self.logger.info("Starting bittorrent operations using tracker url %s" % self.pb_trackerUrl) 
     162        incoming_comment = "Torrent file made by Indytube" 
     163        make_meta_files( self.pb_trackerUrl, [self._incoming_fp], piece_len_pow2=18, comment=incoming_comment, target = self._torrent_filepath) 
     164         
     165    def _doPloneObjectCreation(self): 
     166        #  Construct a Plone based object to represent the torrent file 
     167        #  Construct a Plone based object to represent the transcoded files 
     168        self.logger.info("doing plone object creation") 
     169        #server_url = 'http://username:password@localhost:8080/plumitest/Members/andy/videos/test123.mov/publishXML' 
     170        #server = xmlrpclib.Server(server_url) 
     171        #server.publishObject() 
     172 
     173    def _errorinRemoteOperation(self,foo): 
     174        ''' error was caught during the remote operation ''' 
     175        self.logger.info("Got an error 8-( %s " %foo) 
     176        return False 
    99177 
    100178    def remote_RemoteIndyTubeOperation(self,indyInfo): 
     179        ''' The remote method exposed via the Perspective Broker. Clients call this method to  
     180        have their media file downloaded, transcoded, and processed for bittorrent tracking and seeding ''' 
     181 
    101182        #parse args 
    102         bootstrapURL=indyInfo['bootstrapURL'] 
    103         filename=indyInfo['filename'] 
    104  
    105         # XXX make all these operations run in a separate thread. 
    106  
    107         logging.getLogger(self.pb_serverName).info("downloading media file from url %s, doing encoding on %s " % (bootstrapURL,filename)) 
    108         #1. download it  
    109         incoming_fp = self.pb_downloadDir + '/' + filename 
    110         urllib.urlretrieve(bootstrapURL, incoming_fp) 
    111          
    112         #2. call indytube to transcode it!! 
    113         # TODO 
    114         # transcoder = IndyTubeTranscoder() 
    115         # transcoder.attempt_transcode_file(incoming_fp) 
    116  
    117         #3. Bittorrent - create torrent file of original video file 
    118         torrent_filepath = self.pb_torrentDir + '/' + filename + ".torrent" 
    119         incoming_comment = "Torrent file made by Indytube" 
    120         make_meta_files( self.pb_trackerUrl, [incoming_fp], piece_len_pow2=18, comment=incoming_comment, target = torrent_filepath) 
    121  
    122         #4. Seeding and tracking! 
    123         # TODO 
    124  
    125         # everything scheduled OK - return True 
     183        self._bootstrapURL=indyInfo['bootstrapURL'] 
     184        self._filename=indyInfo['filename'] 
     185 
     186        self.logger.info("started - %s %s " % (self._bootstrapURL,self._filename)) 
     187        deferred_download = threads.deferToThread(self._doOperations) 
     188        deferred_download.addErrback(self._errorinRemoteOperation) 
     189 
     190        #deferred_download.addCallbacks(self._do_Transcoding, self._errorinRemoteOperation) 
     191        #deferred_download.addCallbacks(self._doBittorrentOperation, self._errorinRemoteOperation) 
     192 
     193        # always returns True 
    126194        return True 
    127195 
     
    132200            config, args = configfile.parse_configuration_and_args(defaults, uiname, [], 0, 1) 
    133201            #config, args = configfile.parse_configuration_and_args(defaults, uiname, sys.argv[1:], 0, 1) 
    134             config['torrent_dir'] = self.torrentDir 
     202            config['torrent_dir'] = self.pb_torrentDir 
    135203            config['parse_dir_interval'] = 20 #make the dir scan happen @20 seconds, not default of 60 
    136204            config['save_in'] = u"" 
     
    142210        d = HeadlessDisplayer() 
    143211        config = Preferences().initWithDict(config) 
    144         injectLogger(use_syslog = False, capture_output = True, verbose = True, 
    145                  log_level = logging.DEBUG, log_twisted = False ) 
    146         logging.getLogger('').removeHandler(console)  # remove handler installed by BitTorrent.__init__. 
    147212        #This starts up a RawServer, ie it will block until we are done in there... 
    148213        LaunchMany(config, d.display, 'launchmany-console') 
     
    150215 
    151216# Standard twisted application Boilerplate 
    152 indytube_server = IndyTubeServer() 
     217indytube_server = IndyTubePBServer() 
    153218#parse our config 
    154219if not (os.path.exists(CONF_FILE_DEFAULT)):