Opera8 commited on
Commit
84ce5ef
·
verified ·
1 Parent(s): c5caabb

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +50 -34
main.py CHANGED
@@ -93,7 +93,7 @@ def gregorian_to_jalali(gy, gm, gd):
93
  return jy, jm, jd
94
 
95
  # ==============================================================================
96
- # 🟢 پارت 4: دیتابیس SQLite (نسخه فوق‌سریع و بهینهشده بدون ذخیره شناسه‌ها در هارد)
97
  # ==============================================================================
98
  import os
99
  import sqlite3
@@ -101,12 +101,14 @@ import json
101
  import copy
102
  import threading
103
 
104
- DB_FILE = "/data/users_v3.db"
 
 
105
  CORRUPT_FILE = "/data/users_db.db"
106
  BACKUP_JSON = "/data/users_db.json.bak"
107
 
108
  last_saved_state = {}
109
- # حافظه کش برای پیام‌های پردازش شده صرفاً در RAM (با ری‌استارت اسپیس کاملاً پاک می‌شود)
110
  recent_messages_dict = {}
111
  # قفل‌ها برای جلوگیری از تداخل رشته‌ها (Threads)
112
  db_lock = threading.Lock()
@@ -118,38 +120,53 @@ def init_sqlite_db():
118
  is_first_run = not os.path.exists(DB_FILE)
119
 
120
  conn = sqlite3.connect(DB_FILE, timeout=60.0)
121
- cursor = conn.cursor()
122
- # 🚀 استفاده از WAL برای پشتیبانی از هزاران کاربر همزمان
123
- cursor.execute('PRAGMA journal_mode=WAL;')
124
- cursor.execute('PRAGMA synchronous=NORMAL;')
125
- cursor.execute('CREATE TABLE IF NOT EXISTS users (chat_id TEXT PRIMARY KEY, user_data TEXT)')
126
 
127
- # 🧹 پاکسازی دیتابیس: حذف جدول ذخیره پیام‌ها (طبق درخواست، پیام‌ها دیگر در هارد ذخیره نمی‌شوند)
128
- cursor.execute('DROP TABLE IF EXISTS processed_messages')
 
129
 
 
 
130
  conn.commit()
131
- conn.close()
132
 
133
  if is_first_run:
134
- print("🚨 عملیات نجات آغاز شد...")
135
- restore_users_from_json()
136
-
 
 
 
137
  except Exception as e:
138
  print(f"❌ خطا در راه اندازی دیتابیس: {e}")
139
 
140
- def restore_users_from_json():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  if os.path.exists(BACKUP_JSON):
142
- print("📥 در حال بازیابی اعتبار کاربران از فایل پشتیبان...")
143
  try:
144
  with open(BACKUP_JSON, "r", encoding="utf-8") as f:
145
  data = json.load(f)
146
  if data:
147
- conn = sqlite3.connect(DB_FILE, timeout=60.0)
148
- conn.execute('PRAGMA journal_mode=WAL;')
149
  for cid, udata in data.items():
150
- conn.execute("INSERT OR REPLACE INTO users VALUES (?, ?)", (str(cid), json.dumps(udata)))
151
- conn.commit()
152
- conn.close()
153
  print(f"✅ اعتبار {len(data)} کاربر با موفقیت بازیابی شد.")
154
  except Exception as e:
155
  print(f"❌ خطا در بازیابی اعتبارها: {e}")
@@ -160,30 +177,28 @@ def load_db():
160
  db_dict = {}
161
  try:
162
  conn = sqlite3.connect(DB_FILE, timeout=60.0)
163
- conn.execute('PRAGMA journal_mode=WAL;')
164
  cursor = conn.cursor()
165
 
166
- # لود کردن کاربران
167
  cursor.execute("SELECT chat_id, user_data FROM users")
168
  for row in cursor.fetchall():
169
  db_dict[row[0]] = json.loads(row[1])
170
 
171
  conn.close()
172
  last_saved_state = copy.deepcopy(db_dict)
173
- # شناسه‌های پیام دیگر از دیتابیس لود نمی‌شوند و رم همیشه هنگام شروع خالی است
174
- print(f"🚀 دیتابیس آماده شد. تعداد کاربران: {len(db_dict)} | کش پیام‌ها ریست شد.")
175
  return db_dict
176
  except Exception as e:
177
- print(f"⚠️ ارور در لود نهایی: {e}")
178
  return {}
179
 
180
- # --- سیستم ذخیره سازی کاربران در پس‌زمینه (بدون معطل کردن ربات) ---
181
  def background_save_worker(changed_data):
