Мануал Corsair - Auto reward 30 Min

orohimaru2

Выдающийся
Местный
Сообщения
59
Розыгрыши
0
Репутация
114
Реакции
222
Баллы
1 388
Автор не я взял с Англ сайта
Эта система использует скрипт attendance.py для регистрации времени онлайн. Она не идеальна, так как её можно обойти, но чтобы подключить базу данных к запросу на вход в игру, нужны знания и инструменты. Так что да, система несовершенна, но её можно использовать.

Код:
'''
    Attendance Reward System with Cooldown Timer + Auto Heartbeat
    - On login: registers user as "online"
    - On logout: unregisters user
    - Auto heartbeat: keeps user online as long as page is open
    - Auto-reward script uses this to find active users
'''

import os
from datetime import datetime, timedelta, date
import pyodbc
from flask import (
    Flask, request, redirect, url_for, session,
    render_template_string, flash
)

app = Flask(__name__)
app.secret_key = os.environ.get("FLASK_SECRET", "dev-secret-attendance-v4")
app.permanent_session_lifetime = timedelta(hours=2)

# --- DB config ---
SQL_SERVER = os.environ.get("SQL_SERVER", "YOURDB\\HERE")
USE_SQL_AUTH = os.environ.get("USE_SQL_AUTH", "0") == "1"
SQL_USER = os.environ.get("SQL_USER", "")
SQL_PASS = os.environ.get("SQL_PASS", "")

WORLD_DB = "SA_BETA_WORLDDB_0002"
TRADE_DB = "SA_BETA_TRADEDB_0002"

# --- Reward Configuration (ITEMS ONLY) ---
REWARDS = {
    1: [(16080, 5, 0)],                     # Cron Stone x5
    2: [(17809, 1, 0)],                     # Advice of Valks 10
    3: [(16080, 10, 0)],                    # Cron Stone x10
    4: [(17819, 1, 0)],                     # Advice of Valks 20
    5: [(757008, 1, 0)],                    # Mythical Censer
    6: [(17829, 1, 0)],                     # Advice of Valks 30
    7: [(45077, 3, 0)],                     # J's Hammer of Loyalty
    8: [(17839, 1, 0)],                     # Advice of Valks 40
    9: [(16080, 15, 0)],                    # Cron Stone x15
    10: [(17849, 1, 0)],                    # Advice of Valks 50
    11: [(17859, 1, 0)],                    # Advice of Valks 60
    12: [(16080, 20, 0)],                   # Cron Stone x20
    13: [(17869, 1, 0)],                    # Advice of Valks 70
    14: [(17879, 1, 0)],                    # Advice of Valks 80
    15: [(16080, 25, 0)],                   # Cron Stone x25
    16: [(17889, 1, 0)],                    # Advice of Valks 90
    17: [(17899, 1, 0)],                    # Advice of Valks 100
    18: [(16080, 30, 0)],                   # Cron Stone x30
    19: [(757008, 2, 0)],                   # Mythical Censer x2
    20: [(45077, 3, 0)],                    # J's Hammer of Loyalty
    21: [(16080, 40, 0)],                   # Cron Stone x40
    22: [(17899, 2, 0)],                    # Advice of Valks 100 x2
    23: [(16080, 50, 0)],                   # Cron Stone x50
    24: [(757008, 3, 0)],                   # Mythical Censer x3
    25: [(45077, 3, 0)],                    # J's Hammer of Loyalty
    26: [(16080, 60, 0)],                   # Cron Stone x60
    27: [(17899, 3, 0)],                    # Advice of Valks 100 x3
    28: [(16080, 75, 0)],                   # Cron Stone x75
    29: [(757008, 5, 0)],                   # Mythical Censer x5
    30: [(45077, 3, 0)],                    # J's Hammer of Loyalty
}

# Preload item names for UI
ITEM_NAMES = {
    16080: "Cron Stone",
    17809: "Advice of Valks 10",
    17819: "Advice of Valks 20",
    17829: "Advice of Valks 30",
    17839: "Advice of Valks 40",
    17849: "Advice of Valks 50",
    17859: "Advice of Valks 60",
    17869: "Advice of Valks 70",
    17879: "Advice of Valks 80",
    17889: "Advice of Valks 90",
    17899: "Advice of Valks 100",
    757008: "Mythical Censer",
    45077: "J's Hammer of Loyalty",
}

