2016-07-15 20:09:43 +02:00
|
|
|
import json
|
|
|
|
|
2016-07-26 23:20:51 +02:00
|
|
|
from copy import deepcopy
|
2016-07-25 07:40:26 +02:00
|
|
|
from lbrynet.conf import CURRENCIES
|
2016-07-28 08:36:07 +02:00
|
|
|
from lbrynet.core import utils
|
2016-07-26 03:45:42 +02:00
|
|
|
import logging
|
2016-07-25 07:40:26 +02:00
|
|
|
|
2016-07-26 03:45:42 +02:00
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
BITTREX_FEE = 0.0025
|
2016-07-25 07:40:26 +02:00
|
|
|
|
2016-07-28 21:24:20 +02:00
|
|
|
# Metadata version
|
2016-07-26 03:45:42 +02:00
|
|
|
SOURCE_TYPES = ['lbry_sd_hash', 'url', 'btih']
|
2016-07-29 00:48:29 +02:00
|
|
|
NAME_ALLOWED_CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0987654321-'
|
2016-07-25 07:40:26 +02:00
|
|
|
BASE_METADATA_FIELDS = ['title', 'description', 'author', 'language', 'license', 'content-type', 'sources']
|
2016-07-15 20:09:43 +02:00
|
|
|
OPTIONAL_METADATA_FIELDS = ['thumbnail', 'preview', 'fee', 'contact', 'pubkey']
|
|
|
|
|
2016-07-28 21:24:20 +02:00
|
|
|
MV001 = "0.0.1"
|
|
|
|
MV002 = "0.0.2"
|
|
|
|
CURRENT_METADATA_VERSION = MV002
|
2016-07-25 07:40:26 +02:00
|
|
|
|
2016-07-28 21:24:20 +02:00
|
|
|
METADATA_REVISIONS = {}
|
|
|
|
METADATA_REVISIONS[MV001] = {'required': BASE_METADATA_FIELDS, 'optional': OPTIONAL_METADATA_FIELDS}
|
|
|
|
METADATA_REVISIONS[MV002] = {'required': ['nsfw', 'ver'], 'optional': ['license_url']}
|
|
|
|
|
|
|
|
# Fee version
|
|
|
|
BASE_FEE_FIELDS = ['amount', 'address']
|
|
|
|
|
|
|
|
FV001 = "0.0.1"
|
|
|
|
CURRENT_FEE_REVISION = FV001
|
|
|
|
|
|
|
|
FEE_REVISIONS = {}
|
|
|
|
FEE_REVISIONS[FV001] = {'required': BASE_FEE_FIELDS, 'optional': []}
|
2016-07-26 03:45:42 +02:00
|
|
|
|
|
|
|
|
2016-07-29 00:48:29 +02:00
|
|
|
def verify_name_characters(name):
|
|
|
|
for c in name:
|
|
|
|
assert c in NAME_ALLOWED_CHARSET, "Invalid character"
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2016-07-28 08:19:45 +02:00
|
|
|
class LBRYFeeValidator(dict):
|
2016-07-26 23:20:51 +02:00
|
|
|
def __init__(self, fee_dict):
|
|
|
|
dict.__init__(self)
|
|
|
|
assert len(fee_dict) == 1
|
2016-07-28 08:19:45 +02:00
|
|
|
self.fee_version = None
|
2016-07-28 11:30:13 +02:00
|
|
|
self.currency_symbol = None
|
2016-07-28 08:19:45 +02:00
|
|
|
|
|
|
|
fee_to_load = deepcopy(fee_dict)
|
|
|
|
|
2016-07-26 23:20:51 +02:00
|
|
|
for currency in fee_dict:
|
2016-07-28 08:19:45 +02:00
|
|
|
self._verify_fee(currency, fee_to_load)
|
|
|
|
|
|
|
|
self.amount = self._get_amount()
|
2016-07-26 23:20:51 +02:00
|
|
|
self.address = self[self.currency_symbol]['address']
|
2016-07-26 03:45:42 +02:00
|
|
|
|
2016-07-28 08:19:45 +02:00
|
|
|
def _get_amount(self):
|
2016-07-28 18:43:20 +02:00
|
|
|
amt = self[self.currency_symbol]['amount']
|
|
|
|
if isinstance(amt, float):
|
|
|
|
return amt
|
2016-07-28 08:19:45 +02:00
|
|
|
else:
|
2016-07-28 18:43:20 +02:00
|
|
|
try:
|
|
|
|
return float(amt)
|
|
|
|
except TypeError:
|
|
|
|
log.error('Failed to convert %s to float', amt)
|
|
|
|
raise
|
2016-07-28 08:19:45 +02:00
|
|
|
|
|
|
|
def _verify_fee(self, currency, f):
|
|
|
|
# str in case someone made a claim with a wierd fee
|
|
|
|
assert currency in CURRENCIES, "Unsupported currency: %s" % str(currency)
|
|
|
|
self.currency_symbol = currency
|
|
|
|
self.update({currency: {}})
|
|
|
|
for version in FEE_REVISIONS:
|
|
|
|
self._load_revision(version, f)
|
|
|
|
if not f:
|
|
|
|
self.fee_version = version
|
|
|
|
break
|
|
|
|
assert f[self.currency_symbol] == {}, "Unknown fee keys: %s" % json.dumps(f.keys())
|
|
|
|
|
|
|
|
def _load_revision(self, version, f):
|
|
|
|
for k in FEE_REVISIONS[version]['required']:
|
|
|
|
assert k in f[self.currency_symbol], "Missing required fee field: %s" % k
|
|
|
|
self[self.currency_symbol].update({k: f[self.currency_symbol].pop(k)})
|
|
|
|
for k in FEE_REVISIONS[version]['optional']:
|
|
|
|
if k in f[self.currency_symbol]:
|
|
|
|
self[self.currency_symbol].update({k: f[self.currency_symbol].pop(k)})
|
2016-07-26 23:20:51 +02:00
|
|
|
|
2016-07-28 08:19:45 +02:00
|
|
|
|
2016-07-15 20:09:43 +02:00
|
|
|
class Metadata(dict):
|
|
|
|
def __init__(self, metadata):
|
|
|
|
dict.__init__(self)
|
2016-07-28 08:19:45 +02:00
|
|
|
self.meta_version = None
|
|
|
|
metadata_to_load = deepcopy(metadata)
|
|
|
|
|
|
|
|
self._verify_sources(metadata_to_load)
|
|
|
|
self._verify_metadata(metadata_to_load)
|
|
|
|
|
|
|
|
def _load_revision(self, version, metadata):
|
|
|
|
for k in METADATA_REVISIONS[version]['required']:
|
|
|
|
assert k in metadata, "Missing required metadata field: %s" % k
|
|
|
|
self.update({k: metadata.pop(k)})
|
|
|
|
for k in METADATA_REVISIONS[version]['optional']:
|
|
|
|
if k == 'fee':
|
2016-07-28 16:42:16 +02:00
|
|
|
self._load_fee(metadata)
|
2016-07-28 08:19:45 +02:00
|
|
|
elif k in metadata:
|
|
|
|
self.update({k: metadata.pop(k)})
|
|
|
|
|
|
|
|
def _load_fee(self, metadata):
|
|
|
|
if 'fee' in metadata:
|
|
|
|
self['fee'] = LBRYFeeValidator(metadata.pop('fee'))
|
|
|
|
|
|
|
|
def _verify_sources(self, metadata):
|
2016-07-25 07:40:26 +02:00
|
|
|
assert "sources" in metadata, "No sources given"
|
|
|
|
for source in metadata['sources']:
|
|
|
|
assert source in SOURCE_TYPES, "Unknown source type"
|
|
|
|
|
2016-07-28 08:19:45 +02:00
|
|
|
def _verify_metadata(self, metadata):
|
2016-07-15 20:09:43 +02:00
|
|
|
for version in METADATA_REVISIONS:
|
2016-07-28 08:19:45 +02:00
|
|
|
self._load_revision(version, metadata)
|
|
|
|
if not metadata:
|
|
|
|
self.meta_version = version
|
2016-07-28 08:36:07 +02:00
|
|
|
if utils.version_is_greater_than(self.meta_version, "0.0.1"):
|
|
|
|
assert self.meta_version == self['ver'], "version mismatch"
|
2016-07-15 20:09:43 +02:00
|
|
|
break
|
2016-07-28 08:19:45 +02:00
|
|
|
assert metadata == {}, "Unknown metadata keys: %s" % json.dumps(metadata.keys())
|