initial
This commit is contained in:
7
BaseLib/BaseDaemon.py
Normal file
7
BaseLib/BaseDaemon.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.core.management import BaseCommand
|
||||
|
||||
from BaseLib.BaseEntity import BaseEntity
|
||||
|
||||
|
||||
class BaseDaemon(BaseCommand, BaseEntity):
|
||||
...
|
4
BaseLib/BaseEntity.py
Normal file
4
BaseLib/BaseEntity.py
Normal file
@@ -0,0 +1,4 @@
|
||||
class BaseEntity:
|
||||
def get_user(self):
|
||||
raise NotImplementedError
|
||||
|
98
BaseLib/BaseView.py
Normal file
98
BaseLib/BaseView.py
Normal file
@@ -0,0 +1,98 @@
|
||||
import typing
|
||||
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.http import HttpResponseRedirect, JsonResponse
|
||||
from django.shortcuts import render
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from BaseLib.BaseEntity import BaseEntity
|
||||
from BaseLib.bot import notify_if_needed
|
||||
|
||||
|
||||
class AccessError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BaseView(BaseEntity):
|
||||
request: WSGIRequest
|
||||
context: typing.Optional[typing.Dict] = None
|
||||
required_login: typing.Optional[bool] = None
|
||||
view_file: typing.Optional[str] = None
|
||||
endpoint: typing.Optional[str] = None
|
||||
fields_except: typing.Tuple[str] = ()
|
||||
|
||||
def __init__(self, request):
|
||||
self.context = {}
|
||||
self.request = request
|
||||
|
||||
def get_user(self):
|
||||
return self.request.user
|
||||
|
||||
@classmethod
|
||||
def as_path(cls):
|
||||
return cls.endpoint, cls.as_view()
|
||||
|
||||
@classmethod
|
||||
def as_view(cls):
|
||||
@csrf_exempt
|
||||
def execute(request: WSGIRequest):
|
||||
try:
|
||||
c = cls(request)
|
||||
if c.required_login is not None:
|
||||
if c.required_login and not request.user.is_authenticated:
|
||||
return HttpResponseRedirect("/welcome")
|
||||
if (
|
||||
not c.required_login
|
||||
and request.user.is_authenticated
|
||||
):
|
||||
return HttpResponseRedirect("/")
|
||||
request_method = request.method.lower()
|
||||
exec("from Platform.common_models import *")
|
||||
context = {}
|
||||
for key in request.GET.keys():
|
||||
if key.endswith("_id") and key not in cls.fields_except:
|
||||
model_name = key[:-3]
|
||||
setattr(
|
||||
c,
|
||||
model_name,
|
||||
eval(model_name[0].upper() + model_name[1:]).objects.get(
|
||||
id=int(request.GET[key])
|
||||
),
|
||||
)
|
||||
context[model_name] = getattr(c, model_name)
|
||||
if "action" in request.POST.keys():
|
||||
request_method += "_" + request.POST["action"]
|
||||
method = getattr(c, request_method, None)
|
||||
try:
|
||||
data = c.pre_handle()
|
||||
if method:
|
||||
if data is None:
|
||||
data = method()
|
||||
if isinstance(data, BaseView):
|
||||
return HttpResponseRedirect(data.endpoint)
|
||||
if type(data) == str:
|
||||
return HttpResponseRedirect(data)
|
||||
if type(data) == dict:
|
||||
return JsonResponse(data)
|
||||
if data is not None:
|
||||
return data
|
||||
context = {**context, **c.context}
|
||||
res = render(request, c.view_file, context)
|
||||
res.headers["X-Frame-Options"] = "ALLOW"
|
||||
return res
|
||||
except AccessError:
|
||||
return HttpResponseRedirect("/")
|
||||
except Exception as exc:
|
||||
notify_if_needed(exc)
|
||||
raise
|
||||
|
||||
return execute
|
||||
|
||||
def pre_handle(self):
|
||||
pass
|
||||
|
||||
def get(self):
|
||||
pass
|
||||
|
||||
def post(self):
|
||||
pass
|
0
BaseLib/__init__.py
Normal file
0
BaseLib/__init__.py
Normal file
22
BaseLib/bot.py
Normal file
22
BaseLib/bot.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import telebot
|
||||
|
||||
CHAT_ID = -914906133
|
||||
TELEGRAM_TOKEN = os.getenv("TELEGRAM_TOKEN")
|
||||
if TELEGRAM_TOKEN is not None:
|
||||
bot = telebot.TeleBot(TELEGRAM_TOKEN)
|
||||
|
||||
|
||||
def get_traceback(tb):
|
||||
if tb.tb_next is not None:
|
||||
next_tb = get_traceback(tb.tb_next)
|
||||
else:
|
||||
next_tb = ''
|
||||
return str(tb.tb_frame) + '\n' + next_tb
|
||||
|
||||
|
||||
def notify_if_needed(exc):
|
||||
if type(exc) is not KeyboardInterrupt and TELEGRAM_TOKEN:
|
||||
bot.send_message(CHAT_ID, f"Ошибка на проекте YourGols.\nПодробности: \n{get_traceback(sys.exc_info()[2])}\n{str(exc)}")
|
45
BaseLib/minio.py
Normal file
45
BaseLib/minio.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import io
|
||||
|
||||
from minio import Minio
|
||||
from minio.error import MinioException
|
||||
|
||||
from Platform import settings
|
||||
|
||||
|
||||
class Client:
|
||||
|
||||
def __init__(self, host: str, access_key: str, secret_key: str, bucket_name: str):
|
||||
self.bucket_name = bucket_name
|
||||
self.cli = Minio(
|
||||
host,
|
||||
access_key=access_key,
|
||||
secret_key=secret_key,
|
||||
secure=False
|
||||
)
|
||||
try:
|
||||
self.cli.make_bucket(bucket_name)
|
||||
except MinioException:
|
||||
pass
|
||||
|
||||
def put_object(self, data: bytes, name: str):
|
||||
self.cli.put_object(self.bucket_name, name, io.BytesIO(data), len(data))
|
||||
|
||||
def get_object(self, name: str) -> bytes:
|
||||
try:
|
||||
return self.cli.get_object(self.bucket_name, name).data
|
||||
except MinioException:
|
||||
return b""
|
||||
|
||||
def delete_object(self, name: str):
|
||||
try:
|
||||
self.cli.remove_object(self.bucket_name, name)
|
||||
except MinioException:
|
||||
pass
|
||||
|
||||
|
||||
minio_client = Client(
|
||||
settings.MINIO_HOST,
|
||||
settings.MINIO_ACCESS_KEY,
|
||||
settings.MINIO_SECRET_KEY,
|
||||
settings.MINIO_BUCKET_NAME
|
||||
)
|
96
BaseLib/queue.py
Normal file
96
BaseLib/queue.py
Normal file
@@ -0,0 +1,96 @@
|
||||
import json
|
||||
from json import JSONDecodeError
|
||||
from time import sleep
|
||||
|
||||
import pika
|
||||
from django import db
|
||||
from BaseLib.BaseDaemon import BaseDaemon
|
||||
from pika.adapters.utils.connection_workflow import AMQPConnectorException
|
||||
|
||||
from allinvest import settings
|
||||
|
||||
|
||||
def blocking_connection():
|
||||
return pika.BlockingConnection(
|
||||
pika.ConnectionParameters(
|
||||
host=settings.RABBITMQ_HOST,
|
||||
credentials=pika.PlainCredentials(settings.RABBITMQ_USER, settings.RABBITMQ_PASSWORD)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def send_to_queue(routing_key, payload):
|
||||
with blocking_connection() as connection:
|
||||
channel = connection.channel()
|
||||
queue_name = f"{settings.RABBITMQ_EXCHANGE}_{routing_key}"
|
||||
channel.exchange_declare(
|
||||
exchange=settings.RABBITMQ_EXCHANGE,
|
||||
exchange_type='direct'
|
||||
)
|
||||
channel.queue_declare(queue_name)
|
||||
channel.queue_bind(
|
||||
exchange=settings.RABBITMQ_EXCHANGE,
|
||||
queue=queue_name,
|
||||
routing_key=routing_key
|
||||
)
|
||||
channel.basic_publish(
|
||||
exchange=settings.RABBITMQ_EXCHANGE,
|
||||
routing_key=routing_key,
|
||||
body=json.dumps(payload).encode("UTF-8")
|
||||
)
|
||||
|
||||
|
||||
class MessagingSupport(BaseDaemon):
|
||||
queue_name = None
|
||||
attempts = 3
|
||||
payload = dict()
|
||||
|
||||
def process(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def consume(self, ch, method, properties, body):
|
||||
try:
|
||||
data = json.loads(body.decode('utf-8'))
|
||||
except JSONDecodeError:
|
||||
print("Message is not JSON decodable")
|
||||
return
|
||||
print(f"Got {data}, processing...")
|
||||
finished = False
|
||||
|
||||
for attempt in range(1, self.attempts + 1):
|
||||
print("attempt", attempt)
|
||||
try:
|
||||
db.close_old_connections()
|
||||
self.payload = data
|
||||
self.process()
|
||||
finished = True
|
||||
except Exception as e:
|
||||
print("failed with", str(e))
|
||||
raise
|
||||
sleep(1.5)
|
||||
if finished:
|
||||
break
|
||||
if finished:
|
||||
print("Process finished successfully")
|
||||
else:
|
||||
print("Process failed")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if self.queue_name is None:
|
||||
raise NotImplementedError("Queue name must be declared")
|
||||
print("start listening " + self.queue_name)
|
||||
while True:
|
||||
try:
|
||||
with pika.BlockingConnection(
|
||||
pika.ConnectionParameters(
|
||||
host=settings.RABBITMQ_HOST,
|
||||
credentials=pika.PlainCredentials(settings.RABBITMQ_USER, settings.RABBITMQ_PASSWORD)
|
||||
)
|
||||
) as connection:
|
||||
channel = connection.channel()
|
||||
queue = f"{settings.RABBITMQ_EXCHANGE}_{self.queue_name}"
|
||||
channel.queue_declare(queue=queue)
|
||||
channel.basic_consume(queue=queue, on_message_callback=self.consume, auto_ack=True)
|
||||
channel.start_consuming()
|
||||
except AMQPConnectorException:
|
||||
print("connection to rabbit failed: reconnecting")
|
30
BaseLib/redis.py
Normal file
30
BaseLib/redis.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import redis
|
||||
|
||||
from allinvest import settings
|
||||
|
||||
|
||||
class RedisClient:
|
||||
|
||||
def __init__(self, host, db=1, password=None):
|
||||
kwargs = {
|
||||
"host": host,
|
||||
"db": db
|
||||
}
|
||||
if password:
|
||||
kwargs['password'] = password
|
||||
self.cli = redis.Redis(**kwargs)
|
||||
|
||||
def get(self, key):
|
||||
with self.cli as cli:
|
||||
return cli.get(key)
|
||||
|
||||
def set(self, key, value):
|
||||
with self.cli as cli:
|
||||
cli.set(key, value)
|
||||
|
||||
|
||||
redis_client = RedisClient(
|
||||
settings.REDIS_HOST,
|
||||
settings.REDIS_DB,
|
||||
settings.REDIS_PASSWORD
|
||||
)
|
Reference in New Issue
Block a user