def get_conn(database_name: str):
    """Create an ODBC connection to the specified database."""
    driver = "{ODBC Driver 17 for SQL Server}"
    if USE_SQL_AUTH:
        cs = (
            f"DRIVER={driver};SERVER={SQL_SERVER};DATABASE={database_name};"
            f"UID={SQL_USER};PWD={SQL_PASS};TrustServerCertificate=yes;"
        )
    else:
        cs = (
            f"DRIVER={driver};SERVER={SQL_SERVER};DATABASE={database_name};"
            f"Trusted_Connection=yes;TrustServerCertificate=yes;"
        )
    return pyodbc.connect(cs)

# --- Ensure ActiveSessions Table Exists ---
def ensure_active_sessions_table():
    try:
        with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
            cur.execute("""
                IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'ActiveSessions')
                EXEC('CREATE SCHEMA ActiveSessions');
            """)
            cur.execute("""
                IF NOT EXISTS (
                    SELECT * FROM sys.tables t
                    INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
                    WHERE s.name = 'ActiveSessions' AND t.name = 'TblActiveConnections'
                )
                BEGIN
                    CREATE TABLE ActiveSessions.TblActiveConnections (
                        _userNo        INT NOT NULL PRIMARY KEY,
                        _nickname      NVARCHAR(50) NOT NULL,
                        _loginTime     DATETIME2(3) NOT NULL DEFAULT SYSUTCDATETIME(),
                        _lastHeartbeat DATETIME2(3) NOT NULL DEFAULT SYSUTCDATETIME(),
                        _ipAddress     VARCHAR(45) NULL
                    );
                    CREATE INDEX IX_Heartbeat ON ActiveSessions.TblActiveConnections (_lastHeartbeat);
                END
            """)
    except Exception as e:
        print(f"[DB] Failed to create ActiveSessions table: {e}")

# --- Register Active Session ---
def register_active_session(user_no: int, nickname: str, ip: str = None):
    try:
        with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
            cur.execute("""
                MERGE ActiveSessions.TblActiveConnections AS target
                USING (SELECT ? AS _userNo, ? AS _nickname, ? AS _ipAddress) AS source
                ON target._userNo = source._userNo
                WHEN MATCHED THEN
                    UPDATE SET
                        _nickname = source._nickname,
                        _lastHeartbeat = SYSUTCDATETIME(),
                        _ipAddress = source._ipAddress
                WHEN NOT MATCHED THEN
                    INSERT (_userNo, _nickname, _ipAddress)
                    VALUES (source._userNo, source._nickname, source._ipAddress);
            """, (user_no, nickname, ip))
    except Exception as e:
        print(f"[Session] Failed to register active session: {e}")

# --- Unregister Active Session ---
def unregister_active_session(user_no: int):
    try:
        with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
            cur.execute("""
                DELETE FROM ActiveSessions.TblActiveConnections
                WHERE _userNo = ?
            """, (user_no,))
    except Exception as e:
        print(f"[Session] Failed to unregister session: {e}")

def send_mail(nickname: str, item_id: int, qty: int, enchant: int = 0) -> str:
    """Send item via mail using sendMail stored procedure. Returns symNo or 'UNKNOWN' if not returned."""
    try:
        with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
            cur.execute("""
                DECLARE @symNo NVARCHAR(50);
                EXEC SA_BETA_WORLDDB_0002.dbo.sendMail
                    @toFamilyName = ?,
                    @itemKey      = ?,
                    @itemCount    = ?,
                    @enchant      = ?,
                    @title        = N'Daily Attendance Reward',
                    @contents     = N'Thank you for logging in daily!',
                    @symNo        = @symNo OUTPUT;
                SELECT @symNo AS symNo;
            """, (nickname, item_id, qty, enchant))
            row = cur.fetchone()
            if row:
                return row[0] if row[0] else "UNKNOWN"
            else:
                return "UNKNOWN"
    except Exception as e:
        print(f"[Mail Error] {e}")
        return ""

