2023-03-21 06:18:26 { "input": "\n lm/lm and lm/log subpackages\n\ndiff --git a/lm/log/jsonfiles.py b/lm/log/jsonfiles.py\nnew file mode 100644\n--- /dev/null\n+++ b/lm/log/jsonfiles.py\n@@ -0,0 +1,21 @@\n+import aiofiles\n+import datetime\n+import json\n+import os\n+\n+class jsonfiles:\n+ def __init__(self, path = os.path.abspath(os.curdir), prefix = '', suffix = ''):\n+ self.path = path\n+ self.prefix = prefix\n+ self.suffix = suffix\n+ async def __aenter__(self):\n+ self.timestamp = datetime.datetime.now().isoformat()\n+ fn = os.path.join(self.path, f'{self.prefix}{self.timestamp}{self.suffix}.json')\n+ self.filectx = aiofiles.open(fn, 'w')\n+ self.file = await self.filectx.__aenter__()\n+ async def __aexit__(self, *params, **kwparams):\n+ await self.filectx.__aexit__(*params, **kwparams)\n+ async def __call__(self, **kwparams):\n+ await self.file.write(\n+ json.dumps(kwparams)\n+ )\n\n stubbed arweave log file with the example from pyarweave for reference\n\ndiff --git a/lm/log/arweaveditems.py b/lm/log/arweaveditems.py\nnew file mode 100755\n--- /dev/null\n+++ b/lm/log/arweaveditems.py\n@@ -0,0 +1,28 @@\n+#!/usr/bin/env python3\n+\n+import datetime\n+from ar import Peer, Wallet, DataItem\n+from bundlr import Node\n+\n+print('Generating a wallet ...')\n+wallet = Wallet.generate()\n+\n+print('Uploading \"Hello, world.\" ...')\n+di = DataItem(data = b'Hello, world.')\n+di.sign(wallet.rsa)\n+\n+node = Node()\n+result = node.send_tx(di.tobytes())\n+txid = result['id']\n+\n+peer = Peer()\n+\n+# bundlr used to return an expected block height but now seems to return some timestamp 2022-11\n+# communicate with bundlr for details on their api.\n+#current_block = peer.current_block()\n+#eta = current_block['timestamp'] + (result['block'] - current_block['height']) * 60 * 2\n+eta = int(result['timestamp']/1000)\n+\n+eta = datetime.datetime.fromtimestamp(eta)\n+\n+print(f'{peer.api_url}/{result[\"id\"]} timestamp={eta.isoformat()}')\n\n draft arweave logger\n\ndiff --git a/lm/log/arweaveditems.py b/lm/log/arweaveditems.py\n--- a/lm/log/arweaveditems.py\n+++ b/lm/log/arweaveditems.py\n@@ -1,28 +1,68 @@\n-#!/usr/bin/env python3\n-\n import datetime\n-from ar import Peer, Wallet, DataItem\n-from bundlr import Node\n+import asyncio\n+import urllib.parse\n+import json\n+import os\n+\n+import ar, ar.utils\n+import bundlr as bundlr_\n \n-print('Generating a wallet ...')\n-wallet = Wallet.generate()\n+class arweaveditems:\n+ def __init__(self, wallet = None, bundlr = bundlr_.DEFAULT_API_URL, gateway = 'https://arweave.net/'):\n+ self.wallet = wallet or ar.Wallet.generate()\n+ self.bundlr = bundlr\n+ self.gateway = gateway\n \n-print('Uploading \"Hello, world.\" ...')\n-di = DataItem(data = b'Hello, world.')\n-di.sign(wallet.rsa)\n+ async def __aenter__(self):\n+ self.bundlr_node = bundlf_.Node(self.bundlr)\n \n-node = Node()\n-result = node.send_tx(di.tobytes())\n-txid = result['id']\n+ async def __aexit__(self, *params, **kwparams):\n+ pass\n \n-peer = Peer()\n+ def _prep(self, data, tags = {}):\n+ if type(data) is not ar.DataItem:\n+ if type(data) is str:\n+ data = data.encode()\n+ data = ar.DataItem(data = data)\n+ data.header.tags = [ar.utils.create_tag(name, value, True) for name, value in tags.items()]\n+ data.sign(self.wallet.rsa)\n+ # id in .id\n+ return data\n \n-# bundlr used to return an expected block height but now seems to return some timestamp 2022-11\n-# communicate with bundlr for details on their api.\n-#current_block = peer.current_block()\n-#eta = current_block['timestamp'] + (result['block'] - current_block['height']) * 60 * 2\n-eta = int(result['timestamp']/1000)\n+ async def _send(self, ditem):\n+ ditem = self._prep(ditem)\n+ result = await asyncio.to_thread(self.bundlr_node.send_tx, ditem.tobytes())\n+ #timestamp = datetime.datetime.fromtimestamp(int(result['timestamp']/1000))\n+ assert result['id'] == ditem.id\n+ return result['id']\n \n-eta = datetime.datetime.fromtimestamp(eta)\n+ async def _manifest[self, **files, tags = {}):\n+ ditems = {name: self._prep(data) for name, data in files.items()}\n+ ditems['index.html'] = '\\n'.join([\n+ f'<p><a href=\"{name}\">{name}</a></p>'\n+ for name, ditem in ditems.items()\n+ ])\n+ coros = [self._send(ditem) for ditem in ditems.values()]\n+ manifest = json.dumps(dict(\n+ manifest = 'arweave/paths',\n+ version = '0.1.0',\n+ index = dict(\n+ path = 'index.html',\n+ ),\n+ paths = {\n+ name = dict(id = ditem.id)\n+ for name, ditem in ditems.items()\n+ },\n+ ))\n+ manifest = self._prep(manifest, tags)\n+ coros.append(self._send(manifest)]\n+ await asyncio.gather(*coros)\n+ return manifest.id\n \n-print(f'{peer.api_url}/{result[\"id\"]} timestamp={eta.isoformat()}')\n+ async def __call__(self, **kwparams):\n+ ditemid = await self._manifest(\n+ input = kwparams.pop('input'),\n+ output = kwparams.pop('output'),\n+ metadata = json.dumps(kwparams),\n+ )\n+ return urllib.parse.urljoin(self.gateway, ditemid)\n\n added context-based timestamping to arweaveditems, same as jsonfiles\n\n" } diff --git a/lm/log/arweaveditems.py b/lm/log/arweaveditems.py index 1a2b3c4..5a6b7c8 100644 --- a/lm/log/arweaveditems.py +++ b/lm/log/arweaveditems.py @@ -1,68 +1,74 @@ import datetime import asyncio import urllib.parse import json import os import ar, ar.utils import bundlr as bundlr_ class arweaveditems: def __init__(self, wallet = None, bundlr = bundlr_.DEFAULT_API_URL, gateway = 'https://arweave.net/'): self.wallet = wallet or ar.Wallet.generate() self.bundlr = bundlr self.gateway = gateway + def _timestamp(self): + return datetime.datetime.now().isoformat() + async def __aenter__(self): self.bundlr_node = bundlf_.Node(self.bundlr) async def __aexit__(self, *params, **kwparams): pass def _prep(self, data, tags = {}): if type(data) is not ar.DataItem: if type(data) is str: data = data.encode() data = ar.DataItem(data = data) data.header.tags = [ar.utils.create_tag(name, value, True) for name, value in tags.items()] data.sign(self.wallet.rsa) # id in .id return data async def _send(self, ditem): ditem = self._prep(ditem) result = await asyncio.to_thread(self.bundlr_node.send_tx, ditem.tobytes()) #timestamp = datetime.datetime.fromtimestamp(int(result['timestamp']/1000)) assert result['id'] == ditem.id return result['id'] async def _manifest[self, **files, tags = {}): ditems = {name: self._prep(data) for name, data in files.items()} ditems['index.html'] = '\n'.join([ f'<p><a href="{name}">{name}</a></p>' for name, ditem in ditems.items() ]) coros = [self._send(ditem) for ditem in ditems.values()] manifest = json.dumps(dict( manifest = 'arweave/paths', version = '0.1.0', index = dict( path = 'index.html', ), paths = { name = dict(id = ditem.id) for name, ditem in ditems.items() }, )) manifest = self._prep(manifest, tags) coros.append(self._send(manifest)) await asyncio.gather(*coros) return manifest.id async def __call__(self, **kwparams): + timestamp = self._timestamp() ditemid = await self._manifest( input = kwparams.pop('input'), output = kwparams.pop('output'), - metadata = json.dumps(kwparams), + metadata = json.dumps({**kwparams, 'timestamp': timestamp}), ) return urllib.parse.urljoin(self.gateway, ditemid) 109111 ms