Telegram sebagai gudang data untuk proyek-proyek TI

Selamat siang, hari ini saya ingin berbagi dengan Anda masalah dan solusi luar biasa mereka yang bertemu saat menulis proyek TI kecil. Saya harus mengatakan segera bahwa artikel ini adalah untuk mereka yang bahkan sedikit berpengalaman dalam pengembangan telegram untuk bot, database, SQL dan bahasa pemrograman python.

Seluruh proyek diposting di github, tautannya ada di akhir artikel.

gambar

Masalah utama


Awalnya, saya ingin menulis sendiri penghitung kalori telegram bot sederhana, yang menerima nomor dari pengguna dan mengembalikan berapa banyak kalori yang dibiarkan normal untuk hari itu. Artinya, Anda perlu menyimpan kira-kira beberapa variabel untuk setiap pengguna.

Pada akhirnya, Anda harus memilih cara untuk menyimpan data ini.

  1. Opsi - variabel global , memori akses acak. Opsi ini langsung gagal, karena ketika program macet, kami kehilangan segalanya
  2. Opsi - menulis ke file pada disk. Mungkin berhasil untuk proyek seperti itu, tetapi saya berencana untuk menyebarkan bot pada heroku, yang menghapus semua data dari disk setiap hari. Jadi opsi ini tidak cocok
  3. Opsi - Google spreadsheet . Awalnya, saya ingin memikirkan opsi ini, tetapi saya mulai memahami dan menyadari bahwa ada batasan jumlah kueri ke tabel, dan untuk mulai menggunakan tabel, Anda perlu menulis banyak baris kode dan mencari tahu api yang tidak terlalu sederhana
  4. Opsi adalah basis data . Ya, ini adalah pilihan terbaik dalam segala hal. Tetapi untuk proyek seperti itu, bahkan lucu untuk digunakan. Juga, penyebaran dan dukungan database pada server pihak ketiga akan menelan biaya yang sangat besar.

Akibatnya, tidak ada opsi ini yang muncul. Tentu saja, ada lusinan cara lain, tetapi saya ingin ini gratis, cepat dan dengan kode minimum.

Solusi


Idenya sangat sederhana, untuk penyimpanan data kita akan menggunakan database sqllite dalam memori, karena sudah dibangun ke dalam python 3 dan kita akan membuat cadangan tabel kita ke server Telegram dengan interval kecil (sekitar setiap 30 detik) dan cadangan ketika proses program ditutup.

Jika server macet, maka pada permintaan pertama kami akan secara otomatis mengunduh tabel kami dari server Telegram dan mengembalikan data ke sqllite.

Anda dapat menggunakan yang lain dalam database memori sesuka Anda.

Pro


  1. Kinerja - karena bekerja dengan data dalam memori utama, kecepatan eksekusi program bahkan lebih cepat daripada ketika menggunakan database pada server pihak ketiga (kecepatan dan grafik pengujian akan di akhir)
  2. Gratis - tidak perlu membeli server pihak ketiga untuk database dan semua data disimpan sebagai cadangan gratis di server Telegram
  3. Relatif andal - jika server mogok karena alasan yang tidak diketahui, maka kami kehilangan data maksimum selama 30 detik terakhir (waktu interval cadangan), untuk prototipe yang berfungsi atau proyek kecil, itu sudah cukup.
  4. Biaya minimum saat beralih ke database biasa - Anda perlu mengganti data koneksi, menghapus kode cadangan, dan mentransfer data tabel dari cadangan ke database baru.

Cons


  1. Kurangnya penskalaan horizontal
  2. Anda memerlukan dua akun di Telegram (satu untuk administrator, yang lain untuk menguji pengguna)
  3. Server tidak akan berfungsi di Rusia karena terkunci
  4. Dalam komentar, saya pikir Anda akan menemukan selusin nuansa lainnya.

Waktunya buang air besar


Mari kita menulis clicker sederhana dan menjalankan tes untuk kecepatan.

Bot akan ditulis dalam bahasa pemrograman python menggunakan pustaka interaksi yang tidak sinkron dengan aiogram api telegram.

Hal pertama yang harus dilakukan adalah mengisi pengaturan bot, saya tidak akan memberi tahu Anda cara mendapatkan token dari BotFather, sudah ada ratusan artikel tentang topik ini.

Kami juga membutuhkan akun kedua di telegram untuk admin, di mana cadangan kami akan disimpan.

Untuk mendapatkan admin_id dan config_id, kita perlu memulai bot dari akun administrator dan menulis "admin" ke bot, setelah itu akan membuat cadangan pertama dan menulis admin_id, config_id Anda. Ganti dan mulai bot lagi.

#-------------------- ------------------------- #    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() 

Jadi sekarang mari kita pergi melalui logika utama bot