def record_attendance(user_no: int) -> tuple[int, bool]:
    today = date.today()
    try:
        with get_conn(WORLD_DB) as conn:
            conn.autocommit = False
            cur = conn.cursor()
            cur.execute("""
                SELECT _lastAttendanceDate, _attendanceCount
                FROM PaGamePrivate.TblUserAttendance WITH (UPDLOCK, ROWLOCK)
                WHERE _userNo = ?
            """, (user_no,))
            row = cur.fetchone()
            if row:
                last_date = row[0].date() if row[0] else None
                count = int(row[1])
                if last_date == today:
                    conn.rollback()
                    return count, False
                if last_date == today - timedelta(days=1):
                    new_count = count + 1
                else:
                    new_count = 1
                cur.execute("""
                    UPDATE PaGamePrivate.TblUserAttendance
                    SET _lastAttendanceDate = ?, _attendanceCount = ?
                    WHERE _userNo = ?
                """, (today, new_count, user_no))
            else:
                new_count = 1
                cur.execute("""
                    INSERT INTO PaGamePrivate.TblUserAttendance (_userNo, _lastAttendanceDate, _attendanceCount)
                    VALUES (?, ?, ?)
                """, (user_no, today, new_count))
            conn.commit()
            return new_count, True
    except Exception:
        return 0, False

# ---------- HTML Templates ----------
LOGIN_HTML = """<!doctype html>
<html><head>
  <meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>Attendance Reward – Sign in</title>
  <style>
    body{margin:0;font-family:system-ui,Segoe UI,Arial;background:#0b0d11;color:#e6e6e6;display:grid;place-items:center;height:100vh}
    .card{background:#141922;border:1px solid #232a36;border-radius:16px;box-shadow:0 10px 30px rgba(0,0,0,.35);padding:28px;min-width:300px;max-width:360px}
    h1{margin:0 0 6px 0;font-size:22px}
    p.sub{margin:0 0 16px 0;color:#aab3c2;font-size:13px}
    label{display:block;margin:12px 0 6px 0;font-size:13px;color:#aab3c2}
    input{width:100%;padding:10px 12px;border:1px solid #2a3140;background:#0f131a;color:#e6e6e6;border-radius:10px}
    button{margin-top:16px;width:100%;padding:10px 12px;border:0;border-radius:10px;background:#3b82f6;color:white;font-weight:600;cursor:pointer}
    .err{margin-top:10px;color:#ff7070;font-size:13px}
    .msg{margin-top:10px;color:#87d17e;font-size:13px}
  </style>
</head>
<body>
  <form class="card" method="post" action="/">
    <h1>Daily Attendance</h1>
    <p class="sub">Sign in to claim your daily reward</p>
    <label>Username</label>
    <input name="username" autocomplete="username" required />
    <label>Password</label>
    <input name="password" type="password" autocomplete="current-password" required />
    <button type="submit">Sign in</button>
    {% if error %}<div class="err">{{ error }}</div>{% endif %}
    {% for m in get_flashed_messages() %}<div class="msg">{{ m }}</div>{% endfor %}
  </form>
</body></html>"""

