relative_path_handler.py (4037B)
1 import datetime 2 from typing import List, Tuple 3 4 from wow_token.db.cached_range import CachedRange 5 from wow_token.db.compacted import Compacted 6 from wow_token.db.recent import Recent 7 from wow_token.db.trinity import Trinity 8 from wow_token.flavor import Flavor 9 from wow_token.path_handler.relative_error import InvalidRelativePathError 10 from wow_token.region import Region 11 12 13 class RelativePathHandler: 14 _cdb : Compacted 15 _rdb : Recent 16 def __init__(self, cdb: Compacted, rdb: Recent): 17 self._cdb = cdb 18 self._rdb = rdb 19 20 21 def get_by_timedelta(self, flavor: Flavor, region: Region, timedelta: datetime.timedelta) -> List[Tuple[str, int]]: 22 current_time = datetime.datetime.now(datetime.UTC) 23 start_time = current_time - timedelta 24 25 if timedelta.days < 61: 26 return self._rdb.get_after_unix_timestamp(flavor, region, int(start_time.timestamp())) 27 elif timedelta.days <= 90: 28 trinity = Trinity(region, flavor, CachedRange('90d')) 29 elif timedelta.days <= 183: 30 trinity = Trinity(region, flavor, CachedRange('6m')) 31 elif timedelta.days <= 365: 32 trinity = Trinity(region, flavor, CachedRange('1y')) 33 elif timedelta.days <= 730: 34 trinity = Trinity(region, flavor, CachedRange('2y')) 35 else: 36 trinity = Trinity(region, flavor, CachedRange('all')) 37 38 # If the data is exactly the size of the precomputed structure, go ahead and return it directly 39 if timedelta.days == 90 or timedelta.days == 182 or timedelta.days == 365 or timedelta.days == 730: 40 return self._cdb.get_precomputed_range(trinity, str) 41 42 final_data = [] 43 data = self._cdb.get_precomputed_range(trinity) 44 for timestamp, price in data: 45 if timestamp >= start_time: 46 final_data.append((timestamp.isoformat(), price)) 47 return final_data 48 49 50 def relative_time_handler(self, flavor: Flavor, region: Region, relative_range: str) -> List[Tuple[str, int]]: 51 if relative_range == '30d': 52 relative_range = '744h' 53 54 relative_unit = relative_range[-1] 55 56 match relative_unit: 57 case 'h': 58 hours = int(relative_range[:-1]) 59 if hours > 1488: 60 raise InvalidRelativePathError 61 start_time = datetime.datetime.now(datetime.UTC) - datetime.timedelta(hours=hours) 62 return self._rdb.get_after_unix_timestamp(flavor, region, int(start_time.timestamp())) 63 case 'd': 64 days = int(relative_range[:-1]) 65 if days > 730: 66 raise InvalidRelativePathError 67 delta = datetime.timedelta(days=days) 68 return self.get_by_timedelta(flavor, region, delta) 69 case 'm': 70 months = int(relative_range[:-1]) 71 if months > 48: 72 raise InvalidRelativePathError 73 delta = datetime.timedelta(days=int(30.437*months)) 74 return self.get_by_timedelta(flavor, region, delta) 75 case 'y': 76 years = int(relative_range[:-1]) 77 if years > 10: 78 raise InvalidRelativePathError 79 delta = datetime.timedelta(days=int(365.25*years)) 80 return self.get_by_timedelta(flavor, region, delta) 81 case _: 82 if relative_range == 'all': 83 return self._cdb.get_precomputed_range(Trinity(region, flavor, CachedRange('all')), str) 84 raise InvalidRelativePathError 85 86 87 88 def path_handler(self, uri) -> List[Tuple[str, int]]: 89 # This URI takes the form of /v2/relative/{flavor}/{region}/{range} 90 split_uri = uri.split('/') 91 flavor = Flavor(split_uri[-3]) 92 region = Region(split_uri[-2]) 93 _range = split_uri[-1] 94 if split_uri[-1].endswith('.json'): 95 _range = split_uri[-1][:-5] 96 97 return self.relative_time_handler(flavor, region, _range) 98