(Steve Dougherty)
2013-06-25: Add more work on freenet:// path resolution for WoT. Add more work on freenet:// path resolution for WoT.
diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py --- a/infocalypse/__init__.py +++ b/infocalypse/__init__.py @@ -554,6 +554,13 @@ extensions.wrapfunction(discovery, 'find def freenetpathtouri(ui, path, pull=True): + """ + Return a usable request or insert URI. Expects a freenet:// or freenet: + protocol to be specified. + + If the key is not a USK it will be resolved as a WoT identity. In this + case if the resolution fails, print an error message and return None. + """ # TODO: Is this the only URL encoding that may happen? Why not use a more # semantically meaningful function? path = path.replace("%7E", "~").replace("%2C", ",") @@ -632,6 +639,8 @@ def freenetpush(orig, *args, **opts): if not isfreenetpath(path): return orig(*args, **opts) uri = freenetpathtouri(ui, path, pull=False) + if uri is None: + return # if the uri is the short form (USK@/name/#), generate the key and preprocess the uri. if uri.startswith("USK@/"): ui.status("creating a new key for the repo. For a new repo with an existing key, use clone.\n") diff --git a/infocalypse/keys.py b/infocalypse/keys.py new file mode 100644 --- /dev/null +++ b/infocalypse/keys.py @@ -0,0 +1,15 @@ +from string import split + + +class USK: + def __init__(self, path): + components = split(path, '/') + # Expecting USK@key/name/edition + assert len(components) == 3 + + self.key = components[0] + self.name = components[1] + self.edition = components[2] + + def __str__(self): + return self.key + '/' + self.name + '/' + self.edition \ No newline at end of file diff --git a/infocalypse/wot.py b/infocalypse/wot.py --- a/infocalypse/wot.py +++ b/infocalypse/wot.py @@ -6,6 +6,7 @@ from defusedxml.ElementTree import froms import smtplib from base64 import b32encode from fcp.node import base64decode +from keys import USK def send_pull_request(ui, from_identity, to_identity): @@ -67,10 +68,31 @@ def update_repo_listing(ui, for_identity ui.status("Updated repository listing:\n{0}\n".format(uri)) +def find_repo(ui, truster, wot_identifier, repo_name): + """ + Return a request URI for a repo of the given name published by an + identity matching the given identifier. + Print an error message and return None on failure. + """ + listing = read_repo_listing(ui, truster, wot_identifier) + + if listing is None: + return + + if repo_name not in listing: + # TODO: Perhaps resolve again; print full nick / key? + # TODO: Maybe print key found in the resolve_*identity? + ui.warn("{0} does not publish a repo named '{1}'\n".format( + wot_identifier, repo_name)) + return + + return listing[repo_name] + + def read_repo_listing(ui, truster, wot_identifier): """ Read a repo listing for a given identity. - Return a dictionary of repository URIs keyed by name. + Return a dictionary of repository request URIs keyed by name. """ identity = resolve_identity(ui, truster, wot_identifier) if identity is None: @@ -85,6 +107,8 @@ def read_repo_listing(ui, truster, wot_i # TODO: Set and read vcs edition property. node = fcp.FCPNode() ui.status("Fetching {0}\n".format(uri)) + # TODO: What exception can this throw on failure? Catch it, + # print its description, and return None. mime_type, repo_xml, msg = node.get(uri, priority=1) ui.status("Parsing.\n") @@ -121,17 +145,7 @@ def resolve_pull_uri(ui, path, truster): # TODO: How to handle redundancy? Does Infocalypse automatically try # an R0 if an R1 fails? - repositories = read_repo_listing(ui, truster, wot_id) - - if repositories is None: - return - - if repo_name not in repositories: - ui.warn("Could not find repository named \"{0}\".\n" - .format(repo_name)) - return - - return repositories[repo_name] + return find_repo(ui, truster, wot_id, repo_name) def resolve_push_uri(ui, path): @@ -140,17 +154,34 @@ def resolve_push_uri(ui, path): Print an error message and return None on failure. :param ui: For feedback. - :param path: path describing a repo: nick@key/reponame, + :param path: path describing a repo - nick@key/repo_name, where the identity is a local one. (Such that the insert URI is known.) """ - # Expecting <id stuff>/reponame - # TODO: Duplcate with resolve_pull + # Expecting <id stuff>/repo_name + # TODO: Duplicate with resolve_pull wot_id, repo_name = path.split('/', 1) - local_id = resolve_local_identity(ui, ) + local_id = resolve_local_identity(ui, wot_id) - # Get edition by checking one's own repo list. - repositories = read_repo_listing(ui, ) + if local_id is None: + return + + insert_uri = USK(local_id['InsertURI']) + + identifier = local_id['Nickname'] + '@' + local_id['Identity'] + + repo = find_repo(ui, local_id['Identity'], identifier, repo_name) + + if repo is None: + return + + # Request URI + repo_uri = USK(repo) + + # Maintains path, edition. + repo_uri.key = insert_uri.key + + return str(repo_uri) # Support for querying WoT for own identities and identities meeting various # criteria.