Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
at main 100 lines 3.9 kB view raw
1import time 2import sqlite3 3import random 4import atexit 5 6import gevent 7from Plugin import PluginManager 8 9 10@PluginManager.registerTo("ContentDb") 11class ContentDbPlugin(object): 12 def __init__(self, *args, **kwargs): 13 atexit.register(self.saveAllPeers) 14 super(ContentDbPlugin, self).__init__(*args, **kwargs) 15 16 def getSchema(self): 17 schema = super(ContentDbPlugin, self).getSchema() 18 19 schema["tables"]["peer"] = { 20 "cols": [ 21 ["site_id", "INTEGER REFERENCES site (site_id) ON DELETE CASCADE"], 22 ["address", "TEXT NOT NULL"], 23 ["port", "INTEGER NOT NULL"], 24 ["hashfield", "BLOB"], 25 ["reputation", "INTEGER NOT NULL"], 26 ["time_added", "INTEGER NOT NULL"], 27 ["time_found", "INTEGER NOT NULL"] 28 ], 29 "indexes": [ 30 "CREATE UNIQUE INDEX peer_key ON peer (site_id, address, port)" 31 ], 32 "schema_changed": 2 33 } 34 35 return schema 36 37 def loadPeers(self, site): 38 s = time.time() 39 site_id = self.site_ids.get(site.address) 40 res = self.execute("SELECT * FROM peer WHERE site_id = :site_id", {"site_id": site_id}) 41 num = 0 42 num_hashfield = 0 43 for row in res: 44 peer = site.addPeer(str(row["address"]), row["port"]) 45 if not peer: # Already exist 46 continue 47 if row["hashfield"]: 48 peer.hashfield.replaceFromBytes(row["hashfield"]) 49 num_hashfield += 1 50 peer.time_added = row["time_added"] 51 peer.time_found = row["time_found"] 52 peer.reputation = row["reputation"] 53 if row["address"].endswith(".onion"): 54 peer.reputation = peer.reputation / 2 - 1 # Onion peers less likely working 55 num += 1 56 if num_hashfield: 57 site.content_manager.has_optional_files = True 58 site.log.debug("%s peers (%s with hashfield) loaded in %.3fs" % (num, num_hashfield, time.time() - s)) 59 60 def iteratePeers(self, site): 61 site_id = self.site_ids.get(site.address) 62 for key, peer in list(site.peers.items()): 63 address, port = key.rsplit(":", 1) 64 if peer.has_hashfield: 65 hashfield = sqlite3.Binary(peer.hashfield.tobytes()) 66 else: 67 hashfield = "" 68 yield (site_id, address, port, hashfield, peer.reputation, int(peer.time_added), int(peer.time_found)) 69 70 def savePeers(self, site, spawn=False): 71 if spawn: 72 # Save peers every hour (+random some secs to not update very site at same time) 73 site.greenlet_manager.spawnLater(60 * 60 + random.randint(0, 60), self.savePeers, site, spawn=True) 74 if not site.peers: 75 site.log.debug("Peers not saved: No peers found") 76 return 77 s = time.time() 78 site_id = self.site_ids.get(site.address) 79 cur = self.getCursor() 80 try: 81 cur.execute("DELETE FROM peer WHERE site_id = :site_id", {"site_id": site_id}) 82 cur.executemany( 83 "INSERT INTO peer (site_id, address, port, hashfield, reputation, time_added, time_found) VALUES (?, ?, ?, ?, ?, ?, ?)", 84 self.iteratePeers(site) 85 ) 86 except Exception as err: 87 site.log.error("Save peer error: %s" % err) 88 site.log.debug("Peers saved in %.3fs" % (time.time() - s)) 89 90 def initSite(self, site): 91 super(ContentDbPlugin, self).initSite(site) 92 site.greenlet_manager.spawnLater(0.5, self.loadPeers, site) 93 site.greenlet_manager.spawnLater(60*60, self.savePeers, site, spawn=True) 94 95 def saveAllPeers(self): 96 for site in list(self.sites.values()): 97 try: 98 self.savePeers(site) 99 except Exception as err: 100 site.log.error("Save peer error: %s" % err)