- # -*- 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()
- #该片段来自于http://www.codesnippet.cn/detail/2703201511994.html
来源: http://www.codesnippet.cn/detail/2703201511994.html