182
  with db_lock:
183
  try:
184
  conn = sqlite3.connect(DB_FILE, timeout=60.0)
185
- conn.execute('PRAGMA journal_mode=WAL;')
186
- conn.execute('PRAGMA synchronous=NORMAL;')
187
  conn.executemany("INSERT OR REPLACE INTO users (chat_id, user_data) VALUES (?, ?)", changed_data)
188
  conn.commit()
189
  conn.close()
@@ -192,7 +207,7 @@ def background_save_worker(changed_data):
192
 
193
  def save_db(db_data):
194
  global last_saved_state
195
- changed = []
196
  for cid, data in db_data.items():
197
  if cid not in last_saved_state or last_saved_state[cid] != data:
198
  changed.append((str(cid), json.dumps(data, ensure_ascii=False)))
@@ -203,12 +218,12 @@ def save_db(db_data):
203
  for cid, _ in changed:
204
  last_saved_state[cid] = copy.deepcopy(db_data[cid])
205
 
206
- # 🚀 پرتاب عملیات سنگین به یک پردازشگر دیگر تا ربات متوقف نشود
207
  threading.Thread(target=background_save_worker, args=(changed,), daemon=True).start()
208
 
209
- # --- سیستم بررسی پیام تکراری (اکنون ۱۰۰٪ فقط در RAM کار می‌کند) ---
210
  def is_message_processed(message_id):
211
- # چک کردن داخل RAM (زمان اجرا: 0.0001 ثانیه)
212
  return str(message_id) in recent_messages_dict
213
 
214
  def mark_message_processed(message_id):
@@ -216,7 +231,8 @@ def mark_message_processed(message_id):
216
  with msg_cache_lock:
217
  # ثبت فقط در RAM
218
  recent_messages_dict[msg_id_str] = True
219
- # جلوگیری از پر شدن بیش از حد RAM در استفاده‌های طولانی
 
220
  if len(recent_messages_dict) > 15000:
221
  oldest_key = next(iter(recent_messages_dict))
222
  del recent_messages_dict[oldest_key]
 
93
  return jy, jm, jd
94
 
95
  # ==============================================================================
96
+ # 🟢 پارت 4: دیتابیس SQLite (نسخه بهینه شده برای فضای ابری - بدون باگ شبکه)
97
  # ==============================================================================
98
  import os
99
  import sqlite3
 
101
  import copy
102
  import threading
103
 
104
+ # تغییر نام به v4 برای فرار از فایل‌های قفل شده قبلی و شروع یکپارچه
105
+ DB_FILE = "/data/users_v4.db"
106
+ OLD_DB_V3 = "/data/users_v3.db"
107
  CORRUPT_FILE = "/data/users_db.db"
108
  BACKUP_JSON = "/data/users_db.json.bak"
109
 
110
  last_saved_state = {}
111
+ # حافظه کش فقط در RAM (با ری‌استارت اسپیس پاک می‌شود)
112
  recent_messages_dict = {}
113
  # قفل‌ها برای جلوگیری از تداخل رشته‌ها (Threads)
114
  db_lock = threading.Lock()
 
120
  is_first_run = not os.path.exists(DB_FILE)
121
 
122
  conn = sqlite3.connect(DB_FILE, timeout=60.0)
 
 
 
 
 
123
 
124
+ # 🚀 حذف WAL چون در هاست‌های ابری (NFS) باعث خطای malformed می‌شود
125
+ # با خاموش کردن آن، ارورها برای همیشه از بین می‌روند.
126
+ conn.execute('PRAGMA journal_mode=DELETE;')
127
 
128
+ # اطمینان از وجود جدول کاربران
129
+ conn.execute('CREATE TABLE IF NOT EXISTS users (chat_id TEXT PRIMARY KEY, user_data TEXT)')
130
  conn.commit()
 
131
 
132
  if is_first_run:
133
+ print("🚨 عملیات استخراج و انتقال به دیتابیس ابری جدید آغاز شد...")
134
+ robust_salvage(CORRUPT_FILE, conn) # استخراج از فایل 30 مگابایتی
135
+ robust_salvage(OLD_DB_V3, conn) # استخراج از فایل v3
136
+ restore_users_from_json(conn) # استخراج از فایل بکاپ JSON
137
+
138
+ conn.close()
139
  except Exception as e:
140
  print(f"❌ خطا در راه اندازی دیتابیس: {e}")
141
 
