Files
IWaniHugThatGator-Demo-Public/game/python-packages/pypresence/baseclient.py
2024-03-06 19:57:33 -06:00

124 lines
4.4 KiB
Python

import asyncio
import inspect
import json
import os
import struct
import sys
import tempfile
from typing import Union, Optional
# TODO: Get rid of this import * lol
from .exceptions import *
from .payloads import Payload
from .utils import get_ipc_path, get_event_loop
class BaseClient:
def __init__(self, client_id: str, **kwargs):
pipe = kwargs.get('pipe', None)
loop = kwargs.get('loop', None)
handler = kwargs.get('handler', None)
self.isasync = kwargs.get('isasync', False)
client_id = str(client_id)
self.ipc_path = get_ipc_path(pipe)
if not self.ipc_path:
raise DiscordNotFound
if loop is not None:
self.update_event_loop(loop)
else:
self.update_event_loop(get_event_loop())
self.sock_reader: Optional[asyncio.StreamReader] = None
self.sock_writer: Optional[asyncio.StreamWriter] = None
self.client_id = client_id
if handler is not None:
if not inspect.isfunction(handler):
raise PyPresenceException('Error handler must be a function.')
args = inspect.getfullargspec(handler).args
if args[0] == 'self':
args = args[1:]
if len(args) != 2:
raise PyPresenceException('Error handler should only accept two arguments.')
if self.isasync:
if not inspect.iscoroutinefunction(handler):
raise InvalidArgument('Coroutine', 'Subroutine', 'You are running async mode - '
'your error handler should be awaitable.')
err_handler = self._async_err_handle
else:
err_handler = self._err_handle
loop.set_exception_handler(err_handler)
self.handler = handler
if getattr(self, "on_event", None): # Tasty bad code ;^)
self._events_on = True
else:
self._events_on = False
def update_event_loop(self, loop):
# noinspection PyAttributeOutsideInit
self.loop = loop
asyncio.set_event_loop(self.loop)
def _err_handle(self, loop, context: dict):
result = self.handler(context['exception'], context['future'])
if inspect.iscoroutinefunction(self.handler):
loop.run_until_complete(result)
# noinspection PyUnusedLocal
async def _async_err_handle(self, loop, context: dict):
await self.handler(context['exception'], context['future'])
async def read_output(self):
try:
preamble = await self.sock_reader.read(8)
status_code, length = struct.unpack('<II', preamble[:8])
data = await self.sock_reader.read(length)
except BrokenPipeError:
raise InvalidID
payload = json.loads(data.decode('utf-8'))
if payload["evt"] == "ERROR":
raise ServerError(payload["data"]["message"])
return payload
def send_data(self, op: int, payload: Union[dict, Payload]):
if isinstance(payload, Payload):
payload = payload.data
payload = json.dumps(payload)
assert self.sock_writer is not None, "You must connect your client before sending events!"
self.sock_writer.write(
struct.pack(
'<II',
op,
len(payload)) +
payload.encode('utf-8'))
async def handshake(self):
if sys.platform == 'linux' or sys.platform == 'darwin':
self.sock_reader, self.sock_writer = await asyncio.open_unix_connection(self.ipc_path)
elif sys.platform == 'win32' or sys.platform == 'win64':
self.sock_reader = asyncio.StreamReader(loop=self.loop)
reader_protocol = asyncio.StreamReaderProtocol(
self.sock_reader, loop=self.loop)
try:
self.sock_writer, _ = await self.loop.create_pipe_connection(lambda: reader_protocol, self.ipc_path)
except FileNotFoundError:
raise InvalidPipe
self.send_data(0, {'v': 1, 'client_id': self.client_id})
preamble = await self.sock_reader.read(8)
code, length = struct.unpack('<ii', preamble)
data = json.loads(await self.sock_reader.read(length))
if 'code' in data:
raise DiscordError(data['code'], data['message'])
if self._events_on:
self.sock_reader.feed_data = self.on_event