Libraries refactor and add some sinks #4

Closed
m wants to merge 136 commits from library-refactor into master
3 changed files with 71 additions and 60 deletions
Showing only changes of commit b3c3e7a96c - Show all commits

View File

@ -7,42 +7,16 @@ from twisted.internet.threads import deferToThread
from json import loads from json import loads
from forex_python.converter import CurrencyRates from forex_python.converter import CurrencyRates
from agoradesk_py import AgoraDesk from agoradesk_py import AgoraDesk
from httpx import ReadTimeout, ReadError, RemoteProtocolError from pycoingecko import CoinGeckoAPI # TODO: remove this import and defer to money
from pycoingecko import CoinGeckoAPI
from datetime import datetime
from time import sleep from time import sleep
from pyotp import TOTP from pyotp import TOTP
# Project imports # Project imports
from settings import settings from settings import settings
import util
log = Logger("agora.global") 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): class Agora(object):
""" """
@ -56,8 +30,8 @@ class Agora(object):
""" """
self.log = Logger("agora") self.log = Logger("agora")
self.agora = AgoraDesk(settings.Agora.Token) self.agora = AgoraDesk(settings.Agora.Token)
self.cr = CurrencyRates() self.cr = CurrencyRates() # TODO: remove this and defer to money
self.cg = CoinGeckoAPI() self.cg = CoinGeckoAPI() # TODO: remove this and defer to money
# Cache for detecting new trades # Cache for detecting new trades
self.last_dash = set() self.last_dash = set()
@ -78,7 +52,7 @@ class Agora(object):
self.lc_cheat = LoopingCall(self.run_cheat_in_thread) self.lc_cheat = LoopingCall(self.run_cheat_in_thread)
self.lc_cheat.start(int(settings.Agora.CheatSec)) self.lc_cheat.start(int(settings.Agora.CheatSec))
@handle_exceptions @util.handle_exceptions
def wrap_dashboard(self): def wrap_dashboard(self):
dash = self.agora.dashboard_seller() dash = self.agora.dashboard_seller()
if dash is None: if dash is None:
@ -179,7 +153,7 @@ class Agora(object):
current_trades.append(reference) current_trades.append(reference)
self.tx.cleanup(current_trades) self.tx.cleanup(current_trades)
@handle_exceptions @util.handle_exceptions
def get_recent_messages(self, send_irc=True): def get_recent_messages(self, send_irc=True):
""" """
Get recent messages. Get recent messages.
@ -226,7 +200,7 @@ class Agora(object):
return messages_tmp return messages_tmp
@handle_exceptions @util.handle_exceptions
def enum_ad_ids(self, page=0): def enum_ad_ids(self, page=0):
ads = self.agora._api_call(api_method="ads", query_values={"page": page}) ads = self.agora._api_call(api_method="ads", query_values={"page": page})
if ads is False: if ads is False:
@ -248,7 +222,7 @@ class Agora(object):
ads_total.append(ad) ads_total.append(ad)
return ads_total return ads_total
@handle_exceptions @util.handle_exceptions
def enum_ads(self, requested_asset=None, page=0): def enum_ads(self, requested_asset=None, page=0):
query_values = {"page": page} query_values = {"page": page}
if requested_asset: if requested_asset:
@ -278,22 +252,7 @@ class Agora(object):
ads_total.append([ad[0], ad[1], ad[2], ad[3], ad[4]]) ads_total.append([ad[0], ad[1], ad[2], ad[3], ad[4]])
return ads_total return ads_total
# TODO: move to utils library @util.handle_exceptions
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
def enum_public_ads(self, asset, currency, providers=None, page=0): def enum_public_ads(self, asset, currency, providers=None, page=0):
to_return = [] to_return = []
@ -326,7 +285,7 @@ class Agora(object):
continue continue
date_last_seen = ad["data"]["profile"]["last_online"] date_last_seen = ad["data"]["profile"]["last_online"]
# Check if this person was seen recently # 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 continue
ad_id = ad["data"]["ad_id"] ad_id = ad["data"]["ad_id"]
username = ad["data"]["profile"]["username"] username = ad["data"]["profile"]["username"]
@ -391,7 +350,7 @@ class Agora(object):
else: else:
deferToThread(self.update_prices, assets) deferToThread(self.update_prices, assets)
@handle_exceptions @util.handle_exceptions
def update_prices(self, assets=None): def update_prices(self, assets=None):
# Get all public ads for the given assets # Get all public ads for the given assets
public_ads = self.get_all_public_ads(assets) public_ads = self.get_all_public_ads(assets)
@ -403,7 +362,7 @@ class Agora(object):
self.slow_ad_update(to_update) self.slow_ad_update(to_update)
# TODO: make generic and move to markets # TODO: make generic and move to markets
@handle_exceptions @util.handle_exceptions
def get_all_public_ads(self, assets=None, currencies=None, providers=None): def get_all_public_ads(self, assets=None, currencies=None, providers=None):
""" """
Get all public ads for our listed currencies. Get all public ads for our listed currencies.
@ -487,7 +446,7 @@ class Agora(object):
continue continue
iterations += 1 iterations += 1
@handle_exceptions @util.handle_exceptions
def nuke_ads(self): def nuke_ads(self):
""" """
Delete all of our adverts. Delete all of our adverts.
@ -534,7 +493,7 @@ class Agora(object):
max_local = max_usd * rates[currency] max_local = max_usd * rates[currency]
return (min_local, max_local) return (min_local, max_local)
@handle_exceptions @util.handle_exceptions
def create_ad(self, asset, countrycode, currency, provider, edit=False, ad_id=None): 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. Post an ad with the given asset in a country with a given currency.
@ -654,7 +613,7 @@ class Agora(object):
return False return False
yield (rtrn, ad_id) yield (rtrn, ad_id)
@handle_exceptions @util.handle_exceptions
def strip_duplicate_ads(self): def strip_duplicate_ads(self):
""" """
Remove duplicate ads. Remove duplicate ads.
@ -676,7 +635,7 @@ class Agora(object):
actioned.append(rtrn["success"]) actioned.append(rtrn["success"])
return all(actioned) return all(actioned)
@handle_exceptions @util.handle_exceptions
def release_funds(self, contact_id): def release_funds(self, contact_id):
""" """
Release funds for a contact_id. Release funds for a contact_id.
@ -695,7 +654,7 @@ class Agora(object):
return rtrn return rtrn
# TODO: write test before re-enabling adding total_trades # TODO: write test before re-enabling adding total_trades
@handle_exceptions @util.handle_exceptions
def withdraw_funds(self): def withdraw_funds(self):
""" """
Withdraw excess funds to our XMR wallets. 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 tests.common import fake_public_ads, cg_prices, expected_to_update
from agora import Agora from agora import Agora
from markets import Markets from markets import Markets
import util
class TestAgora(TestCase): class TestAgora(TestCase):
@ -120,6 +121,9 @@ class TestAgora(TestCase):
self.agora.last_online_recent = MagicMock() self.agora.last_online_recent = MagicMock()
self.agora.last_online_recent.return_value = True self.agora.last_online_recent.return_value = True
util.last_online_recent = MagicMock()
util.last_online_recent.return_value = True
# Override get_price # Override get_price
self.agora.cg.get_price = MagicMock() self.agora.cg.get_price = MagicMock()
self.agora.cg.get_price.return_value = cg_prices self.agora.cg.get_price.return_value = cg_prices
@ -132,8 +136,8 @@ class TestAgora(TestCase):
def test_enum_public_ads(self): def test_enum_public_ads(self):
# Override enum_public_ads # Override enum_public_ads
self.agora.agora._api_call = self.mock_enum_public_ads_api_call self.agora.agora._api_call = self.mock_enum_public_ads_api_call
self.agora.last_online_recent = MagicMock() util.last_online_recent = MagicMock()
self.agora.last_online_recent.return_value = True util.last_online_recent.return_value = True
enum_ads_return = self.agora.enum_public_ads("XMR", "USD", self.all_providers) 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): def convert(data):
""" """
Recursively convert a dictionary. Recursively convert a dictionary.
@ -11,3 +21,41 @@ def convert(data):
if isinstance(data, list): if isinstance(data, list):
return list(map(convert, data)) return list(map(convert, data))
return 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