142
+ # 🧲 تابع قدرتمند برای کشیدن اطلاعات از فایل‌هایی که ارور malformed می‌دهند
143
+ def robust_salvage(old_file, new_conn):
144
+ if not os.path.exists(old_file): return
145
+ print(f"🔍 در حال استخراج اطلاعات از فایل {old_file} ...")
146
+ try:
147
+ old_conn = sqlite3.connect(old_file)
148
+ cursor = old_conn.cursor()
149
+ cursor.execute("SELECT chat_id, user_data FROM users")
150
+ rows = cursor.fetchall()
151
+
152
+ # فقط درج اطلاعات کاربر (بدون دست زدن به پیام‌های قدیمی)
153
+ new_conn.executemany("INSERT OR IGNORE INTO users VALUES (?, ?)", rows)
154
+ new_conn.commit()
155
+ old_conn.close()
156
+ print(f"✅ اطلاعات {len(rows)} کاربر از فایل قدیمی با موفقیت استخراج شد.")
157
+ except Exception as e:
158
+ print(f"⚠️ استخراج از فایل قدیمی در یک نقطه متوقف شد (احتمالاً به بخش خراب رسیده است): {e}")
159
+
160
+ def restore_users_from_json(new_conn):
161
  if os.path.exists(BACKUP_JSON):
162
+ print("📥 در حال بازیابی اعتبار کاربران از فایل پشتیبان JSON...")
163
  try:
164
  with open(BACKUP_JSON, "r", encoding="utf-8") as f:
165
  data = json.load(f)
166
  if data:
 
 
167
  for cid, udata in data.items():
168
+ new_conn.execute("INSERT OR REPLACE INTO users VALUES (?, ?)", (str(cid), json.dumps(udata)))
169
+ new_conn.commit()
 
170
  print(f"✅ اعتبار {len(data)} کاربر با موفقیت بازیابی شد.")
171
  except Exception as e:
172
  print(f"❌ خطا در بازیابی اعتبارها: {e}")
 
177
  db_dict = {}
178
  try:
179
  conn = sqlite3.connect(DB_FILE, timeout=60.0)
180
+ conn.execute('PRAGMA journal_mode=DELETE;')
181
  cursor = conn.cursor()
182
 
183
+ # 🟢 فقط لود کردن اطلاعات کاربران
184
  cursor.execute("SELECT chat_id, user_data FROM users")
185
  for row in cursor.fetchall():
186
  db_dict[row[0]] = json.loads(row[1])
187
 
188
  conn.close()
189
  last_saved_state = copy.deepcopy(db_dict)
190
+ print(f"🚀 دیتابیس ابری آماده شد. تعداد کل کاربران: {len(db_dict)}")
 
191
  return db_dict
192
  except Exception as e:
193
+ print(f"⚠️ ارور در لود نهایی دیتابیس: {e}")
194
  return {}
195
 
196
+ # --- سیستم ذخیره سازی کاربران در پس‌زمینه (برای حفظ سرعت ربات) ---
197
  def background_save_worker(changed_data):
198
  with db_lock:
199
  try:
200
  conn = sqlite3.connect(DB_FILE, timeout=60.0)
201
+ conn.execute('PRAGMA journal_mode=DELETE;')
 
202
  conn.executemany("INSERT OR REPLACE INTO users (chat_id, user_data) VALUES (?, ?)", changed_data)
203
  conn.commit()
204
  conn.close()
 
207
 
208
  def save_db(db_data):
209
  global last_saved_state
210
+ changed =[]
211
  for cid, data in db_data.items():
212
  if cid not in last_saved_state or last_saved_state[cid] != data:
213
  changed.append((str(cid), json.dumps(data, ensure_ascii=False)))
 
218
  for cid, _ in changed:
219
  last_saved_state[cid] = copy.deepcopy(db_data[cid])
220
 
221
+ # ارسال عملیات ذخیره به یک Thread دیگر تا ربات قفل نکند
222
  threading.Thread(target=background_save_worker, args=(changed,), daemon=True).start()
223
 
224
+ # --- سیستم ضد تکرار پیام کاملاً منتقل شده به RAM ---
225
  def is_message_processed(message_id):
226
+ # چک کردن داخل RAM در کسری از ثانیه
227
  return str(message_id) in recent_messages_dict
228
 
229
  def mark_message_processed(message_id):
 
231
  with msg_cache_lock:
232
  # ثبت فقط در RAM
233
  recent_messages_dict[msg_id_str] = True
234
+
235
+ # جلوگیری از پر شدن بیش از حد RAM (نگه داشتن فقط 15000 پیام آخر)
236
  if len(recent_messages_dict) > 15000:
237
  oldest_key = next(iter(recent_messages_dict))
238
  del recent_messages_dict[oldest_key]