HOME_HTML = """<!doctype html>
<html><head>
  <meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>Attendance Reward – Home</title>
  <style>
    body{background:#0b0d11;color:#e6e6e6;font-family:system-ui,Segoe UI,Arial;margin:0}
    header{display:flex;justify-content:space-between;align-items:center;padding:14px 18px;background:#141922;border-bottom:1px solid #232a36}
    main{padding:24px}
    .meta{color:#aab3c2;font-size:14px;margin:6px 0 18px}
    .streak{font-size:20px;margin:16px 0;color:#ffd700}
    .cooldown{font-size:16px;margin:8px 0;color:#ffcc00;font-weight:bold}
    button{padding:8px 16px;border:0;border-radius:8px;background:#3b82f6;color:#fff;cursor:pointer;font-weight:600}
    button:disabled{background:#4a5568;cursor:not-allowed}
    .flash-ok{color:#7be18a;margin:6px 0;font-weight:bold}
    .flash-err{color:#ff7070;margin:6px 0;font-weight:bold}
    .reward-table{width:100%;border-collapse:collapse;margin-top:20px}
    .reward-table th, .reward-table td{padding:10px;border-bottom:1px solid #232a36;text-align:left}
    .reward-table th{color:#aab3c2;background:#1a202c}
    .today-row{background:#1e293b;animation: pulse 2s infinite;}
    .claim-btn{margin-top:8px}
    @keyframes pulse {
        0%{background:#1e293b}
        50%{background:#2d3748}
        100%{background:#1e293b}
    }
  </style>
</head>
<body>
  <header>
    <div><strong>Daily Attendance</strong></div>
    <form method="post" action="/logout"><button type="submit">Logout</button></form>
  </header>
  <main>
    <h2>Welcome, {{ username }}</h2>
    <div class="streak">🔥 Current Streak: Day {{ streak }} (Reward Day: {{ reward_day }})</div>

    {% if cooldown %}
        <div class="cooldown">⏳ Next claim in: {{ cooldown }}</div>
    {% endif %}

    {% for m in get_flashed_messages(category_filter=["ok"]) %}<div class="flash-ok">{{ m }}</div>{% endfor %}
    {% for m in get_flashed_messages(category_filter=["err"]) %}<div class="flash-err">{{ m }}</div>{% endfor %}

    <h3>Reward Schedule</h3>
    <table class="reward-table">
        <thead><tr><th>Day</th><th>Items</th><th>Action</th></tr></thead>
        <tbody>
        {% for day in range(1, 31) %}
        <tr {% if day == reward_day %}class="today-row"{% endif %}>
            <td>{{ day }}</td>
            <td>
                {% if day in rewards %}
                    {% for item_id, qty, enchant in rewards[day] %}
                        {{ item_names[item_id] }} x{{ qty }}
                        {% if not loop.last %}, {% endif %}
                    {% endfor %}
                {% else %}
                    —
                {% endif %}
            </td>
            <td>
                {% if day == reward_day and can_claim %}
                    <form method="post" action="/claim" class="claim-btn">
                        <button type="submit">🎁 Claim Now</button>
                    </form>
                {% elif day == reward_day and not can_claim %}
                    <button disabled>✅ Claimed Today</button>
                {% else %}
                    <button disabled>🔒 Future Reward</button>
                {% endif %}
            </td>
        </tr>
        {% endfor %}
        </tbody>
    </table>
  </main>

  <!-- ✅ AUTO HEARTBEAT: Keeps user "online" as long as this tab is open -->
  <script>
    async function sendHeartbeat() {
      try {
        await fetch('/heartbeat', { method: 'POST' });
      } catch (e) {
        console.log('Heartbeat failed:', e);
      }
    }
    // Send heartbeat every 10 seconds
    setInterval(sendHeartbeat, 10000);
    // Send one immediately on page load
    sendHeartbeat();
  </script>
</body></html>"""

# -------------------- Routes --------------------

@app.route("/", methods=["GET", "POST"])
def login():
    error = None
    if request.method == "POST":
        username = request.form.get("username", "").strip()
        password = request.form.get("password", "")
        if not username or not password:
            error = "Enter both fields."
        else:
            user_id = f"{username},{password}"
            try:
                with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
                    cur.execute("""
                        SELECT TOP 1 _userNo, _userNickname
                        FROM PaGamePrivate.TblUserInformation WITH (NOLOCK)
                        WHERE _userId = ?
                    """, (user_id,))
                    row = cur.fetchone()
                if row:
                    session.permanent = True
                    session["username"] = username
                    session["_userNo"] = int(row[0])
                    session["_nickname"] = row[1] or username
                   
                    # ✅ Register as online
                    ensure_active_sessions_table()
                    register_active_session(session["_userNo"], session["_nickname"], request.remote_addr)
                   
                    return redirect(url_for("home"))
                else:
                    error = "Invalid credentials."
            except Exception as ex:
                error = f"DB error: {ex}"
    return render_template_string(LOGIN_HTML, error=error)

@app.route("/home")
def home():
    if "username" not in session:
        return redirect(url_for("login"))

    user_no = session["_userNo"]

    streak = 0
    can_claim = False
    last_claim_date = None

    try:
        with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
            cur.execute("""
                SELECT _lastAttendanceDate, _attendanceCount
                FROM PaGamePrivate.TblUserAttendance WITH (NOLOCK)
                WHERE _userNo = ?
            """, (user_no,))
            row = cur.fetchone()
            if row:
                last_claim_date = row[0].date() if row[0] else None
                streak = int(row[1])
                can_claim = (last_claim_date != date.today())
            else:
                streak = 0
                can_claim = True
    except Exception:
        streak = 0
        can_claim = False

    reward_day = ((streak - 1) % 30) + 1 if streak > 0 else 1

    cooldown = ""
    if not can_claim and last_claim_date == date.today():
        now = datetime.now()
        tomorrow = datetime.combine(date.today() + timedelta(days=1), datetime.min.time())
        remaining = tomorrow - now
        hours, remainder = divmod(remaining.seconds, 3600)
        minutes, _ = divmod(remainder, 60)
        if remaining.days > 0:
            cooldown = f"{remaining.days} days"
        else:
            cooldown = f"{hours}h {minutes}m"

    return render_template_string(
        HOME_HTML,
        username=session["username"],
        streak=streak,
        reward_day=reward_day,
        can_claim=can_claim,
        cooldown=cooldown,
        rewards=REWARDS,
        item_names=ITEM_NAMES,
        range=range
    )

