Libraries refactor and add some sinks #4
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue