commit 452035fba633b71198cb3c1529704345a9275c04
parent 01f614ede0eb194c85ace7d1adce97f9aba63cd2
Author: lash <dev@holbrook.no>
Date: Sun, 15 Feb 2026 00:12:59 +0000
Add docs for resolver
Diffstat:
2 files changed, 88 insertions(+), 7 deletions(-)
diff --git a/dummy/usawa/resolve/base.py b/dummy/usawa/resolve/base.py
@@ -5,11 +5,22 @@ import hexathon
from usawa.error import VerifyError
+"""Verifies a key as a sha512 digest, optionally against the given value.
+
+:param k: Key to check.
+:type k: bytes or hex string
+:param v: Value to check against key.
+:type v: bytes
+:raises ValueError: Invalid key (not 512 bits)
+:raises VerifyError: Value digest does not match key.
+:return: Key as hex string
+:rtype: str
+"""
def sha512_verify(k, v=None):
if isinstance(k, str):
k = bytes.fromhex(k)
if len(k) != 64:
- raise ValueError('expect 512 bit key')
+ raise ValueError('expect 512 bit key')
khx = hexathon.uniform(k.hex())
if v != None:
h = hashlib.sha512()
@@ -21,13 +32,61 @@ def sha512_verify(k, v=None):
class BaseResolver:
- def get(self, k, v, verifier=None):
+ """A resolver abstracts an immutable store used for storing asset data.
+
+ Key/value pairs put to the store are checked by the verifier function before submission. Similarly, the value retrieved is checked by the verifier against the key used to get it.
+
+ :raises IOError: Resolver backend unavailable, temporarily or permanently.
+ :param verifier: Verifier function for checking keys and key/value relation.
+ :type verifier: function, by default usawa.resolve.sha512_verify
+ """
+ def __init__(self, verifier=sha512_verify):
+ self.verifier = verifier
+
+
+ """Get value for key.
+
+ :param k: Key
+ :type k: bytes or hex string
+ :raises FileNotFoundError: Key does not exist.
+ :raises PermissionError: No access to data.
+ :raises IOError: Any other read problem.
+ :return: Value
+ :rtype: bytes
+ """
+ def get(self, k):
raise NotImplementedError()
+ """Put value under key.
- def put(self, k):
+ Value may not be available immediately after method returns, since the implementation may store asynchronously.
+
+ :param k: Key
+ :type k: bytes or hex string
+ :param v: Value
+ :type v: bytes
+ :raises FileExistsError: Key exists.
+ :raises PermissionError: No access to data.
+ :raises IOError: Any other read problem.
+ :return: A textual representation of the key
+ :rtype: str
+ """
+ def put(self, k, v):
raise NotImplementedError()
- def delete(self, k):
+ """Check availability of data without invoking a full get call.
+
+ If -1 is returned, the key does not exist.
+
+ If 0 is returned, the key has been added but may not yet be available for a get() call.
+
+ If a value greater than 0 is returned, get() can safely be called.
+
+ :param k: Key to check state for
+ :type k: bytes or hex string
+ :return: storage state
+ :rtype: int
+ """
+ def state(self, k):
raise NotImplementedError()
diff --git a/dummy/usawa/resolve/fs.py b/dummy/usawa/resolve/fs.py
@@ -4,7 +4,7 @@ import logging
from .base import BaseResolver, sha512_verify
from usawa.error import VerifyError
-logg = logging.getLogger('usawa.fsresolver')
+logg = logging.getLogger('usawa.resolve.fs')
def normalize_keyname(k):
@@ -17,12 +17,23 @@ def normalize_keyname(k):
class FSResolver(BaseResolver):
+ """Resolver implementation for a filesystem directory.
+
+ If directory does not exist it will be created, along with any necessary ascendants.
+
+ :param path: Path to directory to store under.
+ :type path: str
+ :raises PermissionError: Insufficient access to create directory.
+ :seealso: usawa.resolve.BaseResolver
+ """
def __init__(self, path, verifier=sha512_verify):
+ super(FSResolver, self).__init__(verifier=verifier)
self.path = os.path.realpath(path)
- self.verifier = verifier
os.makedirs(self.path, exist_ok=True)
+ """Implements usawa.resolve.BaseResolver
+ """
def get(self, k):
khx = self.verifier(k)
fp = os.path.join(self.path, khx)
@@ -34,6 +45,8 @@ class FSResolver(BaseResolver):
return v
+ """Implements usawa.resolve.BaseResolver
+ """
def put(self, k, v):
khx = self.verifier(k, v=v)
fp = os.path.join(self.path, khx)
@@ -41,4 +54,13 @@ class FSResolver(BaseResolver):
c = f.write(v)
logg.debug('{} bytes written for key {}'.format(c, k))
f.close()
- return v
+ return k
+
+
+ """Implements usawa.resolve.BaseResolver
+ """
+ def have(self, k):
+ r = -1
+ if os.path.is_file():
+ r = 1
+ return r