@app.route("/logout", methods=["POST"])
def logout():
    # ✅ Unregister as online
    if "_userNo" in session:
        unregister_active_session(session["_userNo"])
    session.clear()
    flash("Signed out.", "ok")
    return redirect(url_for("login"))

@app.route("/claim", methods=["POST"])
def claim():
    if "username" not in session:
        return redirect(url_for("login"))

    user_no = session["_userNo"]
    nickname = session.get("_nickname", session["username"])

    streak, is_first_claim = record_attendance(user_no)

    if not is_first_claim:
        flash("You already claimed today's reward.", "err")
        return redirect(url_for("home"))

    reward_day = ((streak - 1) % 30) + 1
    reward_items = REWARDS.get(reward_day, [])

    if not reward_items:
        flash("No reward configured for today.", "err")
        return redirect(url_for("home"))

    messages = []
    any_failed = False

    for item_id, qty, enchant in reward_items:
        sym_no = send_mail(nickname, item_id, qty, enchant)
        item_name = ITEM_NAMES.get(item_id, f"Item {item_id}")
        if sym_no is not None:
            messages.append(f"📬 {item_name} x{qty} sent to your mailbox!")
        else:
            any_failed = True
            messages.append(f"❌ Failed to send {item_name} x{qty}")

    if not any_failed:
        flash(f"🎉 Day {streak} Reward Claimed! " + " | ".join(messages), "ok")
    else:
        flash("⚠️ Partial failure: " + " | ".join(messages), "err")

    return redirect(url_for("home"))

# --- NEW: Heartbeat Route ---
@app.route("/heartbeat", methods=["POST"])
def heartbeat():
    """Update user's last heartbeat timestamp."""
    if "_userNo" not in session:
        return "", 401
   
    try:
        with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
            cur.execute("""
                UPDATE ActiveSessions.TblActiveConnections
                SET _lastHeartbeat = SYSUTCDATETIME()
                WHERE _userNo = ?
            """, (session["_userNo"],))
        return "", 204  # No content, success
    except Exception as e:
        print(f"[Heartbeat] Error: {e}")
        return "", 500

if __name__ == "__main__":
    from waitress import serve
    print("🚀 Serving Attendance System at http://0.0.0.0:8893")
    serve(app, host="0.0.0.0", port=8893)
Код:
'''
    Automatic Ordered Reward Service
    - Runs every 30 minutes
    - Rewards all users with active heartbeat (last 15 mins)
    - Uses ordered reward cycle (1-20)
'''

import os
import pyodbc
import time
import logging

# --- Configuration (MUST MATCH YOUR FLASK APP) ---
SQL_SERVER = os.environ.get("SQL_SERVER", "YOURDB\\HERE")
USE_SQL_AUTH = os.environ.get("USE_SQL_AUTH", "0") == "1"
SQL_USER = os.environ.get("SQL_USER", "")
SQL_PASS = os.environ.get("SQL_PASS", "")
WORLD_DB = "SA_BETA_WORLDDB_0002"

# --- Ordered Reward Pool (20 items) ---
ORDERED_REWARDS = [
    (757360, 3),   # Cycle 1: Greeat Pioneer Chest
    (757360, 3),   # Cycle 2: Cron Stone x3
    (757360, 3),   # Cycle 3: Cron Stone x5
    (757360, 3),   # Cycle 4: Advice of Valks 10
    (757360, 3),   # Cycle 5: Advice of Valks 20
    (757360, 3),   # Cycle 6: Advice of Valks 30
    (757360, 3),   # Cycle 7: Advice of Valks 40
    (757360, 3),   # Cycle 8: Advice of Valks 50
    (757360, 3),   # Cycle 9: Advice of Valks 100
    (757360, 3),  # Cycle 10: Mythical Censer
    (757360, 3),   # Cycle 11: J's Hammer of Loyalty
    (757360, 3),  # Cycle 12: [Event] Shakatu's Luxury Box II
    (757360, 3),  # Cycle 13: [Event] Shakatu's Shiny Box(Life)
    (757360, 3),  # Cycle 14: [Event] Shakatu's Shiny Box(Combat)
    (757360, 3),   # Cycle 15: [Pet]Hedgehog
    (757360, 3),  # Cycle 16: Flower of Oblivion
    (757360, 3),  # Cycle 17: Royal Fern Root
    (757360, 3),  # Cycle 18: Mythical Feather
    (757360, 3),   # Cycle 19: Fruit of Yianaros
    (757360, 3),   # Cycle 20: Rainbow Gem Fruit
]

