150 lines
4.5 KiB
Python
150 lines
4.5 KiB
Python
import re
|
|
|
|
import orjson
|
|
from django.conf import settings
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.http import HttpResponse, HttpResponseBadRequest
|
|
from rest_framework.parsers import JSONParser
|
|
from rest_framework.views import APIView
|
|
from serde import ValidationError
|
|
|
|
from core.forms import HookForm
|
|
from core.lib import market
|
|
from core.lib.serde import drakdoo_s
|
|
from core.models import Callback, Hook
|
|
from core.util import logs
|
|
from core.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
|
|
|
|
log = logs.get_logger(__name__)
|
|
|
|
|
|
def extract_price(message):
|
|
result = re.findall("\d+\.\d+", message) # noqa
|
|
if len(result) != 1:
|
|
log.error(f"Could not extract price from message: {message}")
|
|
return False
|
|
try:
|
|
log.debug(f"Extracted {result[0]} from '{message}'")
|
|
return float(result[0])
|
|
except ValueError:
|
|
return False
|
|
|
|
|
|
class HookAPI(APIView):
|
|
parser_classes = [JSONParser]
|
|
|
|
def post(self, request, hook_name):
|
|
log.debug(f"HookAPI POST: {request.data}")
|
|
|
|
# Try loading the JSON
|
|
# try:
|
|
# loaded_json = orjson.loads(request.data)
|
|
# except orjson.JSONDecodeError:
|
|
# return HttpResponseBadRequest("Invalid JSON")
|
|
|
|
# Try validating the JSON
|
|
try:
|
|
hook_resp = drakdoo_s.BaseDrakdoo.from_dict(request.data)
|
|
except ValidationError as e:
|
|
log.error(f"HookAPI POST: {e}")
|
|
return HttpResponseBadRequest(e)
|
|
|
|
price = extract_price(hook_resp.message)
|
|
if not price:
|
|
log.debug(f"Could not extract price from message: {hook_resp.message}")
|
|
return HttpResponseBadRequest("Could not extract price from message")
|
|
base = hook_resp.market.item
|
|
quote = hook_resp.market.currency
|
|
symbol = f"{base.upper()}/{quote.upper()}"
|
|
if symbol not in settings.ASSET_FILTER:
|
|
log.debug(f"Skipping {symbol} because it is not in the asset filter")
|
|
return HttpResponseBadRequest("Invalid symbol")
|
|
|
|
data = {
|
|
"title": hook_resp.title,
|
|
"message": hook_resp.message,
|
|
"period": hook_resp.period,
|
|
"sent": hook_resp.timestamp.sent,
|
|
"trade": hook_resp.timestamp.trade,
|
|
"exchange": hook_resp.market.exchange,
|
|
"base": hook_resp.market.item,
|
|
"quote": hook_resp.market.currency,
|
|
"symbol": symbol,
|
|
"contract": hook_resp.market.contract,
|
|
"price": price,
|
|
}
|
|
|
|
log.debug("HookAPI callback: data: %s", data)
|
|
|
|
# Try getting the hook
|
|
try:
|
|
hook = Hook.objects.get(hook=hook_name)
|
|
except Hook.DoesNotExist:
|
|
return HttpResponseBadRequest("Hook does not exist.")
|
|
|
|
# Create the callback object
|
|
callback = Callback.objects.create(hook=hook, **data)
|
|
callback.save()
|
|
market.process_callback(callback)
|
|
# Bump received count
|
|
hook.received = hook.received + 1
|
|
hook.save()
|
|
|
|
return HttpResponse("OK")
|
|
|
|
def get(self, request, hook_name):
|
|
hook = Hook.objects.get(name=hook_name)
|
|
|
|
return_data = {"name": hook.name, "hook": hook.hook, "hook_id": hook.id}
|
|
return HttpResponse(orjson.dumps(return_data), content_type="application/json")
|
|
|
|
|
|
class HookList(LoginRequiredMixin, ObjectList):
|
|
# window_content = "window-content/hooks.html"
|
|
list_template = "partials/hook-list.html"
|
|
model = Hook
|
|
context_object_name = "hooks"
|
|
context_object_name_singular = "hook"
|
|
title = "Hooks"
|
|
title_singular = "Hook"
|
|
page_title = "List of active URL endpoints for receiving hooks."
|
|
page_subtitle = "Add URLs here to receive Drakdoo callbacks. Make then unique!"
|
|
|
|
list_url_name = "hooks"
|
|
list_url_args = ["type"]
|
|
|
|
submit_url_name = "hook_create"
|
|
|
|
|
|
class HookCreate(LoginRequiredMixin, ObjectCreate):
|
|
model = Hook
|
|
form_class = HookForm
|
|
context_object_name = "hooks"
|
|
context_object_name_singular = "hook"
|
|
|
|
list_url_name = "hooks"
|
|
list_url_args = ["type"]
|
|
|
|
submit_url_name = "hook_create"
|
|
|
|
|
|
class HookUpdate(LoginRequiredMixin, ObjectUpdate):
|
|
model = Hook
|
|
form_class = HookForm
|
|
context_object_name = "hooks"
|
|
context_object_name_singular = "hook"
|
|
|
|
list_url_name = "hooks"
|
|
list_url_args = ["type"]
|
|
|
|
submit_url_name = "hook_update"
|
|
|
|
|
|
class HookDelete(LoginRequiredMixin, ObjectDelete):
|
|
model = Hook
|
|
context_object_name = "hooks"
|
|
context_object_name_singular = "hook"
|
|
|
|
list_url_name = "hooks"
|
|
list_url_args = ["type"]
|