Telegram كمستودع بيانات لمشاريع تكنولوجيا المعلومات

مساء الخير ، أود اليوم أن أشاطركم المشاكل والحلول غير العادية التي اجتمعت عند كتابة مشاريع تكنولوجيا المعلومات الصغيرة. يجب أن أقول على الفور أن هذا المقال مخصص لأولئك الذين هم على دراية بسيطة بتطوير البرقيات لبرامج الروبوتات وقواعد البيانات و SQL ولغة البرمجة بيثون.

تم نشر المشروع بالكامل على جيثب ، سيكون الرابط في نهاية المقال.

صورة

المشكلة الرئيسية


في البداية ، أردت أن أكتب بنفسي عدادًا بسيطًا من السعرات الحرارية في telegram ، والذي يتلقى رقمًا من المستخدم ويعيد عدد السعرات الحرارية التي يتم تركها إلى وضعها الطبيعي لهذا اليوم. هذا هو ، تحتاج إلى تخزين ما يقرب من اثنين من المتغيرات لكل مستخدم.

في النهاية ، كان عليك اختيار طريقة لتخزين هذه البيانات.

  1. الخيار - المتغيرات العالمية ، ذاكرة الوصول العشوائي. الخيار على الفور فشل ، لأنه عندما يتعطل البرنامج ، نفقد كل شيء
  2. الخيار - الكتابة إلى ملف على القرص. قد ينجح هذا المشروع ، لكنني خططت لنشر روبوت على heroku ، والذي يمحو جميع البيانات من القرص كل يوم. لذلك هذا الخيار لا يصلح
  3. الخيار - جداول بيانات Google . في البداية ، أردت التركيز على هذا الخيار ، لكنني بدأت أفهمه وأدركت أن هناك حدًا لعدد الاستعلامات إلى الجدول ، ولكي أبدأ في استخدام الجدول فقط ، تحتاج إلى كتابة مجموعة من أسطر التعليمات البرمجية ومعرفة واجهة برمجة التطبيقات غير البسيطة
  4. الخيار هو قاعدة بيانات . نعم ، هذا هو الخيار الأفضل في كل شيء. لكن بالنسبة لمثل هذا المشروع ، فإنه من المضحك استخدامه. أيضا ، فإن نشر ودعم قاعدة بيانات على خادم طرف ثالث سيكلف فلسا واحدا.

نتيجة لذلك ، لم يتم عرض أي من هذه الخيارات. بالطبع ، هناك العشرات من الطرق الأخرى ، لكنني أرغب في أن تكون حرة وسريعة ورمز على الأقل.

قرار


الفكرة بسيطة للغاية ، بالنسبة لتخزين البيانات ، سوف نستخدم قاعدة بيانات sqllite في الذاكرة ، لأنها بنيت بالفعل في بيثون 3 وسنقوم بعمل نسخة احتياطية من طاولتنا على خوادم Telegram مع فاصل صغير (كل 30 ثانية تقريبًا) والنسخ الاحتياطي عند إغلاق عملية البرنامج.

إذا تعطل الخادم ، فعند الطلب الأول ، سنقوم تلقائيًا بتنزيل جدولنا من خادم Telegram واستعادة البيانات إلى sqllite.

يمكنك استخدام أي شيء آخر في قاعدة بيانات الذاكرة كما تريد.

الأشياء الجيدة


  1. الأداء - نظرًا للعمل مع البيانات الموجودة في الذاكرة الرئيسية ، تكون سرعة تنفيذ البرنامج أسرع من استخدام قاعدة البيانات على خادم طرف ثالث (ستكون السرعة واختبار الرسوم البيانية في النهاية)
  2. مجاني - لا حاجة لشراء خوادم خارجية لقواعد البيانات ويتم تخزين جميع البيانات كنسخ احتياطي مجانًا على خوادم Telegram
  3. يمكن الاعتماد عليه نسبيًا - إذا تعطل الخادم لأسباب غير معروفة ، فسوف نفقد الحد الأقصى للبيانات لمدة 30 ثانية (وقت الفاصل الزمني للنسخ الاحتياطي) ، أو لنموذج أولي عملي أو مشروع صغير.
  4. الحد الأدنى من التكاليف عند التبديل إلى قاعدة بيانات منتظمة - تحتاج إلى استبدال بيانات الاتصال ، وإزالة رمز النسخ الاحتياطي ونقل بيانات الجدول من النسخة الاحتياطية إلى قاعدة بيانات جديدة.

