用XML_RPC实现P2P

清华大佬耗费三个月吐血整理的几百G的资源,免费分享!....>>>

# -*- coding: utf-8 -*-
from xmlrpclib import ServerProxy, Fault
from os.path import join, isfile, abspath
from SimpleXMLRPCServer import SimpleXMLRPCServer
from urlparse import urlparse
import sys
import xmlrpclib

SimpleXMLRPCServer.allow_reuse_address = 1
#避免循环请求和长链请求。之所以用6是采用了六度分隔的原理
MAX_HISTORY_LENGTH = 6

UNHANDLED     = 100
ACCESS_DENIED = 200

class UnhandledQuery(Fault):
    def __init__(self, message="Counldn't handle the query"):
        Fault.__init__(self, UNHANDLED, message)

class AccessDenied(Fault):
    def __init__(self, message='Access denied'):
        Fault.__init__(self, ACCESS_DENIED, message)

def inside(dirs, name):
    the_dir = abspath(dirs)
    name = abspath(name)
    return name.startswith(join(the_dir, ''))

def getPort(url):
    name = urlparse(url)[1]
    parts = name.split(':')
    return int(parts[-1])

class Node:
    def __init__(self, url, dirname, secret):
        self.url = url
        self.dirname = dirname
        self.secret = secret
        self.known = set()

    def query(self, query, history=[]):
        try:
            return self._handle(query)
        except UnhandledQuery:
            history = history + [self.url]
            if len(history) >= MAX_HISTORY_LENGTH: raise
            return self._broadcast(query, history)

    def hello(self, other):
        self.known.add(other)
        return 0

    def fetch(self, query, secret):
        """找到并下载资源"""
        if secret != self.secret: raise AccessDenied
        result = self.query(query)
        f = open(join(self.dirname, query), 'wb')
        f.write(result.data)
        f.close()
        return 0

    def _start(self):
        #启动XML_RPC服务器
        s = SimpleXMLRPCServer(("", getPort(self.url)), logRequests=False)
        s.register_instance(self)
        s.serve_forever()
            

    def _handle(self, query):
        """处理请求"""
        name = join(self.dirname, query)
        if not isfile(name): raise UnhandledQuery
        if not inside(self.dirname, name): raise AccessDenied
        return xmlrpclib.Binary(open(name, 'rb').read())

    def _broadcast(self, query, history):
        """将查询广播到所有已知的Node"""
        for other in self.known.copy():
            if other in history: continue
            try:
                s = ServerProxy(other)
                return s.query(query, history)
                
            except Fault, f:
                if f.faultCode == UNHANDLED: pass
                else: self.known.remove(other)
            except:
                self.known.remove(other)
        raise UnhandledQuery

def main():
    url, directory, secret = sys.argv[1:]
    n = Node(url, directory, secret)
    n._start()

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt: sys.exit()