Update updater to handle both retail and classic, as well as handle regional updates
This commit is contained in:
parent
36b5de0df2
commit
e5840d5cfe
@ -6,39 +6,68 @@ import os
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
|
||||||
dynamo_client = boto3.client('dynamodb', region_name='us-east-1')
|
local_region = os.environ['AWS_REGION']
|
||||||
timestream_client = boto3.client('timestream-write', region_name='us-east-1')
|
|
||||||
current_table = os.environ['TABLE_NAME']
|
dynamo_client = boto3.client('dynamodb', region_name=local_region)
|
||||||
recent_table = os.environ['RECENT_TABLE_NAME']
|
timestream_client = boto3.client('timestream-write', region_name=local_region)
|
||||||
|
tables = {
|
||||||
|
'retail': {
|
||||||
|
'recent': 'wow-token-price-recent',
|
||||||
|
'current': 'wow-token-price',
|
||||||
|
'timestream': 'wow-token-price-history'
|
||||||
|
},
|
||||||
|
'classic': {
|
||||||
|
'recent': 'wow-token-classic-price-recent',
|
||||||
|
'current': 'wow-token-classic-price',
|
||||||
|
'timestream': 'wow-token-classic-price-history'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# a lambda handler to handle eventbridge triggered vents
|
# a lambda handler to handle eventbridge triggered vents
|
||||||
def lambda_handler(event, context):
|
def lambda_handler(event, context):
|
||||||
|
flavors = ['retail', 'classic']
|
||||||
regions = ['us', 'eu', 'kr', 'tw']
|
regions = ['us', 'eu', 'kr', 'tw']
|
||||||
live_prices = get_combined_live_price()
|
timestamp = int(datetime.datetime.utcnow().timestamp())
|
||||||
print(live_prices)
|
for flavor in flavors:
|
||||||
current_time_epoch = int(datetime.datetime.utcnow().timestamp())
|
flavor_handler(flavor, regions, timestamp)
|
||||||
|
|
||||||
|
|
||||||
|
def flavor_handler(flavor: str, regions: list, timestamp: int) -> None:
|
||||||
|
live_prices = get_combined_live_price(flavor)
|
||||||
|
print(f"Current {flavor} prices:\t{live_prices}")
|
||||||
for region in regions:
|
for region in regions:
|
||||||
print(f'Updating {region.upper()}...')
|
print(f'Updating {region.upper()}...')
|
||||||
update_token_price(region, current_time_epoch, live_prices[region])
|
update_token_price(flavor, region, timestamp, live_prices[region])
|
||||||
|
|
||||||
|
|
||||||
def update_token_price(region: str, current_time_epoch: int, live_price: int):
|
def update_token_price(flavor: str, region: str, current_time_epoch: int, live_price: int):
|
||||||
stored_price = get_stored_price(region)
|
stored_price = get_stored_price(flavor, region)
|
||||||
|
regional_item = get_regional_update_item(flavor, region)
|
||||||
|
print(f'Current live price {live_price}')
|
||||||
print(f'Current stored price {stored_price}')
|
print(f'Current stored price {stored_price}')
|
||||||
|
regional_price = int(regional_item['price']['S'])
|
||||||
|
print(f'Current regional price {regional_price}')
|
||||||
if stored_price != live_price:
|
if stored_price != live_price:
|
||||||
update_stored_token_price(region, live_price, current_time_epoch)
|
# If the stored price is not the same as the live price, nor the regional price
|
||||||
update_recent_token_price(region, live_price, current_time_epoch)
|
# assume no other Lambda has updated it and update it
|
||||||
update_timestream_token_price(region, live_price, current_time_epoch)
|
print(f"Stored price is differing from the live price, updating all databases")
|
||||||
|
update_stored_token_price(flavor, region, live_price, current_time_epoch)
|
||||||
|
update_recent_token_price(flavor, region, live_price, current_time_epoch)
|
||||||
|
update_regional_price(flavor, region, live_price, current_time_epoch)
|
||||||
|
update_timestream_token_price(flavor, region, live_price, current_time_epoch)
|
||||||
|
if (stored_price == live_price) and (regional_price != stored_price):
|
||||||
|
print(f"Stored price differs from regional price but not live price, updating regional databases")
|
||||||
|
update_regional_price(flavor, region, live_price, current_time_epoch)
|
||||||
|
update_timestream_token_price(flavor, region, live_price, current_time_epoch)
|
||||||
else:
|
else:
|
||||||
# price hasn't changed
|
print(f"Price hasn't changed for {flavor} {region.upper()}")
|
||||||
print(f'Price has not changed for {region.upper()}')
|
|
||||||
|
|
||||||
|
|
||||||
# update the current price records in DynamoDB
|
# update the current price records in DynamoDB
|
||||||
def update_stored_token_price(region: str, price: int, current_time_epoch: int) -> None:
|
def update_stored_token_price(flavor: str, region: str, price: int, current_time_epoch: int) -> None:
|
||||||
dynamo_client.update_item(
|
dynamo_client.update_item(
|
||||||
TableName=current_table,
|
TableName=tables[flavor]['current'],
|
||||||
Key={
|
Key={
|
||||||
'region': {
|
'region': {
|
||||||
'S': region
|
'S': region
|
||||||
@ -55,13 +84,61 @@ def update_stored_token_price(region: str, price: int, current_time_epoch: int)
|
|||||||
}
|
}
|
||||||
# ReturnValues="UPDATED_NEW"
|
# ReturnValues="UPDATED_NEW"
|
||||||
)
|
)
|
||||||
print(f'Updated {region.upper()} price to {price}')
|
print(f'Updated {flavor} {region.upper()} price to {price}')
|
||||||
|
|
||||||
|
|
||||||
|
def update_regional_price(flavor: str, region: str, price: int, current_time_epoch: int) -> None:
|
||||||
|
if flavor == 'retail':
|
||||||
|
key = region
|
||||||
|
else:
|
||||||
|
key = f"{flavor}-{region}"
|
||||||
|
dynamo_client.update_item(
|
||||||
|
TableName='wow-token-regional',
|
||||||
|
Key={
|
||||||
|
'region': {
|
||||||
|
'S': key
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpdateExpression='SET price = :p, current_time = :t',
|
||||||
|
ExpressionAttributeValues={
|
||||||
|
':p': {
|
||||||
|
'S': str(price)
|
||||||
|
},
|
||||||
|
':t': {
|
||||||
|
'S': str(current_time_epoch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# ReturnValues="UPDATED_NEW"
|
||||||
|
)
|
||||||
|
print(f'Updated regional {flavor} {region.upper()} price to {price}')
|
||||||
|
|
||||||
|
|
||||||
|
def create_regional_item(flavor: str, region: str):
|
||||||
|
print(f"Creating default regional item in {flavor} {region}")
|
||||||
|
if flavor == 'retail':
|
||||||
|
key = region
|
||||||
|
else:
|
||||||
|
key = f"{flavor}-{region}"
|
||||||
|
dynamo_client.put_item(
|
||||||
|
TableName='wow-token-regional',
|
||||||
|
Item={
|
||||||
|
'region': {
|
||||||
|
'S': key
|
||||||
|
},
|
||||||
|
'price': {
|
||||||
|
'S': str(1)
|
||||||
|
},
|
||||||
|
'timestamp': {
|
||||||
|
'N': str(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# add a record to the recent token price table in DynamoDB
|
# 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:
|
def update_recent_token_price(flavor: str, region: str, price: int, current_time_epoch: int) -> None:
|
||||||
dynamo_client.put_item(
|
dynamo_client.put_item(
|
||||||
TableName=recent_table,
|
TableName=tables[flavor]['recent'],
|
||||||
Item={
|
Item={
|
||||||
'region': {
|
'region': {
|
||||||
'S': region
|
'S': region
|
||||||
@ -78,16 +155,16 @@ def update_recent_token_price(region: str, price: int, current_time_epoch: int)
|
|||||||
}
|
}
|
||||||
# ReturnValues="UPDATED_NEW"
|
# ReturnValues="UPDATED_NEW"
|
||||||
)
|
)
|
||||||
print(f'Added {region.upper()} price {price} to {recent_table} table')
|
print(f'Added {region.upper()} price {price} to {tables[flavor]["recent"]} table')
|
||||||
|
|
||||||
|
|
||||||
def update_timestream_token_price(region: str, price: int, current_time_epoch: int) -> None:
|
def update_timestream_token_price(flavor: str, region: str, price: int, current_time_epoch: int) -> None:
|
||||||
record_inserted = False
|
record_inserted = False
|
||||||
while not record_inserted:
|
while not record_inserted:
|
||||||
try:
|
try:
|
||||||
print('Attempting to write to Timestream')
|
print('Attempting to write to Timestream')
|
||||||
timestream_client.write_records(
|
timestream_client.write_records(
|
||||||
DatabaseName=os.environ['TIMESTREAM_DATABASE'],
|
DatabaseName=tables[flavor]['timestream'],
|
||||||
TableName=f'{region}-price-history',
|
TableName=f'{region}-price-history',
|
||||||
Records=[
|
Records=[
|
||||||
build_timestream_record(region, price, current_time_epoch),
|
build_timestream_record(region, price, current_time_epoch),
|
||||||
@ -97,7 +174,7 @@ def update_timestream_token_price(region: str, price: int, current_time_epoch: i
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f'Error writing to Timestream: {e}')
|
print(f'Error writing to Timestream: {e}')
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
print(f'Updated {region.upper()} price to {price} in Timestream')
|
print(f'Updated {flavor} {region.upper()} price to {price} in Timestream')
|
||||||
|
|
||||||
|
|
||||||
def build_timestream_record(region: str, price: int, current_time_epoch: int) -> dict:
|
def build_timestream_record(region: str, price: int, current_time_epoch: int) -> dict:
|
||||||
@ -118,9 +195,9 @@ def build_timestream_record(region: str, price: int, current_time_epoch: int) ->
|
|||||||
|
|
||||||
|
|
||||||
# get the current stored token price from dynamodb
|
# get the current stored token price from dynamodb
|
||||||
def get_stored_price(region: str) -> int:
|
def get_stored_price(flavor: str, region: str) -> int:
|
||||||
response = dynamo_client.get_item(
|
response = dynamo_client.get_item(
|
||||||
TableName=current_table,
|
TableName=tables[flavor]['current'],
|
||||||
Key={
|
Key={
|
||||||
'region': {
|
'region': {
|
||||||
'S': region
|
'S': region
|
||||||
@ -130,18 +207,44 @@ def get_stored_price(region: str) -> int:
|
|||||||
return int(response['Item']['price']['S'])
|
return int(response['Item']['price']['S'])
|
||||||
|
|
||||||
|
|
||||||
def get_combined_live_price() -> dict:
|
def get_regional_update_item(flavor: str, region: str) -> dict:
|
||||||
|
if flavor == 'retail':
|
||||||
|
key = region
|
||||||
|
else:
|
||||||
|
key = f"{flavor}-{region}"
|
||||||
|
response = dynamo_client.get_item(
|
||||||
|
TableName='wow-token-regional',
|
||||||
|
Key={
|
||||||
|
'region': {
|
||||||
|
'S': key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if 'Item' in response:
|
||||||
|
return response['Item']
|
||||||
|
else:
|
||||||
|
create_regional_item(flavor, region)
|
||||||
|
time.sleep(5)
|
||||||
|
return get_regional_update_item(flavor, region)
|
||||||
|
|
||||||
|
|
||||||
|
def get_combined_live_price(game_flavor: str) -> dict:
|
||||||
|
if game_flavor == 'retail':
|
||||||
|
namespace = 'dynamic'
|
||||||
|
else:
|
||||||
|
namespace = 'dynamic-classic'
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'us': get_token_price_from_blizzard('us'),
|
'us': get_token_price_from_blizzard('us', namespace),
|
||||||
'eu': get_token_price_from_blizzard('eu'),
|
'eu': get_token_price_from_blizzard('eu', namespace),
|
||||||
'kr': get_token_price_from_blizzard('kr'),
|
'kr': get_token_price_from_blizzard('kr', namespace),
|
||||||
'tw': get_token_price_from_blizzard('tw')
|
'tw': get_token_price_from_blizzard('tw', namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_token_price_from_blizzard(region: str):
|
def get_token_price_from_blizzard(region: str, namespace: str):
|
||||||
api_endpoint = f'https://{region}.api.blizzard.com/data/wow/token/index'
|
api_endpoint = f'https://{region}.api.blizzard.com/data/wow/token/index'
|
||||||
params = {'namespace': f'{os.environ.get("BLIZZARD_NAMESPACE")}-{region}'}
|
params = {'namespace': f'{namespace}-{region}'}
|
||||||
headers = {'Authorization': f'Bearer {get_oauth_token()}'}
|
headers = {'Authorization': f'Bearer {get_oauth_token()}'}
|
||||||
response = requests.get(api_endpoint, params=params, headers=headers)
|
response = requests.get(api_endpoint, params=params, headers=headers)
|
||||||
return int(response.json()['price'])
|
return int(response.json()['price'])
|
||||||
|
Loading…
Reference in New Issue
Block a user