commit 837113ea9c9c57ce6f8e3e8d1e6836ea1ef35f83 Author: Ilya Bezrukov Date: Wed Jul 31 04:45:12 2024 +0300 Initial diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a0575fb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.10-alpine + +# install requirements +RUN --mount=type=cache,target=/root/.cache/pip \ + --mount=type=bind,source=requirements.txt,target=requirements.txt \ + pip install -r requirements.txt + +COPY tap.py /app/ + +WORKDIR /app + +CMD ["python3", "tap.py"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f229360 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +requests diff --git a/tap.py b/tap.py new file mode 100644 index 0000000..f9bc0a5 --- /dev/null +++ b/tap.py @@ -0,0 +1,101 @@ +import time +import os +import random +import signal +import sys +from dataclasses import dataclass + +import requests + + +URL = "https://api.hamsterkombatgame.io/clicker/tap" + +ONETAP_TIME = float(os.getenv("ONETAP_TIME", 0.1614)) +GEN_PER_SEC = int(os.getenv("GEN_PER_SEC", 3)) +MAX_TAPS = int(os.getenv("MAX_TAPS", 1000)) +MIN_TAPS = int(os.getenv("MIN_TAPS", 0)) +RAND_DELTA = int(os.getenv("RAND_DELTA", 50)) +EXTRA_WAIT = int(os.getenv("EXTRA_WAIT", 5)) + +AUTH = os.getenv("AUTH") +DRY_RUN = bool(int(os.getenv("DRY_RUN", False))) + + + +class RunState: + def __init__(self, initial: bool = True): + self._running = initial + signal.signal(signal.SIGINT, self.sighandler) + signal.signal(signal.SIGTERM, self.sighandler) + + @property + def running(self): + return self._running + + def sighandler(self, signum, frame): + self.kill() + + def kill(self): + self._running = False + sys.exit(0) + + +@dataclass +class Tap: + tap_count: int + tap_available: int + regen_wait: int + + @classmethod + def fake(cls): + tap_count = random.randint(MIN_TAPS + RAND_DELTA, MAX_TAPS - RAND_DELTA) + tap_regen = int(ONETAP_TIME * tap_count * GEN_PER_SEC) + tap_available = max(min(MAX_TAPS - tap_count + tap_regen, MAX_TAPS), MIN_TAPS) + regen_wait = (MAX_TAPS - tap_available) // GEN_PER_SEC + EXTRA_WAIT + return cls(tap_count, tap_available, regen_wait) + + def to_json(self): + return {"count": self.tap_count, "availableTaps": self.tap_available} + + +def tap_request(tap: Tap): + payload = tap.to_json() + payload.update({"timestamp": int(time.time())}) + try: + r = requests.post(URL, headers={"authorization": AUTH}, json=payload) + except Exception as ex: + print(ex) + return False + if r.status_code != 200: + print(r.status_code, r.text) + return False + return True + + +def main(): + if not AUTH: + raise RuntimeError("AUTH not set") + if DRY_RUN: + print("This is dry-run (requests will not be sent)") + + rs = RunState() + total_earned = 0 + + try: + while rs.running: + tap = Tap.fake() + total_earned += tap.tap_count + + if DRY_RUN: + print(tap) + else: + if not tap_request(tap): + rs.kill() + + time.sleep(tap.regen_wait) + finally: + print("Total earned:", total_earned) + + +if __name__ == "__main__": + main()