Move some functions to a util class from Agora

This commit is contained in:
Mark Veidemanis 2022-02-22 19:53:22 +00:00
parent 18011741c5
commit b3c3e7a96c
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
3 changed files with 71 additions and 60 deletions

View File

@ -7,42 +7,16 @@ from twisted.internet.threads import deferToThread
from json import loads
from forex_python.converter import CurrencyRates
from agoradesk_py import AgoraDesk
from httpx import ReadTimeout, ReadError, RemoteProtocolError
from pycoingecko import CoinGeckoAPI
from datetime import datetime
from pycoingecko import CoinGeckoAPI # TODO: remove this import and defer to money
from time import sleep
from pyotp import TOTP
# Project imports
from settings import settings
import util
log = Logger("agora.global")
# TODO: move to utils
def handle_exceptions(func):
def inner_function(*args, **kwargs):
try:
rtrn = func(*args, **kwargs)
except (ReadTimeout, ReadError, RemoteProtocolError):
return False
if isinstance(rtrn, dict):
if "success" in rtrn:
if "message" in rtrn:
if not rtrn["success"] and rtrn["message"] == "API ERROR":
if "error_code" in rtrn["response"]["error"]:
code = rtrn["response"]["error"]["error_code"]
if not code == 136:
log.error("API error: {code}", code=code)
return False
else:
log.error("API error: {code}", code=rtrn["response"]["error"])
return False
return rtrn
return inner_function
class Agora(object):
"""
@ -56,8 +30,8 @@ class Agora(object):
"""
self.log = Logger("agora")
self.agora = AgoraDesk(settings.Agora.Token)
self.cr = CurrencyRates()
self.cg = CoinGeckoAPI()
self.cr = CurrencyRates() # TODO: remove this and defer to money
self.cg = CoinGeckoAPI() # TODO: remove this and defer to money
# Cache for detecting new trades
self.last_dash = set()
@ -78,7 +52,7 @@ class Agora(object):
self.lc_cheat = LoopingCall(self.run_cheat_in_thread)
self.lc_cheat.start(int(settings.Agora.CheatSec))
@handle_exceptions
@util.handle_exceptions
def wrap_dashboard(self):
dash = self.agora.dashboard_seller()
if dash is None:
@ -179,7 +153,7 @@ class Agora(object):
current_trades.append(reference)
self.tx.cleanup(current_trades)
@handle_exceptions
@util.handle_exceptions
def get_recent_messages(self, send_irc=True):
"""
Get recent messages.
@ -226,7 +200,7 @@ class Agora(object):
return messages_tmp
@handle_exceptions
@util.handle_exceptions
def enum_ad_ids(self, page=0):
ads = self.agora._api_call(api_method="ads", query_values={"page": page})
if ads is False:
@ -248,7 +222,7 @@ class Agora(object):
ads_total.append(ad)
return ads_total
@handle_exceptions
@util.handle_exceptions
def enum_ads(self, requested_asset=None, page=0):
query_values = {"page": page}
if requested_asset:
@ -278,22 +252,7 @@ class Agora(object):
ads_total.append([ad[0], ad[1], ad[2], ad[3], ad[4]])
return ads_total
# TODO: move to utils library
def last_online_recent(self, date):
"""
Check if the last online date was recent.
:param date: date last online
:type date: string
:return: bool indicating whether the date was recent enough
:rtype: bool
"""
date_parsed = datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%fZ")
now = datetime.now()
sec_ago_date = (now - date_parsed).total_seconds()
# self.log.debug("Seconds ago date for {date} ^ {now}: {x}", date=date, now=str(now), x=sec_ago_date)
return sec_ago_date < 172800
@handle_exceptions
@util.handle_exceptions
def enum_public_ads(self, asset, currency, providers=None, page=0):
to_return = []
@ -326,7 +285,7 @@ class Agora(object):
continue
date_last_seen = ad["data"]["profile"]["last_online"]
# Check if this person was seen recently
if not self.last_online_recent(date_last_seen):
if not util.last_online_recent(date_last_seen):
continue
ad_id = ad["data"]["ad_id"]
username = ad["data"]["profile"]["username"]
@ -391,7 +350,7 @@ class Agora(object):
else:
deferToThread(self.update_prices, assets)
@handle_exceptions
@util.handle_exceptions
def update_prices(self, assets=None):
# Get all public ads for the given assets
public_ads = self.get_all_public_ads(assets)
@ -403,7 +362,7 @@ class Agora(object):
self.slow_ad_update(to_update)
# TODO: make generic and move to markets
@handle_exceptions
@util.handle_exceptions
def get_all_public_ads(self, assets=None, currencies=None, providers=None):
"""
Get all public ads for our listed currencies.
@ -487,7 +446,7 @@ class Agora(object):
continue
iterations += 1
@handle_exceptions
@util.handle_exceptions
def nuke_ads(self):
"""
Delete all of our adverts.
@ -534,7 +493,7 @@ class Agora(object):
max_local = max_usd * rates[currency]
return (min_local, max_local)
@handle_exceptions
@util.handle_exceptions
def create_ad(self, asset, countrycode, currency, provider, edit=False, ad_id=None):
"""
Post an ad with the given asset in a country with a given currency.
@ -654,7 +613,7 @@ class Agora(object):
return False
yield (rtrn, ad_id)
@handle_exceptions
@util.handle_exceptions
def strip_duplicate_ads(self):
"""
Remove duplicate ads.
@ -676,7 +635,7 @@ class Agora(object):
actioned.append(rtrn["success"])
return all(actioned)
@handle_exceptions
@util.handle_exceptions
def release_funds(self, contact_id):
"""
Release funds for a contact_id.
@ -695,7 +654,7 @@ class Agora(object):
return rtrn
# TODO: write test before re-enabling adding total_trades
@handle_exceptions
@util.handle_exceptions
def withdraw_funds(self):
"""
Withdraw excess funds to our XMR wallets.

View File

@ -6,6 +6,7 @@ from copy import deepcopy
from tests.common import fake_public_ads, cg_prices, expected_to_update
from agora import Agora
from markets import Markets
import util
class TestAgora(TestCase):
@ -120,6 +121,9 @@ class TestAgora(TestCase):
self.agora.last_online_recent = MagicMock()
self.agora.last_online_recent.return_value = True
util.last_online_recent = MagicMock()
util.last_online_recent.return_value = True
# Override get_price
self.agora.cg.get_price = MagicMock()
self.agora.cg.get_price.return_value = cg_prices
@ -132,8 +136,8 @@ class TestAgora(TestCase):
def test_enum_public_ads(self):
# Override enum_public_ads
self.agora.agora._api_call = self.mock_enum_public_ads_api_call
self.agora.last_online_recent = MagicMock()
self.agora.last_online_recent.return_value = True
util.last_online_recent = MagicMock()
util.last_online_recent.return_value = True
enum_ads_return = self.agora.enum_public_ads("XMR", "USD", self.all_providers)

View File

@ -1,3 +1,13 @@
# Twisted/Klein imports
from twisted.logger import Logger
# Other library imports
from httpx import ReadTimeout, ReadError, RemoteProtocolError
from datetime import datetime
log = Logger("util.global")
def convert(data):
"""
Recursively convert a dictionary.
@ -11,3 +21,41 @@ def convert(data):
if isinstance(data, list):
return list(map(convert, data))
return data
def last_online_recent(date):
"""
Check if the last online date was recent.
:param date: date last online
:type date: string
:return: bool indicating whether the date was recent enough
:rtype: bool
"""
date_parsed = datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%fZ")
now = datetime.now()
sec_ago_date = (now - date_parsed).total_seconds()
# self.log.debug("Seconds ago date for {date} ^ {now}: {x}", date=date, now=str(now), x=sec_ago_date)
return sec_ago_date < 172800
def handle_exceptions(func):
def inner_function(*args, **kwargs):
try:
rtrn = func(*args, **kwargs)
except (ReadTimeout, ReadError, RemoteProtocolError):
return False
if isinstance(rtrn, dict):
if "success" in rtrn:
if "message" in rtrn:
if not rtrn["success"] and rtrn["message"] == "API ERROR":
if "error_code" in rtrn["response"]["error"]:
code = rtrn["response"]["error"]["error_code"]
if not code == 136:
log.error("API error: {code}", code=code)
return False
else:
log.error("API error: {code}", code=rtrn["response"]["error"])
return False
return rtrn
return inner_function