From 16604e2c887d2ea549759166e2a321d4c2c4d77e Mon Sep 17 00:00:00 2001 From: Alessandro Maggio Date: Sat, 23 Jan 2021 23:13:56 +0100 Subject: [PATCH] Create a single class Message for handle the json data --- TwitchChannelPointsMiner/classes/Message.py | 54 +++++++++++++ .../classes/WebSocketsPool.py | 75 ++++++++----------- TwitchChannelPointsMiner/utils.py | 47 ++---------- 3 files changed, 92 insertions(+), 84 deletions(-) create mode 100644 TwitchChannelPointsMiner/classes/Message.py diff --git a/TwitchChannelPointsMiner/classes/Message.py b/TwitchChannelPointsMiner/classes/Message.py new file mode 100644 index 0000000..5848bfd --- /dev/null +++ b/TwitchChannelPointsMiner/classes/Message.py @@ -0,0 +1,54 @@ +import json + +from TwitchChannelPointsMiner.utils import server_time + + +class Message: + def __init__(self, data): + self.topic, self.topic_user = data["topic"].split(".") + + self.message = json.loads(data["message"]) + self.type = self.message["type"] + + self.data = self.message["data"] if "data" in self.message else None + + self.timestamp = self.__get_timestamp() + self.channel_id = self.__get_channel_id() + + self.identifier = f"{self.type}.{self.topic}.{self.channel_id}" + + def __repr__(self): + return self.message + + def __str__(self): + return self.message + + def __get_timestamp(self): + return ( + server_time(self.message) + if self.data is None + else ( + self.data["timestamp"] + if "timestamp" in self.data + else server_time(self.data) + ) + ) + + def __get_channel_id(self): + return ( + self.topic_user + if self.data is None + else ( + self.data["prediction"]["channel_id"] + if "prediction" in self.data + else ( + self.data["claim"]["channel_id"] + if "claim" in self.data + else ( + self.data["channel_id"] + if "channel_id" in self.data + else self.topic_user + ) + ) + ) + ) diff --git a/TwitchChannelPointsMiner/classes/WebSocketsPool.py b/TwitchChannelPointsMiner/classes/WebSocketsPool.py index a510e7a..d378c0a 100644 --- a/TwitchChannelPointsMiner/classes/WebSocketsPool.py +++ b/TwitchChannelPointsMiner/classes/WebSocketsPool.py @@ -3,14 +3,14 @@ import threading import time import json import random -import code from dateutil import parser from TwitchChannelPointsMiner.classes.EventPrediction import EventPrediction from TwitchChannelPointsMiner.classes.Raid import Raid from TwitchChannelPointsMiner.classes.TwitchWebSocket import TwitchWebSocket -from TwitchChannelPointsMiner.utils import get_streamer_index, get_timestamp, get_channel_id +from TwitchChannelPointsMiner.classes.Message import Message +from TwitchChannelPointsMiner.utils import get_streamer_index logger = logging.getLogger(__name__) @@ -111,40 +111,29 @@ class WebSocketsPool: if response["type"] == "MESSAGE": # We should create a Message class ... - data = response["data"] - topic, topic_user = data["topic"].split(".") - - message = json.loads(data["message"]) - message_type = message["type"] - - message_timestamp = get_timestamp(message) - channel_id = get_channel_id(message, topic_user) - message_data = message["data"] if "data" in message else None + message = Message(response["data"]) # If we have more than one PubSub connection, messages may be duplicated # Check the concatenation between message_type.top.channel_id if ( ws.last_message_type_channel is not None and ws.last_message_timestamp is not None - and ws.last_message_timestamp == message_timestamp - and ws.last_message_type_channel - == f"{message_type}.{topic}.{channel_id}" + and ws.last_message_timestamp == message.timestamp + and ws.last_message_type_channel == message.identifier ): return - ws.last_message_timestamp = message_timestamp - ws.last_message_type_channel = ( - f"{message_type}.{topic}.{channel_id}" - ) + ws.last_message_timestamp = message.timestamp + ws.last_message_type_channel = message.identifier - streamer_index = get_streamer_index(ws.streamers, channel_id) + streamer_index = get_streamer_index(ws.streamers, message.channel_id) if streamer_index != -1: try: - if topic == "community-points-user-v1": - if message_type == "points-earned": - earned = message_data["point_gain"]["total_points"] - reason_code = message_data["point_gain"]["reason_code"] - balance = message_data["balance"]["balance"] + if message.topic == "community-points-user-v1": + if message.type == "points-earned": + earned = message.data["point_gain"]["total_points"] + reason_code = message.data["point_gain"]["reason_code"] + balance = message.data["balance"]["balance"] ws.streamers[streamer_index].channel_points = balance logger.info( f"+{earned} → {ws.streamers[streamer_index]} - Reason: {reason_code}.", @@ -153,40 +142,38 @@ class WebSocketsPool: ws.streamers[streamer_index].update_history( reason_code, earned ) - elif message_type == "claim-available": + elif message.type == "claim-available": ws.twitch.claim_bonus( ws.streamers[streamer_index], - message_data["claim"]["id"], + message.data["claim"]["id"], ) - elif topic == "video-playback-by-id": + elif message.topic == "video-playback-by-id": # There is stream-up message type, but it's sent earlier than the API updates - if message_type == "stream-down": + if message.type == "stream-down": if ws.streamers[streamer_index].is_online is True: ws.streamers[streamer_index].set_offline() - elif message_type == "viewcount": + elif message.type == "viewcount": ws.twitch.check_streamer_online( ws.streamers[streamer_index] ) - elif topic == "raid": - if message_type == "raid_update_v2": + elif message.topic == "raid": + if message.type == "raid_update_v2": raid = Raid( message["raid"]["id"], message["raid"]["target_login"] ) ws.twitch.update_raid(ws.streamers[streamer_index], raid) - elif topic == "predictions-channel-v1": + elif message.topic == "predictions-channel-v1": - # if message_type == "event-created" - # if message_type == "event-updated" + # if message.type == "event-created" + # if message.type == "event-updated" - event_dict = message_data["event"] + event_dict = message.data["event"] event_id = event_dict["id"] event_status = event_dict["status"] - current_timestamp = parser.parse(message_data["timestamp"]) - if event_id not in ws.events_predictions: if event_status == "ACTIVE": prediction_window_seconds = float( @@ -208,7 +195,7 @@ class WebSocketsPool: ) if ( ws.streamers[streamer_index].is_online - and event.closing_bet_after(current_timestamp) > 0 + and event.closing_bet_after(message.timestamp) > 0 ): ws.events_predictions[event_id] = event if ws.twitch_browser.currently_is_betting is False: @@ -222,7 +209,7 @@ class WebSocketsPool: # place_bet_thread = threading.Timer(event.closing_bet_after(current_timestamp), ws.twitch.make_predictions, (ws.events_predictions[event_id],)) start_after = ( event.closing_bet_after( - current_timestamp + message.timestamp ) - execution_time ) @@ -256,11 +243,11 @@ class WebSocketsPool: event_dict["outcomes"] ) - elif topic == "predictions-user-v1": + elif message.topic == "predictions-user-v1": # message_type == "prediction-made" # Confirm the prediction ... - if message_type == "prediction-result": - event_id = message_data["prediction"]["event_id"] - event_result = message_data["prediction"]["result"] + if message.type == "prediction-result": + event_id = message.data["prediction"]["event_id"] + event_result = message.data["prediction"]["result"] if event_id in ws.events_predictions: logger.info( f"{ws.events_predictions[event_id]} - Result: {event_result['type']}, Points won: {event_result['points_won'] if event_result['points_won'] else 0}", @@ -278,7 +265,7 @@ class WebSocketsPool: except Exception: logger.error( - f"Exception raised for topic: {topic} and message: {message}", + f"Exception raised for topic: {message.topic} and message: {message}", exc_info=True, ) diff --git a/TwitchChannelPointsMiner/utils.py b/TwitchChannelPointsMiner/utils.py index 7567e58..b10ef94 100644 --- a/TwitchChannelPointsMiner/utils.py +++ b/TwitchChannelPointsMiner/utils.py @@ -13,52 +13,19 @@ def get_streamer_index(streamers, channel_id): return -1 +def float_round(value): + return round(float(value), 2) + + def server_time(message_data): return ( - datetime.fromtimestamp(message_data["server_time"], timezone.utc).isoformat() + "Z" + datetime.fromtimestamp(message_data["server_time"], timezone.utc).isoformat() + + "Z" if message_data is not None and "server_time" in message_data else datetime.fromtimestamp(time.time(), timezone.utc).isoformat() + "Z" ) -def get_timestamp(message): - message_data = message["data"] if "data" in message else None - return ( - server_time(message) - if message_data is None - else ( - message_data["timestamp"] - if "timestamp" in message_data - else server_time(message_data) - ) - ) - - -def get_channel_id(message, topic_user): - message_data = message["data"] if "data" in message else None - return ( - topic_user - if message_data is None - else ( - message_data["prediction"]["channel_id"] - if "prediction" in message_data - else ( - message_data["claim"]["channel_id"] - if "claim" in message_data - else ( - message_data["channel_id"] - if "channel_id" in message_data - else topic_user - ) - ) - ) - ) - - -def float_round(value): - return round(float(value), 2) - - # https://en.wikipedia.org/wiki/Cryptographic_nonce def create_nonce(length=30): nonce = "" @@ -71,4 +38,4 @@ def create_nonce(length=30): else: char = chr(ord("A") + char_index - 26 - 10) nonce += char - return nonce \ No newline at end of file + return nonce