سلبيات


  1. عدم وجود التحجيم الأفقي
  2. تحتاج إلى حسابين في Telegram (أحدهما للمسؤول والآخر لاختبار المستخدم)
  3. لن يعمل الخادم في روسيا بسبب الأقفال
  4. في التعليقات ، أعتقد أنك سوف تجد عشرات الفروق الدقيقة الأخرى.

وقت القرف


دعنا نكتب الفرس بسيطة وتشغيل اختبارات للسرعة.

سيتم كتابة الروبوت في لغة برمجة الثعبان باستخدام مكتبة غير متزامنة للتفاعل مع aiogram api telegram.

أول شيء يجب فعله هو ملء إعدادات برنامج الروبوت ، فلن أخبر عن كيفية الحصول على رمز مميز من BotFather ، فهناك بالفعل مئات المقالات حول هذا الموضوع.

نحتاج أيضًا إلى حساب ثانٍ في برقية للمشرف ، حيث سيتم حفظ النسخ الاحتياطية الخاصة بنا.

للحصول على admin_id و config_id ، نحتاج إلى بدء الروبوت من حساب المسؤول والكتابة "admin" إلى الروبوت ، وبعد ذلك سيقوم بإنشاء النسخة الاحتياطية الأولى وكتابة admin_id ، config_id. استبدال وبدء الروبوت مرة أخرى.

#-------------------- ------------------------- #    BotFather TOKEN = '1234567:your_token' #  logging.basicConfig(level=logging.INFO) bot = Bot(token=TOKEN) dp = Dispatcher(bot) #             admin_id=12345678 config_id=12345 conn = sqlite3.connect(":memory:") #  in memory  cursor = conn.cursor() 

لذلك الآن دعونا نذهب من خلال المنطق الرئيسي للبوت


إذا استقبل الروبوت رسالة تحتوي على كلمة "admin" ، فسنقوم بإنشاء جدول مستخدم باستخدام نموذج البيانات التالي:

  • chatid - فريد معرف المستخدم الدردشة
  • اسم - اسم المستخدم
  • انقر - عدد النقرات
  • الحالة - لا يتم استخدام قيمة جهاز الحالة في هذا المشروع ، لكن لا يمكنك الاستغناء عنها

إضافة مستخدم اختبار ، وإرسال المستند إلى خادم Telegram مع الجدول لدينا. نرسل أيضًا admin_id و config_id إلى المسؤول في شكل رسائل. بعد تلقي المعرفات ، يجب تعليق هذا الرمز.

 #    if message.text == 'admin': cursor.execute("CREATE TABLE users (chatid INTEGER , name TEXT, click INTEGER, state INTEGER)") cursor.execute("INSERT INTO users VALUES (1234, 'eee', 1,0)") conn.commit() sql = "SELECT * FROM users " cursor.execute(sql) data = cursor.fetchall() str_data = json.dumps(data) await bot.send_document(message.chat.id, io.StringIO(str_data)) await bot.send_message(message.chat.id, 'admin_id = {}'.format(message.chat.id)) await bot.send_message(message.chat.id, 'config_id = {}'.format(message.message_id+1)) 

منطق المستخدم


بادئ ذي بدء ، نحاول الحصول من قاعدة بيانات الذاكرة على بيانات المستخدم الذي أرسل الرسالة. في حالة حدوث خطأ ، ثم تحميل البيانات من النسخة الاحتياطية لخادم Telergam ، املأ قاعدة البيانات الخاصة بنا بالبيانات من النسخة الاحتياطية وحاول مرة أخرى العثور على المستخدم.

 #    try: sql = "SELECT * FROM users where chatid={}".format(message.chat.id) cursor.execute(sql) data = cursor.fetchone() # or use fetchone() except Exception: data = await get_data() cursor.execute("CREATE TABLE users (chatid INTEGER , name TEXT, click INTEGER, state INTEGER)") cursor.executemany("INSERT INTO users VALUES (?,?,?,?)", data) conn.commit() sql = "SELECT * FROM users where chatid={}".format(message.chat.id) cursor.execute(sql) data = cursor.fetchone() # or use fetchone() 

