robosats/api/tasks.py

213 lines
7.2 KiB
Python
Raw Normal View History

from celery import shared_task
2022-02-17 19:50:10 +00:00
@shared_task(name="users_cleansing")
def users_cleansing():
2022-02-17 19:50:10 +00:00
"""
Deletes users never used 12 hours after creation
2022-02-17 19:50:10 +00:00
"""
from django.contrib.auth.models import User
from django.db.models import Q
from .logics import Logics
from datetime import timedelta
from django.utils import timezone
2022-01-18 17:52:48 +00:00
# Users who's last login has not been in the last 6 hours
active_time_range = (timezone.now() - timedelta(hours=6), timezone.now())
queryset = User.objects.filter(~Q(last_login__range=active_time_range))
2022-02-17 19:50:10 +00:00
queryset = queryset.filter(is_staff=False) # Do not delete staff users
# And do not have an active trade, any past contract or any reward.
deleted_users = []
for user in queryset:
if user.profile.pending_rewards > 0 or user.profile.earned_rewards > 0 or user.profile.claimed_rewards > 0:
continue
if not user.profile.total_contracts == 0:
continue
2022-01-31 12:53:20 +00:00
valid, _, _ = Logics.validate_already_maker_or_taker(user)
if valid:
deleted_users.append(str(user))
user.delete()
results = {
2022-02-17 19:50:10 +00:00
"num_deleted": len(deleted_users),
"deleted_users": deleted_users,
}
return results
2022-03-05 20:51:16 +00:00
@shared_task(name="give_rewards")
def users_cleansing():
"""
Referral rewards go from pending to earned.
Happens asynchronously so the referral program cannot be easily used to spy.
"""
from api.models import Profile
# Users who's last login has not been in the last 6 hours
queryset = Profile.objects.filter(pending_rewards__gt=0)
# And do not have an active trade, any past contract or any reward.
results = {}
for profile in queryset:
given_reward = profile.pending_rewards
profile.earned_rewards += given_reward
profile.pending_rewards = 0
profile.save()
results[profile.user.username] = {'given_reward':given_reward,'earned_rewards':profile.earned_rewards}
return results
2022-02-17 19:50:10 +00:00
@shared_task(name="follow_send_payment")
def follow_send_payment(lnpayment):
2022-02-17 19:50:10 +00:00
"""Sends sats to buyer, continuous update"""
from decouple import config
from base64 import b64decode
from django.utils import timezone
from datetime import timedelta
from api.lightning.node import LNNode, MACAROON
from api.models import LNPayment, Order
from api.logics import Logics
2022-02-17 19:50:10 +00:00
fee_limit_sat = int(
max(
lnpayment.num_satoshis *
float(config("PROPORTIONAL_ROUTING_FEE_LIMIT")),
float(config("MIN_FLAT_ROUTING_FEE_LIMIT")),
)) # 200 ppm or 10 sats
request = LNNode.routerrpc.SendPaymentRequest(
payment_request=lnpayment.invoice,
fee_limit_sat=fee_limit_sat,
2022-02-17 19:50:10 +00:00
timeout_seconds=60,
) # time out payment in 60 seconds
order = lnpayment.order_paid
try:
2022-02-17 19:50:10 +00:00
for response in LNNode.routerstub.SendPaymentV2(request,
metadata=[
("macaroon",
MACAROON.hex())
]):
if response.status == 0: # Status 0 'UNKNOWN'
# Not sure when this status happens
2022-02-17 19:50:10 +00:00
pass
2022-02-17 19:50:10 +00:00
if response.status == 1: # Status 1 'IN_FLIGHT'
print("IN_FLIGHT")
lnpayment.status = LNPayment.Status.FLIGHT
lnpayment.save()
order.status = Order.Status.PAY
order.save()
2022-02-17 19:50:10 +00:00
if response.status == 3: # Status 3 'FAILED'
print("FAILED")
lnpayment.status = LNPayment.Status.FAILRO
lnpayment.last_routing_time = timezone.now()
lnpayment.routing_attempts += 1
lnpayment.save()
order.status = Order.Status.FAI
2022-02-17 19:50:10 +00:00
order.expires_at = timezone.now() + timedelta(
seconds=Order.t_to_expire[Order.Status.FAI])
order.save()
2022-02-17 19:50:10 +00:00
context = {
"routing_failed":
LNNode.payment_failure_context[response.failure_reason]
}
print(context)
return False, context
2022-02-17 19:50:10 +00:00
if response.status == 2: # Status 2 'SUCCEEDED'
print("SUCCEEDED")
lnpayment.status = LNPayment.Status.SUCCED
lnpayment.save()
order.status = Order.Status.SUC
2022-02-17 19:50:10 +00:00
order.expires_at = timezone.now() + timedelta(
seconds=Order.t_to_expire[Order.Status.SUC])
order.save()
return True, None
except Exception as e:
if "invoice expired" in str(e):
2022-02-17 19:50:10 +00:00
print("INVOICE EXPIRED")
lnpayment.status = LNPayment.Status.EXPIRE
lnpayment.last_routing_time = timezone.now()
lnpayment.save()
order.status = Order.Status.FAI
2022-02-17 19:50:10 +00:00
order.expires_at = timezone.now() + timedelta(
seconds=Order.t_to_expire[Order.Status.FAI])
order.save()
2022-02-17 19:50:10 +00:00
context = {"routing_failed": "The payout invoice has expired"}
return False, context
2022-02-17 19:50:10 +00:00
@shared_task(name="cache_external_market_prices", ignore_result=True)
def cache_market():
from .models import Currency
from .utils import get_exchange_rates
from django.utils import timezone
currency_codes = list(Currency.currency_dict.values())
exchange_rates = get_exchange_rates(currency_codes)
results = {}
2022-02-17 19:50:10 +00:00
for i in range(len(Currency.currency_dict.values())
): # currecies are indexed starting at 1 (USD)
2022-02-17 19:50:10 +00:00
rate = exchange_rates[i]
results[i] = {currency_codes[i], rate}
# Do not update if no new rate was found
2022-02-17 19:50:10 +00:00
if str(rate) == "nan":
continue
# Create / Update database cached prices
currency_key = list(Currency.currency_dict.keys())[i]
Currency.objects.update_or_create(
2022-02-17 19:50:10 +00:00
id=int(currency_key),
currency=int(currency_key),
# if there is a Cached market prices matching that id, it updates it with defaults below
2022-02-17 19:50:10 +00:00
defaults={
"exchange_rate": float(rate),
"timestamp": timezone.now(),
},
)
2022-02-17 19:50:10 +00:00
return results
@shared_task(name="send_message", ignore_result=True)
def send_message(order_id, message):
from api.models import Order
order = Order.objects.get(id=order_id)
if not order.maker.profile.telegram_enabled:
return
from api.messages import Telegram
telegram = Telegram()
if message == 'order_taken':
telegram.order_taken(order)
elif message == 'order_expired_untaken':
telegram.order_expired_untaken(order)
elif message == 'trade_successful':
telegram.trade_successful(order)
elif message == 'public_order_cancelled':
telegram.public_order_cancelled(order)
elif message == 'taker_expired_b4bond':
telegram.taker_expired_b4bond(order)
elif message == 'taker_canceled_b4bond':
telegram.taker_canceled_b4bond(order)
elif message == 'order_published':
telegram.order_published(order)
return