COUNTER_FILE = "reward_cycle_counter.txt"

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s | %(levelname)s | %(message)s',
    handlers=[logging.FileHandler("auto_reward.log", encoding='utf-8'), logging.StreamHandler()]
)
logger = logging.getLogger()

def get_conn(database_name: str):
    driver = "{ODBC Driver 17 for SQL Server}"
    if USE_SQL_AUTH:
        cs = f"DRIVER={driver};SERVER={SQL_SERVER};DATABASE={database_name};UID={SQL_USER};PWD={SQL_PASS};TrustServerCertificate=yes;"
    else:
        cs = f"DRIVER={driver};SERVER={SQL_SERVER};DATABASE={database_name};Trusted_Connection=yes;TrustServerCertificate=yes;"
    return pyodbc.connect(cs)

def send_mail(nickname: str, item_id: int, qty: int, enchant: int = 0) -> bool:
    try:
        with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
            cur.execute("""
                DECLARE @symNo NVARCHAR(50);
                EXEC SA_BETA_WORLDDB_0002.dbo.sendMail
                    @toFamilyName = ?,
                    @itemKey      = ?,
                    @itemCount    = ?,
                    @enchant      = ?,
                    @title        = N'30-Minute Ordered Reward',
                    @contents     = N'Thank you for playing! Here is your scheduled reward.',
                    @symNo        = @symNo OUTPUT;
                SELECT @symNo AS symNo;
            """, (nickname, item_id, qty, enchant))
            return True
    except Exception as e:
        logger.error(f"Mail send failed for {nickname}: {e}")
        return False

def get_active_users():
    """Get users with heartbeat in last 15 minutes"""
    users = []
    try:
        with get_conn(WORLD_DB) as conn, conn.cursor() as cur:
            cur.execute("""
                SELECT _nickname
                FROM ActiveSessions.TblActiveConnections
                WHERE _lastHeartbeat >= DATEADD(MINUTE, -15, SYSUTCDATETIME())
                  AND _nickname IS NOT NULL
                  AND _nickname != ''
            """)
            users = [row[0] for row in cur.fetchall()]
            logger.info(f"Found {len(users)} active users (via Flask login)")
    except Exception as e:
        logger.error(f"Error fetching active users: {e}")
    return users

def get_next_reward_cycle():
    try:
        if os.path.exists(COUNTER_FILE):
            with open(COUNTER_FILE, "r") as f:
                cycle = int(f.read().strip())
        else:
            cycle = 0
        next_cycle = cycle % len(ORDERED_REWARDS) + 1
        with open(COUNTER_FILE, "w") as f:
            f.write(str(next_cycle))
        return next_cycle
    except Exception as e:
        logger.error(f"Error managing cycle counter: {e}. Defaulting to cycle 1.")
        return 1

def distribute_rewards():
    logger.info("Starting 30-minute ordered reward cycle...")
    cycle_number = get_next_reward_cycle()
    item_id, qty = ORDERED_REWARDS[cycle_number - 1]
    logger.info(f"Current reward cycle: #{cycle_number} -> Item {item_id} x{qty}")
   
    users = get_active_users()
    if not users:
        logger.info("No active users found.")
        return

    success = 0
    for nickname in users:
        if send_mail(nickname, item_id, qty):
            logger.info(f"   -> Sent to {nickname}")
            success += 1
        else:
            logger.warning(f"   -> Failed for {nickname}")
   
    logger.info(f"Cycle #{cycle_number} complete: {success}/{len(users)} rewards sent.")

def main():
    logger.info("🚀 Ordered Auto Reward Service Started")
    logger.info("Will run every 30 minutes. Press Ctrl+C to stop.")
   
    while True:
        try:
            distribute_rewards()
            logger.info("Sleeping for 30 minutes...\n")
            time.sleep(1800)  # 30 minutes
        except KeyboardInterrupt:
            logger.info("🛑 Service stopped by user.")
            break
        except Exception as e:
            logger.error(f"💥 Unexpected error: {e}")
            time.sleep(60)

if __name__ == "__main__":
    main()
 
  • Мне нравится
Реакции: òbi

Назад
Сверху