usawa

Signed, immutable accounting.
Info | Log | Files | Refs | Submodules | LICENSE

commit 17df5fecc6b6112c37d47898f2897066f19763c0
parent 2b66b8201f908eff5144c307c0014a87d05ce4ff
Author: Carlosokumu <carlosokumu254@gmail.com>
Date:   Mon,  2 Mar 2026 09:29:38 +0300

add attachment handling functionality

Diffstat:
Mdummy/usawa/storage/ledger_repository.py | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 70 insertions(+), 9 deletions(-)

diff --git a/dummy/usawa/storage/ledger_repository.py b/dummy/usawa/storage/ledger_repository.py @@ -1,16 +1,41 @@ +import hashlib import logging from typing import List +import hexathon +from usawa.asset import Asset from usawa.crypto import ACL, DemoWallet +from usawa.error import VerifyError from usawa.ledger import Ledger +from usawa.resolve.fs import FSResolver from usawa.service import UnixClient from usawa.store import LedgerStore from ..core.models import LedgerEntry from .entry_mapper import EntryMapper from whee.valkey import ValkeyStore from usawa import Ledger, DemoWallet, load +from pathlib import Path +import mimetypes + logg = logging.getLogger("storage.ledger_repository") +def sha256_verify(k, v=None): + if isinstance(k, str): + k = bytes.fromhex(k) + + if len(k) != 32: + raise ValueError('expect 256 bit key') + + khx = hexathon.uniform(k.hex()) + + if v is not None: + h = hashlib.sha256() + h.update(v) + if k != h.digest(): + raise VerifyError(khx) + + return khx + class LedgerRepository: """Repository that wraps LedgerStore and handles mapping""" @@ -20,9 +45,11 @@ class LedgerRepository: :param ledger_path: path to ledger to import :type ledger_store: usawa.LedgerStore """ - self.db = ValkeyStore('') + # self.db = ValkeyStore('') + self.db = unix_client self.client = unix_client self.ledger_path = ledger_path + self.resolver = FSResolver("./assets",verifier=sha256_verify) def _init_store(self) -> tuple[LedgerStore, Ledger, DemoWallet]: @@ -30,11 +57,12 @@ class LedgerRepository: ledger_tree = load(self.ledger_path) ledger = Ledger.from_tree(ledger_tree) store = LedgerStore(self.db, ledger) - + pk = store.get_key() wallet = DemoWallet(privatekey=pk) - logg.debug("wallet pk: %s pubk: %s", wallet.privkey().hex(), wallet.pubkey().hex()) + # store.add_key(wallet=wallet,acl=ledger.acl) + logg.debug("wallet pk: %s pubk: %s", wallet.privkey().hex(), wallet.pubkey().hex()) ledger.set_wallet(wallet) ledger.acl = ACL.from_wallet(wallet) store.load(acl=ledger.acl) @@ -47,14 +75,21 @@ class LedgerRepository: store, ledger, wallet = self._init_store() ledger.truncate() - logg.debug("serial after load : %s", ledger.serial) - entry = EntryMapper.to_entry(domain_entry, ledger=ledger) entry.sign(wallet) - logg.debug(f"Mapped entry - Serial: {entry.serial}, Parent: {entry.parent.hex()}") + logg.debug(f"Mapped entry - Serial: {entry.serial}, Parent: {entry.parent.hex()}, Attachments: {entry.attachment}") - store.add_entry(entry, update_ledger=True) + for attachment in domain_entry.attachments: + info = self.get_file_info(attachment) + asset = Asset.from_file(attachment,slug=info["slug"], description= info["description"],mimetype= info["mimetype"]) + store.add_asset(asset) + entry.attach(asset) + with open(attachment, "rb") as f: + data = f.read() + self.resolver.put(asset.get_digest(binary=True), data) + + store.add_entry(entry, update_ledger=True) ledger.truncate() ledger.sign() logg.debug("Parent digest after add_entry %s", ledger.parent.hex()) @@ -74,4 +109,30 @@ class LedgerRepository: ] except Exception as e: logg.error(f"Failed to retrieve entries: {e}") - return [] -\ No newline at end of file + return [] + + + + def get_asset_bytes(self, digest: str): + logg.debug(f"Getting asset for digest:{digest}") + return self.resolver.get(digest) + + + def get_file_info(self,file_path: str) -> dict: + path = Path(file_path) + + slug = path.stem + + mimetype, _ = mimetypes.guess_type(file_path) + + if mimetype: + kind = mimetype.split("/")[0] + description = f"{kind.capitalize()} file: {path.name}" + else: + description = f"File: {path.name}" + + return { + "slug": slug, + "description": description, + "mimetype": mimetype, + } +\ No newline at end of file