Plotting federated instances

main
Bob Mottram 2020-07-08 13:28:41 +01:00
parent b1516507f8
commit 7b06a3b262
4 changed files with 137 additions and 15 deletions

View File

@ -144,6 +144,15 @@ To list the domains referenced in public posts:
python3 epicyon.py --postDomains nickname@domain
```
## Plotting federated instances
To plot a set of federated instances, based upon a sample of handles on those instances:
``` bash
python3 epicyon.py --socnet nickname1@domain1,nickname2@domain2,nickname3@domain3
xdot socnet.dot
```
## Delete posts
To delete a post which you wrote you must first know its url. It is usually something like:

View File

@ -67,6 +67,7 @@ from shares import sendUndoShareViaServer
from shares import addShare
from theme import setTheme
from announce import sendAnnounceViaServer
from socnet import instancesGraph
import argparse
@ -151,6 +152,10 @@ parser.add_argument('--postDomains', dest='postDomains', type=str,
default=None,
help='Show domains referenced in public '
'posts for the given handle')
parser.add_argument('--socnet', dest='socnet', type=str,
default=None,
help='Show dot diagram for social network '
'of federated instances')
parser.add_argument('--postsraw', dest='postsraw', type=str,
default=None,
help='Show raw json of posts for the given handle')
@ -449,13 +454,35 @@ if args.postDomains:
elif args.gnunet:
proxyType = 'gnunet'
domainList = []
domainList = getPublicPostDomains(baseDir, nickname, domain, False, True,
proxyType, args.port, httpPrefix, debug,
domainList = getPublicPostDomains(baseDir, nickname, domain,
proxyType, args.port,
httpPrefix, debug,
__version__, domainList)
for postDomain in domainList:
print(postDomain)
sys.exit()
if args.socnet:
if ',' not in args.socnet:
print('Syntax: '
'--socnet nick1@domain1,nick2@domain2,nick3@domain3')
sys.exit()
if not args.http:
args.port = 443
proxyType = 'tor'
dotGraph = instancesGraph(baseDir, args.socnet,
proxyType, args.port,
httpPrefix, debug,
__version__)
try:
with open('socnet.dot', 'w') as fp:
fp.write(dotGraph)
print('Saved to socnet.dot')
except BaseException:
pass
sys.exit()
if args.postsraw:
if '@' not in args.postsraw:
print('Syntax: --postsraw nickname@domain')

View File

@ -146,11 +146,14 @@ def getUserUrl(wfRequest: {}) -> str:
def parseUserFeed(session, feedUrl: str, asHeader: {},
projectVersion: str, httpPrefix: str,
domain: str) -> None:
domain: str,depth=0) -> {}:
if depth > 10:
return None
feedJson = getJson(session, feedUrl, asHeader, None,
projectVersion, httpPrefix, domain)
if not feedJson:
return
return None
if 'orderedItems' in feedJson:
for item in feedJson['orderedItems']:
@ -168,9 +171,10 @@ def parseUserFeed(session, feedUrl: str, asHeader: {},
userFeed = \
parseUserFeed(session, nextUrl, asHeader,
projectVersion, httpPrefix,
domain)
for item in userFeed:
yield item
domain, depth+1)
if userFeed:
for item in userFeed:
yield item
elif isinstance(nextUrl, dict):
userFeed = nextUrl
if userFeed.get('orderedItems'):
@ -444,8 +448,8 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int,
maxMentions: int,
maxEmoji: int, maxAttachments: int,
federationList: [],
personCache: {}, raw: bool,
simple: bool, debug: bool,
personCache: {},
debug: bool,
projectVersion: str, httpPrefix: str,
domain: str, domainList=[]) -> []:
"""Returns a list of domains referenced within public posts
@ -467,6 +471,9 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int,
userFeed = parseUserFeed(session, outboxUrl, asHeader,
projectVersion, httpPrefix, domain)
for item in userFeed:
i += 1
if i > maxPosts:
break
if not item.get('object'):
continue
if not isinstance(item['object'], dict):
@ -486,9 +493,6 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int,
getDomainFromActor(tagItem['href'])
if postDomain not in postDomains:
postDomains.append(postDomain)
i += 1
if i == maxPosts:
break
return postDomains
@ -2986,8 +2990,7 @@ def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str,
def getPublicPostDomains(baseDir: str, nickname: str, domain: str,
raw: bool, simple: bool, proxyType: str,
port: int, httpPrefix: str,
proxyType: str, port: int, httpPrefix: str,
debug: bool, projectVersion: str,
domainList=[]) -> []:
""" Returns a list of domains referenced within public posts
@ -3028,7 +3031,7 @@ def getPublicPostDomains(baseDir: str, nickname: str, domain: str,
postDomains = \
getPostDomains(session, personUrl, 64, maxMentions, maxEmoji,
maxAttachments, federationList,
personCache, raw, simple, debug,
personCache, debug,
projectVersion, httpPrefix, domain, domainList)
postDomains.sort()
return postDomains

83
socnet.py 100644
View File

@ -0,0 +1,83 @@
__filename__ = "socnet.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.1.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
from session import createSession
from webfinger import webfingerHandle
from posts import getPersonBox
from posts import getPostDomains
def instancesGraph(baseDir: str, handles: str,
proxyType: str,
port: int, httpPrefix: str,
debug: bool, projectVersion: str) -> str:
""" Returns a dot graph of federating instances
based upon a few sample handles.
The handles argument should contain a comma separated list
of handles on different instances
"""
dotGraphStr = 'digraph instances {\n'
if ',' not in handles:
return dotGraphStr + '}\n'
session = createSession(proxyType)
if not session:
return dotGraphStr + '}\n'
personCache = {}
cachedWebfingers = {}
federationList = []
maxMentions = 99
maxEmoji = 99
maxAttachments = 5
personHandles = handles.split(',')
for handle in personHandles:
handle = handle.strip()
if handle.startswith('@'):
handle = handle[1:]
if '@' not in handle:
continue
nickname = handle.split('@')[0]
domain = handle.split('@')[1]
domainFull = domain
if port:
if port != 80 and port != 443:
if ':' not in domain:
domainFull = domain + ':' + str(port)
handle = httpPrefix + "://" + domainFull + "/@" + nickname
wfRequest = \
webfingerHandle(session, handle, httpPrefix,
cachedWebfingers,
domain, projectVersion)
if not wfRequest:
return dotGraphStr + '}\n'
if not isinstance(wfRequest, dict):
print('Webfinger for ' + handle + ' did not return a dict. ' +
str(wfRequest))
return dotGraphStr + '}\n'
(personUrl, pubKeyId, pubKey,
personId, shaedInbox,
capabilityAcquisition,
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
personCache,
projectVersion, httpPrefix,
nickname, domain, 'outbox')
postDomains = \
getPostDomains(session, personUrl, 64, maxMentions, maxEmoji,
maxAttachments, federationList,
personCache, debug,
projectVersion, httpPrefix, domain, [])
postDomains.sort()
for fedDomain in postDomains:
dotLineStr = ' "' + domain + '" -> "' + fedDomain + '";\n'
if dotLineStr not in dotGraphStr:
dotGraphStr += dotLineStr
return dotGraphStr + '}\n'