From 547aa08b1f05ec0cdf725c34a7b1d1512b694063 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Thu, 8 Dec 2022 16:35:20 +0100 Subject: remaining essentials: uuid, errors --- bsfs/utils/uuid.py | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 bsfs/utils/uuid.py (limited to 'bsfs/utils/uuid.py') diff --git a/bsfs/utils/uuid.py b/bsfs/utils/uuid.py new file mode 100644 index 0000000..7c39128 --- /dev/null +++ b/bsfs/utils/uuid.py @@ -0,0 +1,108 @@ +""" + +Part of the BlackStar filesystem (bsfs) module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +from collections import abc +import hashlib +import os +import platform +import random +import threading +import time +import typing +import uuid + +# constants +HASH = hashlib.sha256 + +# exports +__all__: typing.Sequence[str] = [ + 'UCID', + 'UUID', + ] + + +## code ## + +class UUID(abc.Iterator, abc.Callable): + """Generate 256-bit universally unique IDs. + + This is a 'best-effort' kind of implementation that tries to ensure global + uniqueness, even tough actual uniqueness cannot be guaranteed. + The approach is different from python's uuid module (which implements + RFC 4122) in that it generates longer UUIDs and in that it cannot be + reconstructed whether two UUIDs were generated on the same system. + + The ID is a cryptographic hash over several components: + * host + * system + * process + * thread + * random + * time + * cpu cycles + * content (if available) + + """ + + # host identifier + host: str + + # system identifier + system: str + + # process identifier + process: str + + # thread identifier + thread: str + + def __init__(self, seed: typing.Optional[int] = None): + # initialize static components + self.host = str(uuid.getnode()) + self.system = '-'.join(platform.uname()) + self.process = str(os.getpid()) + self.thread = str(threading.get_ident()) + # initialize random component + random.seed(seed) + + def __call__(self, content: typing.Optional[str] = None) -> str: + """Return a globally unique ID.""" + # content component + content = str(content) if content is not None else '' + # time component + now = str(time.time()) + # clock component + clk = str(time.perf_counter()) + # random component + rnd = str(random.random()) + # build the token from all available components + token = self.host + self.system + self.process + self.thread + rnd + now + clk + content + # return the token's hash + return HASH(token.encode('ascii', 'ignore')).hexdigest() + + def __iter__(self) -> typing.Iterator[str]: + """Iterate indefinitely over universally unique IDs.""" + return self + + def __next__(self) -> str: + """Generate universally unique IDs.""" + return self() + + +class UCID(abc.Callable): + """Generate 256-bit content IDs. + + Effectively computes a cryptographic hash over the content. + + """ + @staticmethod + def from_path(path: str) -> str: + """Read the content from a file.""" + with open(path, 'rb') as ifile: + return HASH(ifile.read()).hexdigest() + +## EOF ## -- cgit v1.2.3 From 21a02197d73f263ae222f2ccc49248d8617e2d7d Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sun, 18 Dec 2022 13:40:49 +0100 Subject: project cosmetics --- bsfs/utils/uuid.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bsfs/utils/uuid.py') diff --git a/bsfs/utils/uuid.py b/bsfs/utils/uuid.py index 7c39128..6366b18 100644 --- a/bsfs/utils/uuid.py +++ b/bsfs/utils/uuid.py @@ -27,7 +27,7 @@ __all__: typing.Sequence[str] = [ ## code ## -class UUID(abc.Iterator, abc.Callable): +class UUID(abc.Iterator, abc.Callable): # type: ignore [misc] # abc.Callable "is an invalid base class" """Generate 256-bit universally unique IDs. This is a 'best-effort' kind of implementation that tries to ensure global @@ -69,7 +69,7 @@ class UUID(abc.Iterator, abc.Callable): # initialize random component random.seed(seed) - def __call__(self, content: typing.Optional[str] = None) -> str: + def __call__(self, content: typing.Optional[str] = None) -> str: # pylint: disable=arguments-differ """Return a globally unique ID.""" # content component content = str(content) if content is not None else '' @@ -93,7 +93,7 @@ class UUID(abc.Iterator, abc.Callable): return self() -class UCID(abc.Callable): +class UCID(): """Generate 256-bit content IDs. Effectively computes a cryptographic hash over the content. -- cgit v1.2.3