diff --git a/app/damination.py b/app/damination.py index 6992dde..c886155 100644 --- a/app/damination.py +++ b/app/damination.py @@ -10,19 +10,17 @@ from datetime import datetime import aiohttp + class StatusEndpointFilter(logging.Filter): def filter(self, record): if 'GET /status' in record.getMessage(): return False return True - # Config Parser config = configparser.ConfigParser() config.read("config/settings.ini") - - MAX_RETRIES = config.getint("config", "MAX_RETRIES") SERVER_IP = config.get("server", "ip") SERVER_PORT = config.get("server", "port") @@ -37,7 +35,6 @@ file_handler = logging.handlers.RotatingFileHandler(log_filename, maxBytes=10000 file_handler.setLevel(logging.INFO) file_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') file_handler.setFormatter(file_formatter) - file_handler.addFilter(StatusEndpointFilter()) # Create stream handler @@ -55,6 +52,7 @@ class Roulette(BaseModel): name : str conf : dict + class Content(BaseModel): account : str name : str @@ -63,6 +61,7 @@ class Content(BaseModel): amount : int | None roulette : Roulette | None + class Donate(BaseModel): code : str content : Content @@ -70,6 +69,7 @@ class Donate(BaseModel): class DaminationAPI(): + def __init__(self): self.WIDGET_IDS = [] self.queue = asyncio.Queue() @@ -79,13 +79,19 @@ class DaminationAPI(): self.connections = {} self.processing_tasks = [] + async def initialize_widgets(self): - widgets = config.get("widget", "ids").split(",") if config.has_option("widget", "ids"): - for widget in widgets: - await self.add_widget_and_start_fetching_notifications(widget) - - logger.info(f"initialize wigets : {widgets}") + widgets = config.get("widget", "ids").split(",") + + if widgets[0]: + for widget in widgets: + await self.add_widget_and_start_fetching_notifications(widget) + logger.info(f"initialize wigets : {widgets}") + + else: + logger.error(f"widgets empty") + async def process_notification(self): while True: @@ -93,48 +99,85 @@ class DaminationAPI(): if donate is not None: for widget_id, value in donate.items(): await self.send_notifications_to_subscribers(widget_id, value) + else: + logger.error("No notifications in the queue, breaking loop.") break - def add_subscriber(self, widget_id: str, url: str) -> bool: + + def get_subscribers(self, widget_id: str) -> list: + """ + 주어진 widget_id에 해당하는 구독자 목록을 반환합니다. + widget_id: 구독자 목록을 얻을 위젯 ID + """ + + if widget_id in self.subscribers: + subscribers = self.subscribers[widget_id] + logger.info(f"get {widget_id} subscribers : {subscribers}") + return subscribers + + else: + logger.error(f"no subscribers") + return [] + + + def add_subscriber(self, widget_id: str, url: str) -> str: if widget_id not in self.subscribers: self.subscribers[widget_id] = [] if url not in self.subscribers[widget_id]: self.subscribers[widget_id].append(url) - return True + logger.info(f"Added subscriber: widget_id={widget_id}, url={url}") + return widget_id + else: - return False + logger.error(f"Subscriber already exists: widget_id={widget_id}, url={url}") + return '' - def remove_subscriber(self, widget_id: str, url: str) -> bool: + + def remove_subscriber(self, widget_id: str, url: str) -> str: if widget_id in self.subscribers and url in self.subscribers[widget_id]: self.subscribers[widget_id].remove(url) - return True + logger.info(f"Removed subscriber: widget_id={widget_id}, url={url}") + return widget_id + else: - return False + logger.error(f"Subscriber not found: widget_id={widget_id}, url={url}") + return '' def get_widget_ids(self) -> list: """ 현재 설정된 모든 위젯 ID 목록을 반환합니다. """ - - logger.debug(f"get widget {self.WIDGET_IDS}") - return self.WIDGET_IDS + if self.WIDGET_IDS: + logger.info(f"get widget {self.WIDGET_IDS}") + return self.WIDGET_IDS + + else: + logger.error(f"widget id empty") + return [] - def add_widget_id(self, widget_id:str): + + def add_widget_id(self, widget_id:str) -> str: """ 주어진 widget_id를 위젯 ID 목록에 추가합니다. widget_id: 추가할 위젯 ID """ - try: - self.WIDGET_IDS.append(widget_id) - logger.debug(f"add widget {widget_id}") + if widget_id not in self.WIDGET_IDS: + self.WIDGET_IDS.append(widget_id) + logger.info(f"add widget {widget_id}") + return widget_id + + else: + logger.error(f"{widget_id} already exists in the list.") + return '' except Exception as e: logger.error(e) + def remove_widget_id(self, widget_id: str) -> str: """ 주어진 widget_id를 위젯 ID 목록에서 제거합니다. 제거한 widget_id를 반환하며, @@ -145,10 +188,11 @@ class DaminationAPI(): try: if widget_id in self.WIDGET_IDS: widget = self.WIDGET_IDS.pop(self.WIDGET_IDS.index(widget_id)) - logger.debug(f"delete widget {widget}") + logger.info(f"remove widget {widget}") return widget else: + logger.error(f"not in widget") return '' except Exception as e: @@ -203,6 +247,7 @@ class DaminationAPI(): self.remove_widget_id(widget_id) logger.info(f"Connection failed for widget_id: {widget_id}") + @staticmethod def get_websocket_payload(widget_id:str) -> str: """ @@ -219,7 +264,7 @@ class DaminationAPI(): return payload - async def add_widget_and_start_fetching_notifications(self, widget_id: str) -> bool: + async def add_widget_and_start_fetching_notifications(self, widget_id: str) -> str: """ 주어진 widget_id를 위젯 ID 목록에 추가하고 알림을 가져오는 작업을 시작합니다. widget_id: 추가할 위젯 ID @@ -229,13 +274,14 @@ class DaminationAPI(): self.add_widget_id(widget_id) task = asyncio.create_task(self.fetch_notifications(self.queue, widget_id)) self.fetch_tasks.append(task) - return True + return widget_id else: - logger.warning(f"Widget ID {widget_id} already exists in the list.") - return False + logger.error(f"Widget ID {widget_id} already exists in the list.") + return '' - async def remove_widget_and_stop_fetching_notifications(self, widget_id: str): + + async def remove_widget_and_stop_fetching_notifications(self, widget_id: str) -> str: """ 주어진 widget_id를 위젯 ID 목록에서 제거하고 알림을 가져오는 작업을 중단합니다. widget_id: 제거할 위젯 ID @@ -246,8 +292,10 @@ class DaminationAPI(): fetch_task = self.fetch_tasks.pop(index) fetch_task.cancel() await fetch_task + return widget_id else: - logger.warning(f"Widget ID {widget_id} not found.") + logger.error(f"Widget ID {widget_id} not found.") + return '' async def pop_notification_from_queue(self): @@ -261,21 +309,12 @@ class DaminationAPI(): else: return None + async def get_connection(self, url: str): if url not in self.connections: self.connections[url] = aiohttp.ClientSession() return self.connections[url] - def get_subscribers(self, widget_id: str) -> list: - """ - 주어진 widget_id에 해당하는 구독자 목록을 반환합니다. - widget_id: 구독자 목록을 얻을 위젯 ID - """ - - if widget_id in self.subscribers: - return self.subscribers[widget_id] - else: - return [] async def send_notifications_to_subscribers(self, widget_id: str, donate): """ @@ -300,6 +339,7 @@ class DaminationAPI(): else: logger.error(f"Failed to send notification to {subscriber_url} with status code {response.status}.") + async def run(self): await self.initialize_widgets() @@ -310,6 +350,7 @@ class DaminationAPI(): await task await asyncio.sleep(0.1) + async def close(self): for session in self.connections.values(): await session.close() \ No newline at end of file diff --git a/app/main.py b/app/main.py index 6d4250e..ffdd96b 100644 --- a/app/main.py +++ b/app/main.py @@ -12,7 +12,10 @@ app = web.Application() async def get_widgets(request): widget_id = request.match_info['widget_id'] subscribers = toonat.get_subscribers(widget_id) - return web.json_response(subscribers) + if subscribers: + return web.json_response(subscribers) + else: + return web.Response(text=f"no subscribers") @routes.get('/subscribe/{widget_id}') async def subscribe(request): @@ -46,7 +49,10 @@ async def get_widgets(request): 현재 설정된 모든 위젯 ID 목록을 반환하는 웹 API 엔드포인트입니다. """ widget_ids = toonat.get_widget_ids() - return web.json_response(widget_ids) + if widget_ids: + return web.json_response(widget_ids) + else: + return web.Response(text=f"no widget_ids") @routes.get('/add_widget')