MetadataHandler.py :  » Network » Torrent-Swapper » swapper » Swapper » Overlay » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Network » Torrent Swapper 
Torrent Swapper » swapper » Swapper » Overlay » MetadataHandler.py
# Written by Jie Yang, Arno Bakker
# see LICENSE.txt for license information
import sys
import md5
import os
from sha import sha
from time import time,ctime
from traceback import print_exc

from BitTornado.bencode import bencode,bdecode
from BitTornado.BT1.MessageID import *
from Swapper.utilities import isValidInfohash,show_permid
from Swapper.CacheDB.CacheDBHandler import TorrentDBHandler
from Swapper.unicode import name2unicode

# Python no recursive imports?
# from overlayswarm import overlay_infohash
overlay_infohash = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'


DEBUG = False
## Arno: FIXME: 8MB too large, IMHO.
Max_Torrent_Size = 8*1024*1024    # 8MB torrent = about 80G files

class MetadataHandler:
    
    __single = None
    
    def __init__(self):
        if MetadataHandler.__single:
            raise RuntimeError, "MetadataHandler is singleton"
        MetadataHandler.__single = self

    def getInstance(*args, **kw):
        if MetadataHandler.__single is None:
            MetadataHandler(*args, **kw)
        return MetadataHandler.__single
    getInstance = staticmethod(getInstance)
        
    def register(self, secure_overlay, dlhelper, launchmany, config_dir):
        self.secure_overlay = secure_overlay
        self.dlhelper = dlhelper
        self.config_dir = os.path.join(config_dir, 'torrent2')    #TODO: user can set it
        self.torrent_db = TorrentDBHandler()

    def handleMessage(self, permid, message):
        
        t = message[0]
        
        if t == GET_METADATA:
            if DEBUG:
                print >> sys.stderr,"metadata: Got GET_METADATA",len(message),show_permid(permid)
            return self.send_metadata(permid, message)
        elif t == METADATA:
            if DEBUG:
                print >> sys.stderr,"metadata: Got METADATA",len(message)
            return self.got_metadata(permid, message)
        else:
            if DEBUG:
                print >> sys.stderr,"metadata: UNKNOWN OVERLAY MESSAGE", ord(t)
            return False

    def send_metadata_request(self, permid, torrent_hash):
        if not isValidInfohash(torrent_hash):
            return False
        try:
            metadata_request = bencode(torrent_hash)
            self.secure_overlay.addTask(permid, GET_METADATA + metadata_request)
        except:
            return False
        return True
        

    def send_metadata(self, conn, message):
        try:
            torrent_hash = bdecode(message[1:])
        except:
            print_exc()
            if DEBUG:
                print >> sys.stderr,"metadata: GET_METADATA: error becoding"
            return False
        if not isValidInfohash(torrent_hash):
            if DEBUG:
                print >> sys.stderr,"metadata: GET_METADATA: invalid hash"
            return False

        torrent_path = self.find_torrent(torrent_hash)
        if not torrent_path:
            if DEBUG:
                print >> sys.stderr,"metadata: GET_METADATA: not torrent path"
            return False
        torrent_data = self.read_torrent(torrent_path)
        if torrent_data:
            self.do_send_metadata(conn, torrent_hash, torrent_data)
        else:
            if DEBUG:
                print >> sys.stderr,"metadata: GET_METADATA: no torrent data to send"
            pass
        return True
    
    def do_send_metadata(self, permid, torrent_hash, torrent_data):
        torrent = {'torrent_hash':torrent_hash, 'metadata':torrent_data}
        metadata_request = bencode(torrent)
        if DEBUG:
            print >> sys.stderr,"metadata: send metadata", len(metadata_request)
        self.secure_overlay.addTask(permid,METADATA + metadata_request)

    def find_torrent(self, torrent_hash):
        """ lookup torrent file and return torrent path """
        
        data = self.torrent_db.getTorrent(torrent_hash)
        if not data:
            return None
        try:
            filepath = os.path.join(data['torrent_dir'], data['torrent_name'])
            if os.path.isfile(filepath):
                return filepath
        except:
            return None

    def read_torrent(self, torrent_path):
        try:
            file = open(torrent_path, "rb")
            torrent_data = file.read()
            file.close()
            torrent_size = len(torrent_data)
            if DEBUG:
                print >> sys.stderr,"metadata: read torrent", torrent_path, torrent_size
            if torrent_size > Max_Torrent_Size:
                return None
            if DEBUG:
                print >> sys.stderr,"metadata: sending torrent", torrent_size, md5.new(torrent_data).hexdigest()
            return torrent_data
        except:
            return None


    def addTorrentToDB(self, src, torrent_hash, metadata):
        
        metainfo = bdecode(metadata)
        namekey = name2unicode(metainfo)  # convert info['name'] to type(unicode)
        info = metainfo['info']
        
        torrent = {}
        torrent['torrent_dir'], torrent['torrent_name'] = os.path.split(src)
        
        torrent_info = {}
        torrent_info['name'] = info.get(namekey, '')
        length = 0
        nf = 0
        if info.has_key('length'):
            length = info.get('length', 0)
            nf = 1
        elif info.has_key('files'):
            for li in info['files']:
                nf += 1
                if li.has_key('length'):
                    length += li['length']
        torrent_info['length'] = length
        torrent_info['num_files'] = nf
        torrent_info['announce'] = metainfo.get('announce', '')
        torrent_info['announce-list'] = metainfo.get('announce-list', '')
        torrent_info['creation date'] = metainfo.get('creation date', 0)
        torrent['info'] = torrent_info
        
        self.torrent_db.addTorrent(torrent_hash, torrent, new_metadata=True)
        self.torrent_db.sync()
        
    def save_torrent(self, torrent_hash, metadata):
        if DEBUG:
            print >> sys.stderr,"metadata: Store torrent", md5.new(torrent_hash).digest(), "on disk"
        #TODO: 
        file_name = self.get_filename(metadata, torrent_hash)
        save_path = os.path.join(self.config_dir, file_name)
        self.addTorrentToDB(save_path, torrent_hash, metadata)
        self.write_torrent(metadata, self.config_dir, file_name)

    def get_filename(self, metadata, torrent_hash):
        # assign a name for the torrent. add a timestamp if it exists.
        metainfo = bdecode(metadata)
        file_name = sha(torrent_hash).hexdigest()+'.torrent'
        _path = os.path.join(self.config_dir, file_name)
        if os.path.exists(_path):
            file_name = str(time()) + '_' + file_name 
        return file_name
        # exceptions will be handled by got_metadata()
        
    def write_torrent(self, metadata, dir, name):
        try:
            if not os.access(dir,os.F_OK):
                os.mkdir(dir)
            save_path = os.path.join(dir, name)
            file = open(save_path, 'wb')
            file.write(metadata)
            file.close()
            if DEBUG:
                print >> sys.stderr,"metadata: write torrent", save_path, len(metadata), hash(metadata)
        except:
            print_exc()
            print >> sys.stderr, "metadata: write torrent failed"

    def valid_metadata(self, torrent_hash, metadata):
        metainfo = bdecode(metadata)
        infohash = sha(bencode(metainfo['info'])).digest()
        if infohash != torrent_hash:
            print >> sys.stderr, "metadata: infohash doesn't match the torrent " + \
            "hash. Required: " + `torrent_hash` + ", but got: " + `infohash`
            return False
        return True
        
    def got_metadata(self, conn, message):
        try:
            message = bdecode(message[1:])
        except:
            return False
        if not isinstance(message, dict):
            return False
        try:
            torrent_hash = message['torrent_hash']
            if not isValidInfohash(torrent_hash):
                return False
            metadata = message['metadata']
            if not self.valid_metadata(torrent_hash, metadata):
                return False
            if DEBUG:
                torrent_size = len(metadata)
                print >> sys.stderr,"metadata: Recvd torrent", torrent_size, md5.new(metadata).hexdigest()
            self.save_torrent(torrent_hash, metadata)
            if self.dlhelper is not None:
                self.dlhelper.call_dlhelp_task(torrent_hash, metadata)
        except Exception, msg:
            print_exc()
            print >> sys.stderr,"metadata: Received metadata is broken", msg
            return False
        
        return True
        
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.