SiteManagerPlugin.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import logging, json, os, re, sys, time
  2. import gevent
  3. from Plugin import PluginManager
  4. from Config import config
  5. from util import Http
  6. from Debug import Debug
  7. allow_reload = False # No reload supported
  8. log = logging.getLogger("DnschainPlugin")
  9. @PluginManager.registerTo("SiteManager")
  10. class SiteManagerPlugin(object):
  11. dns_cache_path = "%s/dns_cache.json" % config.data_dir
  12. dns_cache = None
  13. # Checks if its a valid address
  14. def isAddress(self, address):
  15. if self.isDomain(address):
  16. return True
  17. else:
  18. return super(SiteManagerPlugin, self).isAddress(address)
  19. # Return: True if the address is domain
  20. def isDomain(self, address):
  21. return re.match(r"(.*?)([A-Za-z0-9_-]+\.[A-Za-z0-9]+)$", address)
  22. # Load dns entries from data/dns_cache.json
  23. def loadDnsCache(self):
  24. if os.path.isfile(self.dns_cache_path):
  25. self.dns_cache = json.load(open(self.dns_cache_path))
  26. else:
  27. self.dns_cache = {}
  28. log.debug("Loaded dns cache, entries: %s" % len(self.dns_cache))
  29. # Save dns entries to data/dns_cache.json
  30. def saveDnsCache(self):
  31. json.dump(self.dns_cache, open(self.dns_cache_path, "wb"), indent=2)
  32. # Resolve domain using dnschain.net
  33. # Return: The address or None
  34. def resolveDomainDnschainNet(self, domain):
  35. try:
  36. match = self.isDomain(domain)
  37. sub_domain = match.group(1).strip(".")
  38. top_domain = match.group(2)
  39. if not sub_domain: sub_domain = "@"
  40. address = None
  41. with gevent.Timeout(5, Exception("Timeout: 5s")):
  42. res = Http.get("https://api.dnschain.net/v1/namecoin/key/%s" % top_domain).read()
  43. data = json.loads(res)["data"]["value"]
  44. if "zeronet" in data:
  45. for key, val in data["zeronet"].items():
  46. self.dns_cache[key+"."+top_domain] = [val, time.time()+60*60*5] # Cache for 5 hours
  47. self.saveDnsCache()
  48. return data["zeronet"].get(sub_domain)
  49. # Not found
  50. return address
  51. except Exception as err:
  52. log.debug("Dnschain.net %s resolve error: %s" % (domain, Debug.formatException(err)))
  53. # Resolve domain using dnschain.info
  54. # Return: The address or None
  55. def resolveDomainDnschainInfo(self, domain):
  56. try:
  57. match = self.isDomain(domain)
  58. sub_domain = match.group(1).strip(".")
  59. top_domain = match.group(2)
  60. if not sub_domain: sub_domain = "@"
  61. address = None
  62. with gevent.Timeout(5, Exception("Timeout: 5s")):
  63. res = Http.get("https://dnschain.info/bit/d/%s" % re.sub(r"\.bit$", "", top_domain)).read()
  64. data = json.loads(res)["value"]
  65. for key, val in data["zeronet"].items():
  66. self.dns_cache[key+"."+top_domain] = [val, time.time()+60*60*5] # Cache for 5 hours
  67. self.saveDnsCache()
  68. return data["zeronet"].get(sub_domain)
  69. # Not found
  70. return address
  71. except Exception as err:
  72. log.debug("Dnschain.info %s resolve error: %s" % (domain, Debug.formatException(err)))
  73. # Resolve domain
  74. # Return: The address or None
  75. def resolveDomain(self, domain):
  76. domain = domain.lower()
  77. if self.dns_cache == None:
  78. self.loadDnsCache()
  79. if domain.count(".") < 2: # Its a topleved request, prepend @. to it
  80. domain = "@."+domain
  81. domain_details = self.dns_cache.get(domain)
  82. if domain_details and time.time() < domain_details[1]: # Found in cache and its not expired
  83. return domain_details[0]
  84. else:
  85. # Resovle dns using dnschain
  86. thread_dnschain_info = gevent.spawn(self.resolveDomainDnschainInfo, domain)
  87. thread_dnschain_net = gevent.spawn(self.resolveDomainDnschainNet, domain)
  88. gevent.joinall([thread_dnschain_net, thread_dnschain_info]) # Wait for finish
  89. if thread_dnschain_info.value and thread_dnschain_net.value: # Booth successfull
  90. if thread_dnschain_info.value == thread_dnschain_net.value: # Same returned value
  91. return thread_dnschain_info.value
  92. else:
  93. log.error("Dns %s missmatch: %s != %s" % (domain, thread_dnschain_info.value, thread_dnschain_net.value))
  94. # Problem during resolve
  95. if domain_details: # Resolve failed, but we have it in the cache
  96. domain_details[1] = time.time()+60*60 # Dont try again for 1 hour
  97. return domain_details[0]
  98. else: # Not found in cache
  99. self.dns_cache[domain] = [None, time.time()+60] # Don't check again for 1 min
  100. return None
  101. # Return or create site and start download site files
  102. # Return: Site or None if dns resolve failed
  103. def need(self, address, all_file=True):
  104. if self.isDomain(address): # Its looks like a domain
  105. address_resolved = self.resolveDomain(address)
  106. if address_resolved:
  107. address = address_resolved
  108. else:
  109. return None
  110. return super(SiteManagerPlugin, self).need(address, all_file)
  111. # Return: Site object or None if not found
  112. def get(self, address):
  113. if self.sites == None: # Not loaded yet
  114. self.load()
  115. if self.isDomain(address): # Its looks like a domain
  116. address_resolved = self.resolveDomain(address)
  117. if address_resolved: # Domain found
  118. site = self.sites.get(address_resolved)
  119. if site:
  120. site_domain = site.settings.get("domain")
  121. if site_domain != address:
  122. site.settings["domain"] = address
  123. else: # Domain not found
  124. site = self.sites.get(address)
  125. else: # Access by site address
  126. site = self.sites.get(address)
  127. return site