From b8155ef468e26d0a77df7e0694a00ebd9bd6a573 Mon Sep 17 00:00:00 2001 From: "DESKTOP-JVKHS7I\\Adam" Date: Tue, 28 Apr 2020 02:49:30 +0530 Subject: [PATCH] fishy network removed, integreted web push notificaitons --- fishy/__init__.py | 2 +- fishy/__main__.py | 42 +++++++++++------- fishy/systems/__init__.py | 1 - fishy/systems/config.py | 5 +-- fishy/systems/fishing_event.py | 9 ++-- fishy/systems/fishy_network.py | 40 ----------------- fishy/systems/globals.py | 1 + fishy/systems/gui.py | 80 ++++++++++++++++++++++++++++------ fishy/systems/helper.py | 19 +------- fishy/systems/web.py | 57 ++++++++++++++++++++++++ requirements.txt | 2 + 11 files changed, 162 insertions(+), 96 deletions(-) delete mode 100644 fishy/systems/fishy_network.py create mode 100644 fishy/systems/web.py diff --git a/fishy/__init__.py b/fishy/__init__.py index 168b65f..93a0876 100644 --- a/fishy/__init__.py +++ b/fishy/__init__.py @@ -1,2 +1,2 @@ from fishy.__main__ import main -__version__ = "0.2.8" +__version__ = "0.3.0" diff --git a/fishy/__main__.py b/fishy/__main__.py index bf1ad98..d0b77be 100644 --- a/fishy/__main__.py +++ b/fishy/__main__.py @@ -9,28 +9,26 @@ import cv2 import pywintypes import fishy from fishy.systems import * -from fishy.systems import helper +from fishy.systems import helper, web from fishy.systems.config import Config from fishy.systems.gui import GUI, GUIEvent, GUIFunction class Fishy: - def __init__(self, gui_ref, gui_event_buffer): + def __init__(self, gui_ref, gui_event_buffer, config): self.gui_events = gui_event_buffer self.start = False self.fishPixWindow = None self.fishy_thread = None self.gui = gui_ref + self.config = config - def start_fishing(self, ip: str, action_key: str, borderless: bool, collect_r: bool): + def start_fishing(self, action_key: str, borderless: bool, collect_r: bool): """ Starts the fishing code explained in comments in detail """ - if ip != "": - net.initialize(ip) - # initialize widow try: Window.Init(borderless) @@ -43,7 +41,7 @@ class Fishy: FishingMode("hook", 0, HookEvent(action_key, collect_r)) FishingMode("stick", 1, StickEvent()) FishingMode("look", 2, LookEvent()) - FishingMode("idle", 3, IdleEvent(ip != "")) + FishingMode("idle", 3, IdleEvent(self.config.get("uid"))) self.fishPixWindow = Window(color=cv2.COLOR_RGB2HSV) @@ -97,14 +95,29 @@ class Fishy: Thread(target=show, args=()).start() -def initialize(c: Config, gui): - if c.get("first_launch", True, False): +def create_shortcut_first(gui, c): + if not c.get("shortcut_created", False): helper.create_shortcut(gui) - c.set("first_launch", False) + c.set("shortcut_created", True) + + +def initialize_uid(config: Config): + if config.get("uid") is not None: + return + + new_uid = helper.create_new_uid() + if web.register_user(new_uid): + config.set("uid", new_uid) + else: + logging.error("Couldn't register uid, some features might not work") + + +def initialize(gui, c: Config): + create_shortcut_first(gui, c) + initialize_uid(c) try: auto_upgrade() - helper.ping(c, "started") except Exception: pass @@ -114,6 +127,8 @@ def initialize(c: Config, gui): helper.install_thread_excepthook() sys.excepthook = helper.unhandled_exception_logging + helper.check_addon() + def wait_and_check(): time.sleep(10) @@ -129,13 +144,10 @@ def main(): gui.start() logging.info(f"Fishybot v{fishy.__version__}") - initialize(c, gui) - - helper.check_addon() + initialize(gui, c) bot = Fishy(gui, events_buffer) bot.start_event_handler() - helper.ping(c, f"closed,fishes:{G.totalFishCaught}") if __name__ == "__main__": diff --git a/fishy/systems/__init__.py b/fishy/systems/__init__.py index cc3a7e3..dfec628 100644 --- a/fishy/systems/__init__.py +++ b/fishy/systems/__init__.py @@ -2,6 +2,5 @@ from fishy.systems.fishing_event import HookEvent, StickEvent, LookEvent, IdleEv from fishy.systems.fishing_mode import FishingMode from fishy.systems.globals import G from fishy.systems.pixel_loc import PixelLoc -import fishy.systems.fishy_network as net from fishy.systems.window import Window from fishy.systems.auto_update import auto_upgrade diff --git a/fishy/systems/config.py b/fishy/systems/config.py index 42de830..a47f048 100644 --- a/fishy/systems/config.py +++ b/fishy/systems/config.py @@ -10,12 +10,9 @@ class Config: def __init__(self): self.config_dict = json.loads(open(filename).read()) if os.path.exists(filename) else dict() - def get(self, key, default=None, save=True): + def get(self, key, default=None): if key in self.config_dict: return self.config_dict[key] - - if save: - self.set(key, default) return default def set(self, key, value, save=True): diff --git a/fishy/systems/fishing_event.py b/fishy/systems/fishing_event.py index 7bce3b2..3e5ac71 100644 --- a/fishy/systems/fishing_event.py +++ b/fishy/systems/fishing_event.py @@ -8,9 +8,9 @@ from abc import abstractmethod, ABC import pyautogui +from fishy.systems import web from fishy.systems.globals import G from fishy.systems.helper import round_float -import fishy.systems.fishy_network as net class FishEvent(ABC): @@ -73,12 +73,12 @@ class IdleEvent(FishEvent): State when the fishing hole is depleted or the bot is doing nothing """ - def __init__(self, use_net): + def __init__(self, uid): """ sets the flag to send notification on phone :param use_net: true if user wants to send notification on phone """ - self.use_net = use_net + self.uid = uid def onEnterCallback(self, previousMode): """ @@ -87,8 +87,7 @@ class IdleEvent(FishEvent): """ G.fishCaught = 0 - if self.use_net: - net.sendHoleDeplete(G.fishCaught) + web.send_hole_deplete(self.uid, G.fishCaught) if previousMode.name == "hook": logging.info("HOLE DEPLETED") diff --git a/fishy/systems/fishy_network.py b/fishy/systems/fishy_network.py deleted file mode 100644 index 2ebc28f..0000000 --- a/fishy/systems/fishy_network.py +++ /dev/null @@ -1,40 +0,0 @@ -import logging -import socket -import json - -PORT = 8023 -MESSAGE = "yo" -RETRY_LIMIT = 5 -IP = 0 -s = None - - -def initialize(ip): - global s, IP - IP = ip - - -def send_message(message, count=1): - try: - sock = socket.socket() - sock.connect((IP, PORT)) - sock.send(bytes(message, "utf-8")) - sock.close() - except ConnectionRefusedError: - logging.info("Connection Refused, please turn on service on mobile") - except TimeoutError: - logging.info("Timeout Error") - - if count < RETRY_LIMIT: - send_message(message, count+1) - - -def sendHoleDeplete(count): - message = {"action": "holeDeplete", "fishCount": count} - jsonString = json.dumps(message) - send_message(jsonString) - - -if __name__ == "__main__": - initialize("192.168.0.192") - sendHoleDeplete(2) diff --git a/fishy/systems/globals.py b/fishy/systems/globals.py index 634aec8..4331803 100644 --- a/fishy/systems/globals.py +++ b/fishy/systems/globals.py @@ -6,3 +6,4 @@ class G: totalFishCaught = 0 stickInitTime = 0 FishingStarted = False + _is_subbed = None diff --git a/fishy/systems/gui.py b/fishy/systems/gui.py index d8c9a63..a3af645 100644 --- a/fishy/systems/gui.py +++ b/fishy/systems/gui.py @@ -1,5 +1,6 @@ import logging import os +import tempfile import time from enum import Enum from logging import StreamHandler @@ -8,10 +9,10 @@ from tkinter import filedialog, messagebox from tkinter.ttk import * from typing import Tuple, List, Callable, Optional +import pyqrcode from ttkthemes import ThemedTk import threading -from fishy.systems import helper from fishy.systems.config import Config @@ -52,6 +53,7 @@ class GUI: self.root = None self.console = None self.start_button = None + self.notif = None self.thread = threading.Thread(target=self.create, args=()) @@ -61,6 +63,9 @@ class GUI: rootLogger.addHandler(new_console) def create(self): + from fishy.systems import helper + from fishy.systems import web + self.root = ThemedTk(theme="equilux", background=True) self.root.title("Fiishybot for Elder Scrolls Online") self.root.geometry('650x550') @@ -82,7 +87,7 @@ class GUI: debug_menu = Menu(menubar, tearoff=0) debug_menu.add_command(label="Check PixelVal", - command=lambda: self._event_trigger(GUIEvent.CHECK_PIXELVAL)) + command=lambda: self._event_trigger(GUIEvent.CHECK_PIXELVAL, ())) debug_var = IntVar() debug_var.set(int(self.config.get('debug', False))) @@ -90,6 +95,7 @@ class GUI: def keep_console(): self.config.set("debug", bool(debug_var.get())) logging.debug("Restart to update the changes") + debug_menu.add_checkbutton(label="Keep Console", command=keep_console, variable=debug_var) debug_menu.add_command(label="Log Dump", command=lambda: logging.error("Not Implemented")) @@ -116,13 +122,14 @@ class GUI: # region controls left_frame = Frame(controls_frame) - Label(left_frame, text="Android IP").grid(row=0, column=0) - ip = Entry(left_frame) - ip.insert(0, self.config.get("ip", "")) - ip.grid(row=0, column=1) + Label(left_frame, text="Notification:").grid(row=0, column=0) + + self.notif = IntVar(value=int(web.is_subbed(self.config.get('uid')))) + Checkbutton(left_frame, command=self.give_notification_link, + variable=self.notif).grid(row=0, column=1) Label(left_frame, text="Fullscreen: ").grid(row=1, column=0, pady=(5, 5)) - borderless = Checkbutton(left_frame, variable=IntVar(value=int(self.config.get("borderless", False)))) + borderless = Checkbutton(left_frame, ) borderless.grid(row=1, column=1) left_frame.grid(row=0, column=0) @@ -145,8 +152,7 @@ class GUI: self.start_button = Button(self.root, text="STOP" if self._bot_running else "START", width=25) def start_button_callback(): - args = (ip.get(), - action_key_entry.get(), + args = (action_key_entry.get(), borderless.instate(['selected']), collect_r.instate(['selected'])) self._event_trigger(GUIEvent.START_BUTTON, args) @@ -158,7 +164,7 @@ class GUI: self._apply_theme(self.config.get("dark_mode", True)) self.root.update() - self.root.minsize(self.root.winfo_width(), self.root.winfo_height()) + self.root.minsize(self.root.winfo_width()+10, self.root.winfo_height()+10) self.root.protocol("WM_DELETE_WINDOW", self._set_destroyed) self.destroyed = False @@ -171,7 +177,7 @@ class GUI: self.start_restart = False self.create() if self.destroyed: - self._event_trigger(GUIEvent.QUIT) + self._event_trigger(GUIEvent.QUIT, ()) break time.sleep(0.01) @@ -213,8 +219,7 @@ class GUI: self.console.see("end") # scroll to bottom self.console['state'] = 'disabled' - def _save_config(self, ip, action_key, borderless, collect_r): - self.config.set("ip", ip, False) + def _save_config(self, action_key, borderless, collect_r): self.config.set("action_key", action_key, False) self.config.set("borderless", borderless, False) self.config.set("collect_r", collect_r, False) @@ -225,3 +230,52 @@ class GUI: def call(self, gui_func: GUIFunction, args: Tuple = None): self._function_queue.append((gui_func, args)) + + def give_notification_link(self): + from fishy.systems import web + + if web.is_subbed(self.config.get("uid")): + web.unsub(self.config.get("uid")) + return + + self.notif.set(0) + + def quit_top(): + top.destroy() + top_running[0] = False + + def check(): + if web.is_subbed(self.config.get("uid"), False): + messagebox.showinfo("Note!", "Notification configured successfully!") + web.send_notification(self.config.get("uid"), "Sending a test notification :D") + self.notif.set(1) + quit_top() + else: + messagebox.showerror("Error", "Subscription wasn't successful") + + qrcode = pyqrcode.create(web.get_notification_page(self.config.get("uid"))) + t = os.path.join(tempfile.gettempdir(), "fishyqr.png") + qrcode.png(t, scale=8) + + top_running = [True] + + top = Toplevel(background=self.root["background"]) + top.minsize(width=500, height=500) + top.title("Notification Setup") + + Label(top, text="Step 1.").pack(pady=(5, 5)) + Label(top, text="Scan the QR Code on your Phone and press \"Enable Notification\"").pack(pady=(5, 5)) + canvas = Canvas(top, width=qrcode.get_png_size(8), height=qrcode.get_png_size(8)) + canvas.pack(pady=(5, 5)) + Label(top, text="Step 2.").pack(pady=(5, 5)) + Button(top, text="Check", command=check).pack(pady=(5, 5)) + + image = PhotoImage(file=t) + canvas.create_image(0, 0, anchor="nw", image=image) + + + top.protocol("WM_DELETE_WINDOW", quit_top) + top.grab_set() + while top_running[0]: + top.update() + top.grab_release() diff --git a/fishy/systems/helper.py b/fishy/systems/helper.py index d607553..c2187ab 100644 --- a/fishy/systems/helper.py +++ b/fishy/systems/helper.py @@ -14,12 +14,7 @@ import numpy as np from uuid import uuid1 from hashlib import md5 -import requests -from whatsmyip.ip import get_ip -from whatsmyip.providers import GoogleDnsProvider - import fishy -from fishy.systems.config import Config import functools from fishy.systems.gui import GUIFunction @@ -76,18 +71,8 @@ def disable_logging(func): return wrapper -@disable_logging -def req(config: Config, data): - url = 'https://dcserver1.herokuapp.com/fishy' - ip = get_ip(GoogleDnsProvider) - h = config.get("hash", md5(str(uuid1()).encode()).hexdigest()) - body = {"hash": h, "data": data, "ip": ip} - requests.post(url, json=body) - - -def ping(config: Config, data): - if config.get("check", True, False): - threading.Thread(target=req, args=(config, data,)).start() +def create_new_uid(): + return md5(str(uuid1()).encode()).hexdigest() def install_thread_excepthook(): diff --git a/fishy/systems/web.py b/fishy/systems/web.py new file mode 100644 index 0000000..645222e --- /dev/null +++ b/fishy/systems/web.py @@ -0,0 +1,57 @@ +import requests + +from fishy.systems.globals import G +from fishy.systems.helper import disable_logging + +domain = "https://fishyeso.herokuapp.com" + +user = "/api/user" +notify = "/api/notify" +subscription = "/api/subscription/" + + +@disable_logging +def register_user(uid): + body = {"uid": uid} + response = requests.post(domain + user, json=body) + print(response.status_code) + return response.ok and response.json()["success"] + + +def get_notification_page(uid): + return domain+f"?uid={uid}" + + +@disable_logging +def send_notification(uid, message): + if not is_subbed(uid): + return False + + body = {"uid": uid, "message": message} + response = requests.post(domain + notify, json=body) + return response.json()["success"], response.json()["error"] + + +def send_hole_deplete(uid, fishes_caught): + send_notification(uid, f"Hole depleted, {fishes_caught} fishes caught!") + + +@disable_logging +def is_subbed(uid, lazy=True): + if lazy and G._is_subbed is not None: + return G._is_subbed + + if uid is None: + return False + + body = {"uid": uid} + response = requests.get(domain + subscription, params=body) + G._is_subbed = response.json()["subbed"] + return G._is_subbed + + +@disable_logging +def unsub(uid): + G._is_subbed = False + body = {"uid": uid} + requests.delete(domain + subscription, json=body) diff --git a/requirements.txt b/requirements.txt index aff8dc7..0960da8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,5 @@ pyautogui requests beautifulsoup4 whatsmyip +pyqrcode +pypng