cic-cli/cic/meta.py

150 lines
4.4 KiB
Python
Raw Normal View History

2022-02-21 06:34:25 +01:00
from __future__ import annotations
2021-10-09 19:56:29 +02:00
# standard imports
2022-02-10 09:22:21 +01:00
import base64
2021-10-09 19:56:29 +02:00
import json
import logging
2022-02-10 09:22:21 +01:00
import os
2021-10-09 19:56:29 +02:00
2022-02-21 06:34:25 +01:00
# types
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from cic.cmd.arg import CmdCtrl
# external imports
from cic_types import MetadataPointer
2022-02-10 09:22:21 +01:00
from cic_types.processor import generate_metadata_pointer
from hexathon import strip_0x
2022-02-21 06:34:25 +01:00
from cic.MetaRequestHandler import MetadataRequestsHandler
2021-10-14 15:43:23 +02:00
from cic.output import OutputWriter
2022-02-21 06:34:25 +01:00
from cic.utils import object_to_str
2022-02-10 09:22:21 +01:00
# local imports
from .base import Data, data_dir
logg = logging.getLogger(__name__)
2021-10-09 19:56:29 +02:00
class Meta(Data):
2021-11-29 08:02:12 +01:00
"""Serialize and publish metadata for token.
2021-10-09 19:56:29 +02:00
2021-11-29 08:02:12 +01:00
The token metadata is any mutable data that is not part of the initial token proof, but published simultaneously as the token nonetheless.
:param path: Path to settings directory
:type path: str
:param writer: Writer interface receiving the output of the processor
:type writer: cic.output.OutputWriter
"""
2022-02-21 06:34:25 +01:00
def __init__(
self, path=".", writer=None, name="", location="", country_code="", contact={}
):
2021-10-09 19:56:29 +02:00
super(Meta, self).__init__()
2022-02-21 06:34:25 +01:00
self.name = name
2022-02-10 09:22:21 +01:00
self.contact = contact
self.country_code = country_code
self.location = location
2021-10-09 19:56:29 +02:00
self.path = path
self.writer = writer
2022-02-21 06:34:25 +01:00
self.meta_path = os.path.join(self.path, "meta.json")
2021-10-09 19:56:29 +02:00
def load(self):
2022-02-21 06:34:25 +01:00
"""Load metadata from settings."""
2021-10-09 19:56:29 +02:00
super(Meta, self).load()
2022-02-21 06:34:25 +01:00
f = open(self.meta_path, "r", encoding="utf-8")
2021-10-09 20:37:54 +02:00
o = json.load(f)
2021-10-09 19:56:29 +02:00
f.close()
2022-02-21 06:34:25 +01:00
self.name = o["name"]
self.contact = o["contact"]
self.country_code = o["country_code"]
self.location = o["location"]
2021-10-09 19:56:29 +02:00
self.inited = True
def start(self):
2022-02-21 06:34:25 +01:00
"""Initialize metadata settings from template."""
2021-10-09 19:56:29 +02:00
super(Meta, self).start()
2022-02-21 06:34:25 +01:00
meta_template_file_path = os.path.join(
data_dir, f"meta_template_v{self.version()}.json"
)
f = open(meta_template_file_path, encoding="utf-8")
2021-10-09 19:56:29 +02:00
o = json.load(f)
f.close()
2021-10-09 20:37:54 +02:00
2022-02-21 06:34:25 +01:00
o["name"] = self.name
o["contact"] = self.contact
o["country_code"] = self.country_code
o["location"] = self.location
f = open(self.meta_path, "w", encoding="utf-8")
json.dump(o, f, sort_keys=True, indent="\t")
f.close()
2021-10-09 20:37:54 +02:00
def reference(self, token_address):
2022-02-21 06:34:25 +01:00
"""Calculate the mutable reference for the token metadata."""
token_address_bytes = bytes.fromhex(strip_0x(token_address))
2022-02-21 06:34:25 +01:00
return generate_metadata_pointer(
token_address_bytes, MetadataPointer.TOKEN_META
)
def asdict(self):
2022-02-21 06:34:25 +01:00
"""Output proof state to dict."""
return {
2022-02-21 06:34:25 +01:00
"name": self.name,
"country_code": self.country_code,
"location": self.location,
"contact": self.contact,
}
2021-10-21 15:11:05 +02:00
def process(self, token_address=None, token_symbol=None, writer=None):
2021-11-29 08:02:12 +01:00
"""Serialize and publish metadata.
2022-02-21 06:34:25 +01:00
See cic.processor.Processor.process
2021-11-29 08:02:12 +01:00
"""
2022-02-21 06:34:25 +01:00
if writer is None:
writer = self.writer
v = json.dumps(self.asdict())
2021-10-21 15:11:05 +02:00
token_address_bytes = bytes.fromhex(strip_0x(token_address))
k = generate_metadata_pointer(token_address_bytes, MetadataPointer.TOKEN_META)
2022-02-21 06:34:25 +01:00
writer.write(k, v.encode("utf-8"))
2021-10-21 15:11:05 +02:00
2022-02-21 06:34:25 +01:00
token_symbol_bytes = token_symbol.encode("utf-8")
k = generate_metadata_pointer(
token_symbol_bytes, MetadataPointer.TOKEN_META_SYMBOL
)
writer.write(k, v.encode("utf-8"))
return (k, v)
2021-10-09 20:37:54 +02:00
def __str__(self):
2022-02-21 06:34:25 +01:00
return object_to_str(self, ["name", "contact", "country_code", "location"])
2021-10-14 15:43:23 +02:00
class MetadataWriter(OutputWriter):
2021-11-29 08:02:12 +01:00
"""Custom writer for publishing data under immutable content-addressed pointers in the cic-meta storage backend.
Data that is not utf-8 will be converted to base64 before publishing.
Implements cic.output.OutputWriter
"""
2021-10-21 15:11:05 +02:00
2021-10-14 15:43:23 +02:00
def write(self, k, v):
2021-10-21 15:11:05 +02:00
rq = MetadataRequestsHandler(MetadataPointer.NONE, bytes.fromhex(k))
try:
2022-02-21 06:34:25 +01:00
v = v.decode("utf-8")
v = json.loads(v)
2022-02-21 06:34:25 +01:00
logg.debug(f"metadatawriter bindecode {k} {v}")
except UnicodeDecodeError:
2022-02-21 06:34:25 +01:00
v = base64.b64encode(v).decode("utf-8")
v = json.loads(json.dumps(v))
2022-02-21 06:34:25 +01:00
logg.debug(f"metadatawriter b64encode {k} {v}")
r = rq.create(v)
2022-02-21 06:34:25 +01:00
logg.info(f"metadata submitted at {k}")
return r