Move webfinger cache

master
Bob Mottram 2019-06-30 16:03:26 +01:00
parent 4b68f1b437
commit ff338e4de2
5 changed files with 103 additions and 43 deletions

39
cache.py 100644
View File

@ -0,0 +1,39 @@
__filename__ = "cache.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "0.0.1"
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
# cache of actor json
# If there are repeated lookups then this helps prevent a lot
# of needless network traffic
personCache = {}
# cached webfinger endpoints
cachedWebfingers = {}
def storePersonInCache(personUrl: str,personJson) -> None:
"""Store an actor in the cache
"""
personCache[personUrl]=personJson
def storeWebfingerInCache(handle: str,wf) -> None:
"""Store a webfinger endpoint in the cache
"""
cachedWebfingers[handle]=wf
def getPersonFromCache(personUrl: str):
"""Get an actor from the cache
"""
if personCache.get(personUrl):
return personCache[personUrl]
return None
def getWebfingerFromCache(handle: str):
"""Get webfinger endpoint from the cache
"""
if cachedWebfingers.get(handle):
return cachedWebfingers[handle]
return None

View File

@ -137,10 +137,10 @@ class PubServer(BaseHTTPRequestHandler):
self.wfile.write(json.dumps(getPerson).encode('utf-8')) self.wfile.write(json.dumps(getPerson).encode('utf-8'))
self.GETbusy=False self.GETbusy=False
return return
getPersonKey = personKeyLookup(thisDomain,self.path) personKey = personKeyLookup(thisDomain,self.path)
if getPersonKey: if personKey:
self._set_headers('text/html; charset=utf-8') self._set_headers('text/html; charset=utf-8')
self.wfile.write(getPersonKey.encode('utf-8')) self.wfile.write(personKey.encode('utf-8'))
self.GETbusy=False self.GETbusy=False
return return
# check that a json file was requested # check that a json file was requested

View File

@ -15,34 +15,6 @@ from webfinger import createWebfingerEndpoint
from webfinger import storeWebfingerEndpoint from webfinger import storeWebfingerEndpoint
from posts import createOutbox from posts import createOutbox
# cache of actor json
# If there are repeated lookups then this helps prevent a lot
# of needless network traffic
personCache = {}
def storePersonInCache(personUrl: str,personJson) -> None:
personCache[personUrl]=personJson
def getPersonFromCache(personUrl: str):
if personCache.get(personUrl):
return personCache[personUrl]
return None
def getPersonKey(username: str,domain: str,keyType='public'):
"""Returns the public or private key of a person
"""
handle=username+'@'+domain
baseDir=os.getcwd()
keyFilename=baseDir+'/keys/'+keyType+'/'+handle.lower()+'.key'
if not os.path.isfile(keyFilename):
return ''
keyPem=''
with open(keyFilename, "r") as pemFile:
keyPem=pemFile.read()
if len(keyPem)<20:
return ''
return keyPem
def generateRSAKey() -> (str,str): def generateRSAKey() -> (str,str):
key = RSA.generate(2048) key = RSA.generate(2048)
privateKeyPem = key.exportKey("PEM").decode("utf-8") privateKeyPem = key.exportKey("PEM").decode("utf-8")

View File