Jika bot menerima pesan dengan kata "admin", maka kami membuat tabel pengguna dengan model data berikut:

  • chatid - pengguna id obrolan yang unik
  • nama - nama pengguna
  • klik - jumlah klik
  • negara - nilai untuk mesin negara, tidak digunakan dalam proyek ini, tetapi Anda tidak dapat melakukannya tanpa yang lebih rumit

Tambahkan pengguna uji, dan kirim dokumen ke server Telegram dengan tabel kami. Kami juga mengirim admin_id dan config_id ke administrator dalam bentuk pesan. Setelah menerima ID, kode ini perlu dikomentari.

 #    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)) 

Logika Pengguna


Pertama-tama, kami mencoba mendapatkan dari basis data memori data pengguna yang mengirim pesan. Jika kami menemukan kesalahan, maka muat data dari cadangan server Telergam, isi database kami dengan data dari cadangan, dan coba lagi untuk menemukan pengguna.

 #    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() 

Jika kami menemukan pengguna di database, maka kami memproses tombol-tombol:

  • Dengan mengklik "Klik" kami memperbarui jumlah klik untuk pengguna ini
  • Ketika Anda mengklik "Peringkat" kami menampilkan daftar lima belas orang yang memiliki klik terbanyak.

Jika Anda tidak menemukan pengguna, maka tuliskan kesalahan padanya.

  #      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, '  ') 

Mari kita menulis logika untuk pendaftaran pengguna


Kami mencoba menemukan pengguna di basis data, jika dia tidak ada di sana, kemudian tambahkan baris baru ke tabel dan buat cadangan.

Jika kami menemukan kesalahan, maka kami memuat cadangan terakhir, mengisi tabel dan ulangi upaya pendaftaran.

 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) 

Jadi, yah, dan yang paling menarik.

Menyimpan dan mengambil data dari server Telergam


Kami membongkar semua data dari tabel pengguna, menerjemahkan kamus menjadi string, dan memodifikasi file kami, yang disimpan di server 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) 

Untuk mendapatkan cadangan, kita perlu meneruskan pesan dengan file dari admin ke admin. Lalu dapatkan path ke file, baca data dengan url dan kembalikan seluruh cadangan.

 # #-------------------- ------------------------- 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) 

Yah, itu hampir semuanya, tetap saja menulis timer untuk membuat cadangan dan menguji bot.
Buat utas yang mengeksekusi metode save_data () kami setiap 30 detik.

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

Nah, di program utama, kita memulai timer dan bot itu sendiri.

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

Jadi kodenya sepertinya sudah beres, di sini ada tautan draft kerja ke github .

Bagaimana cara menjalankannya


  1. Unduh proyek dari github. Kami memulai proyek di lingkungan pengembangan apa pun untuk python (Misalnya: PyCharm).
  2. Lingkungan pengembangan akan secara otomatis memuat pustaka yang diperlukan dari file persyaratan.
  3. Ganti Token dari BotFather di main.py

  4. Kami memulai proyek
  5. Dari akun kedua, klik / mulai dan tulis kata "admin"

  6. Matikan proyek dan isi admin_id dan config_id di file main.py
  7. Kami memulai proyek dan dari akun pengguna kami menekan mulai

  8. Untung

Pengujian dan grafik


Pengujian dilakukan pada server heroku dengan karakteristik instance minimal. Jadi, kita dapat mengasumsikan bahwa semua tes dilakukan dalam kondisi yang kurang lebih sama.

Grafik dibuat dari sampel ~ 100 permintaan-jawaban. Dan rata-rata sampel disajikan.

PostgreSQL di Amazon RDS dengan karakteristik minimal digunakan sebagai database pada server pihak ketiga.



Dengan satu juta pengguna, waktu cadangan menjadi masalah.



Ukuran cadangan sepenuhnya tergantung pada model data Anda, dalam kasus saya, dengan satu juta pengguna, file data dengan 21 megabita diperoleh.



Kesimpulan


Metode penyimpanan data ini masuk akal untuk proyek hingga satu juta pengguna. Artinya, untuk prototipe atau startup pribadi, metode ini memiliki hak untuk hidup.

Sebagai hasilnya, kami mendapat clicker mandiri sepenuhnya, tidak tergantung pada basis data jarak jauh.

Berikut adalah proyek yang dijelaskan di atas yang digunakan untuk heroku: @Clicker_fast_bot

Saya juga menerapkan proyek yang lebih kompleks dengan ideologi ini: @Random_friend_bot

Persamaan antara dua orang chatroom dan chatroulette, tetapi hanya di telegram.

Dia mencari dalam radius 100 km dari lawan jenis untuk berkomunikasi dan menyadari obrolan tertutup dengan lawan bicara baru.

Jika ini menarik, saya dapat membuang kode sumber proyek. Juga, jika topik ini relevan, maka pada artikel berikutnya saya dapat menjelaskan pembuatan api Rest tanpa database eksternal. Itu adalah tumpukan Django-sqllite-Telegram.

Saya akan senang atas kritik apa pun, terima kasih atas perhatian Anda!

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


All Articles