برگزارکنندگان المپیک می‌خواهند سامانه‌ای درست کنند که به‌راحتی بتوانند اخبار برگزاری و وقایع هر رشته را به خبرگزاری‌های مختلف ورزشی اطلاع دهند؛ به این صورت که یک سری پخش‌کننده‌ی اخبار دارند که وقایع را منتشر می‌کنند و یک سری دنبال‌کننده‌ی اخبار دارند که به‌محض دریافت خبر، آن را در خبرگزاری‌شان قرار می‌دهند. آن‌ها از شما کمک خواسته‌اند تا در پیاده‌سازی این سامانه‌ کمک کنید.

پیاده‌سازی

شما باید سه کلاس OlympicsServer، ‍Publisher و Subscriberرا پیاده‌سازی کنید و همچنین توابع مشخص‌شده‌ی آن‌ها را نیز پیاده‌سازی کنید. در صورت لزوم می‌توانید توابع دیگری به کلاس‌هایتان اضافه کنید.

تعاریف

موضوع (topic)

هر خبری که منتشر می‌شود، یک موضوع دارد. به‌طور مثال، sports/basketball/groupstage یک موضوع است؛ یعنی این خبر یک خبر ورزشی در رشته‌ی بسکتبال و در دور گروهی مسابقات است.

پیام (message)

هر خبر یک پیام به همراه خود دارد. به‌طور مثال، Football match result: Team A won! پیامی است که منتشرکننده‌ آن را انتشار می‌دهد. پیام‌ها به‌صورت یک رشته (string) هستند.

کیفیت سرویس (QoS)

کیفیت سرویس یعنی خبری که منتشر می‌شود، برای منتشرکننده چه میزان اهمیت دارد که به دست دنبال‌کننده‌اش برسد. به‌طور مثال، کیفیت سرویس سطح صفر یعنی برای منتشرکننده هیچ اهمیتی ندارد که پیامش به دنبال کننده‌اش رسیده یا نه؛ یعنی پس از انتشار آن را فراموش می‌کند. ولی کیفیت سرویس سطح یک یعنی برای منتشر کننده مهم است که حداقل پیامش به یک مخاطبش رسیده باشد و رسیدن پیام را حداقل به یک دنبال‌کننده گارانتی می‌کند.

منتشرکننده (publisher)

منتشرکننده یک کاربر (client) است که خبر را در یک موضوع مشخص، با یک پیام مشخص و یک کیفیت سرویس منتشر می‌کند. به طور مثال:

client.publish('sports/handball', 'Match result: Team A won!', qos=1)
Python

دنبال‌کننده (subscriber)

دنبال‌کننده نیز یک کاربر است که یک موضوع مشخص را دنبال می‌کند و در صورت match شدن موضوعات، تابع callback را صدا می‌زند. به‌طور مثال:

client.subscribe('sports/football')
Python

تابع callback

تابع callback تابعی است که دنبال‌کننده پس از این‌که موضوع یک خبر با آن match می‌شود، آن تابع را صدا می‌زند. این تابع به‌طور مثال می‌تواند پیام را چاپ کند یا در دیتابیس یا یک لیست اضافه کند. به‌طور مثال این یک تابع callback است که پیام را صرفاً چاپ می‌کند:

def message_callback(topic, message):
    print(f"Received message on topic {topic}: {message}")
Python

توجه داشته باشید که پیاده‌سازی این تابع را نیاز نیست انجام دهید و صرفا باید آن را هنگام match شدن تاپیک صدا بزنید.

سطوح دسترسی موضوعات

  • دسترسی صفرسطحی: در این دسترسی دنبال‌کنندگان باید کاملاً با تاپیک منطبق باشند. (به‌طور مثال /sports به sports/football دسترسی ندارد.)
  • دسترسی یک‌سطحی: در این دسترسی دنبال‌کنندگان تنها می‌توانند در یک عمق با تاپیک اشتراک داشته باشند. (به‌طور مثال sports/+ به sports/football دسترسی دارد ولی به sports/football/finals دسترسی ندارد.)
  • دسترسی چندسطحی: در این دسترسی دنبال‌کنندگان در چند عمق می‌توانند با تاپیک اشتراک داشته باشند. (به‌طور مثال sports/# به sports/football دسترسی دارد و همچنین به sports/football/finals نیز دسترسی دارد.)

سرور

سرور به صورت چندنخی (multi-thread) کار می‌کند و هر خبر در یک نخ منتشر می‌شود. همچنین برای جلوگیری از race condition یک قفل (lock) در درون سرور قرار دارد که در جای لازم نخ‌ها را قفل می‌کند و همچنین دارای دو تابع اصلی publish و subscribe است. این دو تابع اکثر منطق برنامه را در خود جای می‌دهند و کلاس Publisher و Subscriber به‌ترتیب در خود publish و subscribe دارند که با استفاده از توابع متناظر خود در سرور عمل انتشار و دنبال کردن را انجام می‌دهند.

همچنین به این توجه داشته باشید که سرور باید برای دنبال‌کننده‌هایی که در حال حاضر آنلاین نیستند پیام را ذخیره کند. تاپیک‌ها و پیامشان را به صورت آرایه‌ای از تاپل و در فایل messages.pkl و به‌صورت فایل pickle ذخیره کنید.

کاربر (client)

این کلاس برای شما پیاده‌سازی شده است که صرفاً در توابع publish و subscribe با ساختن یک کلاس متناظر با آن و صدا کردن تابعش عمل انتشار و دنبال کردن خبر را انجام می‌دهد.

مثال

کد نمونه

def message_callback(topic, message):
    print(f"Received message on topic {topic}: {message}")
    
server = OlympicsServer()

client = Client(server)
        
client.subscribe('sports/#', message_callback)
        
client.publish('sports/football', 'Football match result: Team A won!', qos=1)
client.publish('sports/football/worldcup', 'World Cup result: Team Z won!', qos=1)
client.publish('sports/basketball/nba', 'NBA result: Team Y won!', qos=1)

Python

خروجی نمونه

Received message on topic sports/football: Football match result: Team A won!
Received message on topic sports/football/worldcup: World Cup result: Team Z won!
Received message on topic sports/basketball/nba: NBA result: Team Y won!
Plain text

در این‌جا دنبال‌کننده چون موضوع sports/# را دنبال کرده است، پس هر خبری که با sports شروع شود را دریافت و با صدا زدن تابع callback آن را چاپ می‌کند.

پروژه‌ی اولیه

پروژه‌ی اولیه‌ی این سؤال را می‌توانید از این لینک دانلود کنید.

نحوه‌ی ارسال

پس از تکمیل پروژه، فایل‌های client.py و server.py را به صورت یک فایل zip را ارسال نمایید.

[your-zip-file-name].zip
├── client.py
└── server.py
Plain text

ارسال پاسخ برای این سؤال
فایلی انتخاب نشده است.