إذا وجدنا المستخدم في قاعدة البيانات ، فسنقوم بمعالجة الأزرار:

  • بالنقر فوق "النقر" ، نقوم بتحديث عدد النقرات لهذا المستخدم
  • عند النقر فوق "تصنيف" ، نعرض قائمة تضم خمسة عشر شخصًا لديهم أكبر عدد من النقرات.

إذا لم تجد المستخدم ، فاكتب له خطأ.

  #      click     if data is not None: if message.text == '': sql = "UPDATE users SET click = {} WHERE chatid = {}".format(data[2]+1,message.chat.id) cursor.execute(sql) conn.commit() await bot.send_message(message.chat.id, ': {} '.format(data[2]+1)) #        10 if message.text == '': sql = "SELECT * FROM users ORDER BY click DESC LIMIT 15" cursor.execute(sql) newlist = cursor.fetchall() # or use fetchone() sql_count = "SELECT COUNT(chatid) FROM users" cursor.execute(sql_count) count=cursor.fetchone() rating=': {}\n'.format(count[0]) i=1 for user in newlist: rating=rating+str(i)+': '+user[1]+' - '+str(user[2])+'\n' i+=1 await bot.send_message(message.chat.id, rating) else: await bot.send_message(message.chat.id, '  ') 

دعنا نكتب منطق تسجيل المستخدم


نحن نحاول العثور على المستخدم في قاعدة البيانات ، إذا لم يكن هناك ، ثم أضف صفًا جديدًا إلى الجدول وعمل نسخة احتياطية.

إذا حدث خطأ ، فسنحمّل آخر نسخة احتياطية ، املأ الجدول وكرر محاولة التسجيل.

 sql_select = "SELECT * FROM users where chatid={}".format(message.chat.id) sql_insert = "INSERT INTO users VALUES ({}, '{}', {},{})".format(message.chat.id,message.chat.first_name, 0, 0) try: cursor.execute(sql_select) data = cursor.fetchone() if data is None: cursor.execute(sql_insert) conn.commit() await save_data() except Exception: data = await get_data() cursor.execute("CREATE TABLE users (chatid INTEGER , name TEXT, click INTEGER, state INTEGER)") cursor.executemany("INSERT INTO users VALUES (?,?,?,?)", data) conn.commit() cursor.execute(sql_select) data = cursor.fetchone() if data is None: cursor.execute(sql_insert) conn.commit() await save_data() #   button = KeyboardButton('') button2 = KeyboardButton('') #  kb = ReplyKeyboardMarkup(resize_keyboard=True).add(button).add(button2) #     await bot.send_message(message.chat.id,' {}'.format(message.chat.first_name),reply_markup=kb) 

حسنا ، والأكثر إثارة للاهتمام.

حفظ واسترجاع البيانات من خادم Telergam


نقوم بإلغاء تحميل جميع البيانات من جدول المستخدم ، وترجمة القاموس إلى سلسلة ، وتعديل ملفنا ، الذي يتم تخزينه على خوادم Telegram.

  #-------------------- ------------------------- async def save_data(): sql = "SELECT * FROM users " cursor.execute(sql) data = cursor.fetchall() # or use fetchone() try: #     str_data=json.dumps(data) #      await bot.edit_message_media(InputMediaDocument(io.StringIO(str_data)), admin_id, config_id) except Exception as ex: print(ex) 

