From cf178140d34a8f9429e58dc860688ffa4542de2d Mon Sep 17 00:00:00 2001 From: gsd Date: Thu, 22 Feb 2024 00:24:57 +0300 Subject: [PATCH] first --- Dockerfile | 6 +++ backend_integration.py | 77 ++++++++++++++++++++++++++++++++++++++ colors.py | 29 ++++++++++++++ paybot.facti13.py | 85 ++++++++++++++++++++++++++++++++++++++++++ ws.py | 61 ++++++++++++++++++++++++++++++ 5 files changed, 258 insertions(+) create mode 100644 Dockerfile create mode 100644 backend_integration.py create mode 100644 colors.py create mode 100644 paybot.facti13.py create mode 100644 ws.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e069f4c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.10 +RUN python -m pip install git+https://git.pblr-nyk.pro/gsd/Donation-Alerts-API-Python aiohttp websocket-client +ENV PYTHONUNBUFFERED 1 +WORKDIR /app +COPY ./ ./ +ENTRYPOINT ["python", "paybot.facti13.py"] \ No newline at end of file diff --git a/backend_integration.py b/backend_integration.py new file mode 100644 index 0000000..4062108 --- /dev/null +++ b/backend_integration.py @@ -0,0 +1,77 @@ +import ssl +import aiohttp, os, sys +from colors import * +import traceback + +class BackendClient: + up = False + warn = False + + def __init__(self): + if not os.getenv("BACKEND_URL", ""): + error("BACKEND_URL not setted in env") + sys.exit(10) + if not os.getenv("SECRET_KEY", ""): + error("SECRET_KEY not setted in env") + sys.exit(11) + self.secret_key = os.getenv("SECRET_KEY") + self.pulse_url = f"{os.getenv('BACKEND_URL')}/api/pulse" + self.vip_url = f"{os.getenv('BACKEND_URL')}/api/external/vip" + self.detect = f"{os.getenv('BACKEND_URL')}/api/profile/steam" + + async def getSteam(self, any): + async with aiohttp.ClientSession(cookies={ + "secretkey":self.secret_key}) as session: + async with session.post(self.detect, ssl=False, json={"any":any}) as response: + return await response.json() + + async def pulse(self, exit_if_error = False): + async with aiohttp.ClientSession(cookies={ + "secretkey":self.secret_key}) as session: + try: + async with session.get(self.pulse_url, ssl=False) as response: + await response.text() + self.up = True + if not self.warn: + info("Backend connected!") + self.warn = True + except: + error("Backend not respond") + traceback.print_exc() + if exit_if_error: + sys.exit(200) + self.up = False + self.warn = False + return self.up + + async def vip(self, steamid, amount: int, extra: str, unique: str = ""): + async with aiohttp.ClientSession(cookies={ + "secretkey":self.secret_key}) as session: + async with session.post(self.vip_url + f"?steam={steamid}&amount={int(amount)}&service=qiwi&extra={extra}&unique={unique}", ssl=False) as response: + try: + result = int(await response.text()) + if result == 0: + warning(f"[S64:{steamid}] VIP as not be added, maybe permition already exists") + return 99 + elif result > 0: + info(f"[S64:{steamid}] VIP has be added!") + return 100 + elif result < 0: + info(f"[S64:{steamid}] VIP has be extends!") + return 101 + except: + error(f"[S64:{steamid}] Backend returned error") + traceback.print_exc() + return False + return False + + async def prices(self, exit_if_error = False): + async with aiohttp.ClientSession() as session: + try: + async with session.get(self.vip_url) as response: + return await response.json() + except: + traceback.print_exc() + if exit_if_error: + error("Cannot fetch prices") + sys.exit(200) \ No newline at end of file diff --git a/colors.py b/colors.py new file mode 100644 index 0000000..4866f1a --- /dev/null +++ b/colors.py @@ -0,0 +1,29 @@ +from time import strftime + +class colors: + HEADER = u'\033[95m' + OKBLUE = u'\033[94m' + OKGREEN = u'\033[92m' + WARNING = u'\033[93m' + FAIL = u'\033[91m' + ENDC = u'\033[0m' + BOLD = u'\033[1m' + UNDERLINE = u'\033[4m' + +HEADER = u"[{:^7}] ({:^17}) {}" + +def ok(text): + HEAD = colors.OKGREEN + u"OK" + colors.ENDC + return print(HEADER.format(HEAD, strftime(u"%H:%M:%S %d.%m.%y"), text)) + +def error(text): + HEAD = colors.FAIL + u"FAIL" + colors.ENDC + return print(HEADER.format(HEAD, strftime(u"%H:%M:%S %d.%m.%y"), text)) + +def warning(text): + HEAD = colors.WARNING + u"WARNING" + colors.ENDC + return print(HEADER.format(HEAD, strftime(u"%H:%M:%S %d.%m.%y"), text)) + +def info(text): + HEAD = colors.HEADER + u"INFO" + colors.ENDC + return print(HEADER.format(HEAD, strftime(u"%H:%M:%S %d.%m.%y"), text)) \ No newline at end of file diff --git a/paybot.facti13.py b/paybot.facti13.py new file mode 100644 index 0000000..9adaa22 --- /dev/null +++ b/paybot.facti13.py @@ -0,0 +1,85 @@ +from http import client +from turtle import back +from donationalerts_api.asyncio_api import Alert, Event +from backend_integration import BackendClient +from colors import * +import os, sys, asyncio +import ws + +class CustomAlerts(Alert): + backend: BackendClient + prices = {} + + convert_map = { + "month":30*24*60*60, + "week":7*24*60*60, + "day":1*24*60*60 + } + + def __init__(self, token, backend): + super().__init__(token) + + def run(self): + @self.event() + async def handler(event): + print(event) + self.calculate(event) + + async def calculate(self, event: Event): + if event.currency != "RUB": + warning(f"[{event.id}] donate is not RUB") + return None + + info("Update prices") + await self.update_prices_from_server() + + money = int(event.amount) + steam2 = self.backend.detect(event.message).steam2 + uid = event.id + + seconds = self.price_checker(money) + if seconds == 0: + warning(f"[{uid}] so smol donate {money} RUB") + + info(f"Add vip {steam2}, amount {money}") + await self.backend.vip(steam2, seconds, f"rub={int(money * 0.9)};", unique=f"da_{uid}") + + async def update_prices_from_server(self, exit_if_error = True): + #info("Fetch prices from server backend") + prices = await self.backend.prices(exit_if_error) + self.update_prices(prices) + + def update_prices(self, prices): + for price in prices: + if price["money_price"] == 0: + continue + self.prices = {} + self.prices.update({float(price["money_price"]) + float(price["money_price"] * price["da_percent"] / 10):self.convert_map[price['period']]}) + if not self.prices: + error("cannot get prices from server") + sys.exit(228) + + def price_checker(self, amount): + seconds2give = 0 + for rub, sec in self.prices.items(): + if amount >= rub and seconds2give <= sec: + seconds2give = sec + return seconds2give + +if __name__ == "__main__": + if not os.getenv("BACKEND_URL", "") or not os.getenv("SECRET_KEY", ""): + error("BACKEND_URL or SECRET_KEY is not setted!") + sys.exit(1) + if not os.getenv("DA_TOKEN", ""): + error("DA_TOKEN in not setted!") + sys.exit(2) + + print("Build date: "+os.getenv("BUILDDATE", "not setted")) + def run(): + client = CustomAlerts(os.getenv("DA_TOKEN"), BackendClient()) + client.run() + + ws.SERVICE_NAME = "dapay" + ws.START_AFTER_CONNECT = run + wsc = ws.WS(os.getenv("BACKEND_URL"), os.getenv("SECRET_KEY")) + wsc.run() \ No newline at end of file diff --git a/ws.py b/ws.py new file mode 100644 index 0000000..a6c8ee8 --- /dev/null +++ b/ws.py @@ -0,0 +1,61 @@ +import websocket, sys +from threading import Thread +from json import dumps +from time import sleep +import os + +START_AFTER_CONNECT = None +SERVICE_NAME = None + +def create_pulser(ws: websocket.WebSocketApp): + def run(ws): + builddate = int(os.getenv("BUILDDATE", "0")) + while 1: + ws.send_text(dumps({"name":SERVICE_NAME, "builddate":builddate})) + sleep(15) + thread = Thread(target=run, args=[ws], daemon=True) + thread.start() + +def start(): + print("substart") + + +class WS: + ws: websocket.WebSocketApp + def __init__(self, backend, auth): + if (START_AFTER_CONNECT is None or SERVICE_NAME is None): + print("Setup START_AFTER_CONNECT and SERVICE_NAME") + sys.exit(1) + else: + print(f"Run after setup {SERVICE_NAME}: {START_AFTER_CONNECT}") + + addr = backend + if not "wss://" in addr: + addr = addr.replace("https://", "wss://") + if not "/ws/services" in addr: + addr += "/ws/services" + + print(f"Connect to {addr}, secret len: {len(auth)}") + self.ws = websocket.WebSocketApp(addr, cookie="secretkey="+auth, on_close=self.on_close, on_open=self.on_open) + + @staticmethod + def on_close(ws_self, status_code, msg): + print(f"WS Close, code:{status_code}, msg: {msg}") + sys.exit(0) + + @staticmethod + def on_open(ws_self): + print("Connected") + create_pulser(ws_self) + if START_AFTER_CONNECT: + START_AFTER_CONNECT() + + def run(self): + if self.ws.run_forever(): + print("fuck") + +if __name__ == "__main__": + START_AFTER_CONNECT = start + SERVICE_NAME = "test" + wsc = WS("wss://tf2.pblr-nyk.pro/ws/services", "") + wsc.run() \ No newline at end of file