commit 1ff0631915563c77c1ffd2ab03e095a763f47a22
parent 8936cccd29becbbcc7dbd99f4d38693537feb3ec
Author: Emily Doherty <git@emily.sh>
Date: Fri, 8 Sep 2023 23:20:22 -0700
Initial implementations
Okay not really, but I have lost the original git repo so this is where we're at qq
Diffstat:
2 files changed, 176 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,14 @@
+token-current:
+ zip wow-token-current.zip wow-token-current.py
+
+token-historical:
+ zip wow-token-historical.zip wow-token-historical.py
+
+token-updater:
+ cd venv/lib/python3.9/site-packages && zip -r ../../../../wow-token-updater.zip .
+ zip -g wow-token-updater.zip wow-token-updater.py
+
+clean:
+ rm -v wow-token-current.zip wow-token-historical.zip wow-token-updater.zip
+
+all: token-current token-historical token-updater
diff --git a/wow-token-updater.py b/wow-token-updater.py
@@ -0,0 +1,162 @@
+import datetime
+import time
+import boto3
+import json
+import os
+import requests
+
+
+dynamo_client = boto3.client('dynamodb', region_name='us-east-1')
+timestream_client = boto3.client('timestream-write', region_name='us-east-1')
+current_table = os.environ['TABLE_NAME']
+recent_table = os.environ['RECENT_TABLE_NAME']
+
+
+# a lambda handler to handle eventbridge triggered vents
+def lambda_handler(event, context):
+ regions = ['us', 'eu', 'kr', 'tw']
+ live_prices = get_combined_live_price()
+ print(live_prices)
+ current_time_epoch = int(datetime.datetime.utcnow().timestamp())
+ for region in regions:
+ print(f'Updating {region.upper()}...')
+ update_token_price(region, current_time_epoch, live_prices[region])
+
+
+def update_token_price(region: str, current_time_epoch: int, live_price: int):
+ stored_price = get_stored_price(region)
+ print(f'Current stored price {stored_price}')
+ if stored_price != live_price:
+ update_stored_token_price(region, live_price, current_time_epoch)
+ update_recent_token_price(region, live_price, current_time_epoch)
+ update_timestream_token_price(region, live_price, current_time_epoch)
+ else:
+ # price hasn't changed
+ print(f'Price has not changed for {region.upper()}')
+
+
+# update the current price records in DynamoDB
+def update_stored_token_price(region: str, price: int, current_time_epoch: int) -> None:
+ dynamo_client.update_item(
+ TableName=current_table,
+ Key={
+ 'region': {
+ 'S': region
+ }
+ },
+ UpdateExpression='SET price = :p, current_time = :t',
+ ExpressionAttributeValues={
+ ':p': {
+ 'S': str(price)
+ },
+ ':t': {
+ 'S': str(current_time_epoch)
+ }
+ }
+ # ReturnValues="UPDATED_NEW"
+ )
+ print(f'Updated {region.upper()} price to {price}')
+
+
+# add a record to the recent token price table in DynamoDB
+def update_recent_token_price(region: str, price: int, current_time_epoch: int) -> None:
+ dynamo_client.put_item(
+ TableName=recent_table,
+ Item={
+ 'region': {
+ 'S': region
+ },
+ 'price': {
+ 'S': str(price)
+ },
+ 'timestamp': {
+ 'N': str(current_time_epoch)
+ },
+ 'expire': {
+ 'N': str(current_time_epoch + (60 * 60 * 24 * 31 * 12))
+ }
+ }
+ # ReturnValues="UPDATED_NEW"
+ )
+ print(f'Added {region.upper()} price {price} to {recent_table} table')
+
+
+def update_timestream_token_price(region: str, price: int, current_time_epoch: int) -> None:
+ record_inserted = False
+ while not record_inserted:
+ try:
+ print('Attempting to write to Timestream')
+ timestream_client.write_records(
+ DatabaseName=os.environ['TIMESTREAM_DATABASE'],
+ TableName=f'{region}-price-history',
+ Records=[
+ build_timestream_record(region, price, current_time_epoch),
+ ]
+ )
+ record_inserted = True
+ except Exception as e:
+ print(f'Error writing to Timestream: {e}')
+ time.sleep(2)
+ print(f'Updated {region.upper()} price to {price} in Timestream')
+
+
+def build_timestream_record(region: str, price: int, current_time_epoch: int) -> dict:
+ return {
+ 'Dimensions': [
+ {
+ 'Name': 'region',
+ 'Value': region,
+ 'DimensionValueType': 'VARCHAR'
+ }
+ ],
+ 'MeasureName': 'price',
+ 'MeasureValue': str(price),
+ 'MeasureValueType': 'BIGINT',
+ 'Time': str(current_time_epoch),
+ 'TimeUnit': 'SECONDS',
+ }
+
+
+# get the current stored token price from dynamodb
+def get_stored_price(region: str) -> int:
+ response = dynamo_client.get_item(
+ TableName=current_table,
+ Key={
+ 'region': {
+ 'S': region
+ }
+ }
+ )
+ return int(response['Item']['price']['S'])
+
+
+def get_combined_live_price() -> dict:
+ return {
+ 'us': get_token_price_from_blizzard('us'),
+ 'eu': get_token_price_from_blizzard('eu'),
+ 'kr': get_token_price_from_blizzard('kr'),
+ 'tw': get_token_price_from_blizzard('tw')
+ }
+
+
+def get_token_price_from_blizzard(region: str):
+ api_endpoint = f'https://{region}.api.blizzard.com/data/wow/token/index'
+ params = {'namespace': f'{os.environ.get("BLIZZARD_NAMESPACE")}-{region}'}
+ headers = {'Authorization': f'Bearer {get_oauth_token()}'}
+ response = requests.get(api_endpoint, params=params, headers=headers)
+ return int(response.json()['price'])
+
+
+def get_oauth_token():
+ url = 'https://us.battle.net/oauth/token'
+ payload = {
+ 'grant_type': 'client_credentials',
+ 'client_id': os.environ.get('BLIZZARD_CLIENT_ID'),
+ 'client_secret': os.environ.get('BLIZZARD_CLIENT_SECRET')
+ }
+ response = requests.post(url, data=payload)
+ return json.loads(response.text)['access_token']
+
+
+if __name__ == '__main__':
+ lambda_handler(None, None)