@ -11,15 +11,17 @@ import json
import commentjson import commentjson
import html import html
import datetime import datetime
import os, shutil import os
import shutil
import threading import threading
import sys
import trace
from cache import storePersonInCache
from cache import getPersonFromCache
from pprint import pprint from pprint import pprint
from random import randint from random import randint
from session import getJson from session import getJson
from session import postJson from session import postJson
from person import getPersonFromCache
from person import storePersonInCache
from person import getPersonKey
try: try:
from BeautifulSoup import BeautifulSoup from BeautifulSoup import BeautifulSoup
except ImportError: except ImportError:
@ -31,6 +33,51 @@ sendThreads = []
# stores the results from recent post sending attempts # stores the results from recent post sending attempts
postLog = [] postLog = []
class threadWithTrace(threading.Thread):
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
self.__run_backup = self.run
self.run = self.__run
threading.Thread.start(self)
def __run(self):
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, event, arg):
if event == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, event, arg):
if self.killed:
if event == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
self.killed = True
def getPersonKey(username: str,domain: str,keyType='public'):
"""Returns the public or private key of a person
"""
handle=username+'@'+domain
baseDir=os.getcwd()
keyFilename=baseDir+'/keys/'+keyType+'/'+handle.lower()+'.key'
if not os.path.isfile(keyFilename):
return ''
keyPem=''
with open(keyFilename, "r") as pemFile:
keyPem=pemFile.read()
if len(keyPem)<20:
return ''
return keyPem
def permitted(url: str,federationList) -> bool: def permitted(url: str,federationList) -> bool:
"""Is a url from one of the permitted domains? """Is a url from one of the permitted domains?
""" """
@ -74,7 +121,7 @@ def getPersonBox(session,wfRequest,boxName='inbox'):
personUrl = getUserUrl(wfRequest) personUrl = getUserUrl(wfRequest)
if not personUrl: if not personUrl:
return None return None
personJson=getPersonFromCache(personUrl) personJson = getPersonFromCache(personUrl)
if not personJson: if not personJson:
personJson = getJson(session,personUrl,asHeader,None) personJson = getJson(session,personUrl,asHeader,None)
if not personJson.get(boxName): if not personJson.get(boxName):
@ -307,7 +354,7 @@ def threadSendPost(session,postJsonObject,federationList,inboxUrl: str,signature
tries=0 tries=0
backoffTime=60 backoffTime=60
for attempt in range(20): for attempt in range(20):
postResult = postJson(session,postJsonObject,federationList,inboxUrl,signatureHeader): postResult = postJson(session,postJsonObject,federationList,inboxUrl,signatureHeader)
if postResult: if postResult:
postLog.append(postJsonObject['published']+' '+postResult+'\n') postLog.append(postJsonObject['published']+' '+postResult+'\n')
# keep the length of the log finite # keep the length of the log finite
@ -358,9 +405,9 @@ def sendPost(session,username: str, domain: str, toUsername: str, toDomain: str,
# Keep the number of threads being used small # Keep the number of threads being used small
while len(sendThreads)>10: while len(sendThreads)>10:
sendThreads[0].stop() sendThreads[0].kill()
sendThreads.pop(0) sendThreads.pop(0)
thr = threading.Thread(target=threadSendPost,args=(session,postJsonObject.copy(),federationList,inboxUrl,signatureHeader.copy()),daemon=True) thr = threadWithTrace(target=threadSendPost,args=(session,postJsonObject.copy(),federationList,inboxUrl,signatureHeader.copy()),daemon=True)
sendThreads.append(thr) sendThreads.append(thr)
thr.start() thr.start()
return 0 return 0

View File

@ -14,6 +14,8 @@ import json
import commentjson import commentjson
import os import os
from session import getJson from session import getJson
from cache import storeWebfingerInCache
from cache import getWebfingerFromCache
def parseHandle(handle): def parseHandle(handle):
if '.' not in handle: if '.' not in handle:
@ -31,14 +33,14 @@ def parseHandle(handle):
return username, domain return username, domain
cachedWebfingers = {}
def webfingerHandle(session,handle: str,https: bool): def webfingerHandle(session,handle: str,https: bool):
username, domain = parseHandle(handle) username, domain = parseHandle(handle)
if not username: if not username:
return None return None
if cachedWebfingers.get(username+'@'+domain): wf=getWebfingerFromCache(username+'@'+domain)
return cachedWebfingers[username+'@'+domain] if wf:
return wf
prefix='https' prefix='https'
if not https: if not https:
prefix='http' prefix='http'
@ -50,7 +52,7 @@ def webfingerHandle(session,handle: str,https: bool):
#except: #except:
# print("Unable to webfinger " + url) # print("Unable to webfinger " + url)
# return None # return None
cachedWebfingers[username+'@'+domain] = result storeWebfingerInCache(username+'@'+domain, result)
return result return result
def generateMagicKey(publicKeyPem): def generateMagicKey(publicKeyPem):