من أجل الحصول على نسخة احتياطية ، نحتاج إلى إعادة توجيه الرسالة مع الملف من المسؤول إلى المسؤول. ثم الحصول على المسار إلى الملف ، وقراءة البيانات عن طريق رابط وإعادة النسخة الاحتياطية بأكملها.

 # #-------------------- ------------------------- async def get_data(): #         forward_data = await bot.forward_message(admin_id, admin_id, config_id) #    ,   file_data = await bot.get_file(forward_data.document.file_id) #    url file_url_data = bot.get_file_url(file_data.file_path) #     json_file= urlopen(file_url_data).read() #    json     return json.loads(json_file) 

حسنًا ، هذا كل شيء تقريبًا ، يبقى فقط كتابة مؤقت لعمل نسخ احتياطية واختبار الروبوت.
قم بإنشاء سلسلة رسائل تنفذ طريقة save_data () الخاصة بنا كل 30 ثانية.

 def timer_start(): threading.Timer(30.0, timer_start).start() try: asyncio.run_coroutine_threadsafe(save_data(),bot.loop) except Exception as exc: pass 

حسنًا ، في البرنامج الرئيسي ، نبدأ الموقت والبوت نفسه.

 #-------------------- ------------------------- if __name__ == '__main__': timer_start() executor.start_polling(dp, skip_updates=True) 

لذا يبدو أنه تم حل الكود ، وهنا رابط مسودة العمل إلى جيثب .

كيفية الجري


  1. قم بتنزيل المشروع من جيثب. نبدأ المشروع في أي بيئة تطوير لبيثون (على سبيل المثال: PyCharm).
  2. ستقوم بيئة التطوير تلقائيًا بتحميل المكتبات اللازمة من ملف المتطلبات.
  3. استبدال الرمز من BotFather في main.py

  4. نبدأ المشروع
  5. من الحساب الثاني ، انقر فوق / ابدأ واكتب كلمة "المسؤول"

  6. أوقف تشغيل المشروع واملأ admin_id و config_id في ملف main.py
  7. نبدأ المشروع ومن حساب المستخدم نضغط البدء

  8. ربح

الاختبار والرسوم البيانية


وأجريت اختبارات على خوادم heroku مع الحد الأدنى من خصائص المثال. لذلك ، يمكننا أن نفترض أن جميع الاختبارات أجريت في ظروف متساوية إلى حد ما.

الرسوم البيانية مصنوعة من عينات من ~ 100 طلب - إجابات. ويتم تقديم متوسط ​​العينة.

تم استخدام PostgreSQL على Amazon RDS مع الحد الأدنى من الخصائص كقاعدة بيانات على خادم طرف ثالث.



مع وجود مليون مستخدم ، يصبح وقت النسخ الاحتياطي مشكلة.



يعتمد حجم النسخة الاحتياطية تمامًا على طراز البيانات الخاص بك ، في حالتي ، مع مليون مستخدم ، تم الحصول على ملف بيانات به 21 ميغابايت.



استنتاج


طريقة تخزين البيانات هذه منطقية بالنسبة للمشاريع التي يصل عدد مستخدميها إلى مليون مستخدم. وهذا هو ، لنموذج أولي أو بدء التشغيل الشخصي ، هذه الطريقة لها الحق في الحياة.

نتيجة لذلك ، حصلنا على مستدق مستقل تمامًا ومستقل عن قواعد البيانات البعيدة.

هنا هو المشروع الموضح أعلاه نشرها على heroku:Clicker_fast_bot

لقد قمت أيضًا بتنفيذ مشروع أكثر تعقيدًا باستخدام هذه الإيديولوجية:Random_friend_bot

تشبه غرف الدردشة والدردشة مع شخصين ، ولكن فقط في برقية.

إنه يبحث داخل دائرة نصف قطرها 100 كم من شخص من الجنس الآخر للتواصل ويدرك محادثة مغلقة مع محاور جديد.

إذا كان الأمر ممتعًا ، يمكنني التخلص من الكود المصدري للمشروع. وأيضًا ، إذا كان هذا الموضوع ذا صلة ، في المقال التالي ، يمكنني وصف إنشاء تطبيق Rest api بدون قواعد بيانات خارجية. هذا هو كومة django-sqllite-Telegram.

سأكون سعيدًا بأي نقد ، شكرًا لك على اهتمامك!

Source: https://habr.com/ru/post/ar464865/


All Articles