امکانات پیشرفته چت - قسمت اول

دقت کنید که این مستند مخصوص نیازمندی‌های چت است و برای رقابت آنلاین هیچ کاربردی ندارد.

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

پیش‌نیازها

  1. در صورتی که با سرویس بلادرنگ آشنایی ندارید به معرفی سرویس بلادرنگ مراجعه کنید.
  2. در صورتی که هنوز با تنظیمات پنل سرویس بلادرنگ آشنا نشده اید، به تنظیمات پنل سرویس بلادرنگ مراجعه کنید.
  3. اگر هنوز SDK یونیتی را راه‌اندازی نکرده‌اید، به راه‌اندازی SDK یونیتی مراجعه کنید.
  4. در صورتی که با نحوه ایجاد یک چت ساده به کمک سرویس بلادرنگ آشنایی ندارید، مستند اتصال ساده و ارسال پیام را حتما مطالعه کنید.

نکات مهم

توجه کنید که برای آنکه بتوانید هر یک از سرویس‌های گفته شده در ادامه این مستند را به درستی فراخوانی کنید، و کار مورد انتظار شما را انجام دهد، باید نکات زیر را دقت کنید:

  1. کاربر خود را مطابق با مستند اتصال ساده و ارسال پیام به سرویس بلادرنگ بکتوری وصل کرده باشید. زیرا تمامی پیام‌های عضویت، ساخت گروه و … بر روی ارتباط بازی که بکتوری برقرار است کار می‌کنند و بدون آن خطا می‌دهند.
  2. برخی اعمال فقط توسط Owner گروه امکان‌پذیر است، که بر روی هر سرویسی که از این نوع باشد، این نکته یادآوری شده است.
  3. در قسمت اول از امکانات پیشرفته چت، ما تمام کارهایی که کاربر شما می‌تواند انجام دهد و در واقع محرک آن کاربر شماست، را بیان کرده‌ایم. برای مثال دعوت کردن یک عضو به گروهی که کاربر شما Owner آن است. حالت برعکس که کاربر شما خود کسی باشد که دعوت شده، در مستند بعدی که قسمت دوم چت پیشرفته است، پوشش داده شده است.
  4. همه اتفاقاتی که برای کاربر CurrentUser در SDK در گروه‌هایی که عضویت دارد، می‌افتد، از طریق Listener به شما خبر داده می‌شود که در قسمت دوم این مستند می‌توانید آنها را مشاهده کنید.

ساخت گروه چت

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

برای ساخت یک گروه، در اپلیکیشن یونیتی خود کافیست کد زیر را اجرا کنید:

// Create the group
BacktoryChat.Group.CreateNewGroup ("MyGroup", BacktoryChat.Group.Mode.Private,
(response) =>
{
    // Check if creation was successful or not
    if (response.Successful) {
        Debug.Log("Group created successfully with id: " + response.Body.GroupName);
    } else {
        Debug.Log("Group create failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

در مثال بالا ما گروه Private ساختیم. گروه‌ها بر دو نوع هستند:

مهم: محدودیت تعداد اعضای گروه در حال حاضر ۵۰ نفر است.

لیست گروه‌های من

در اپلیکیشن‌های چت مانند Telegram، اولین کاری که با باز شدن اپلیکیشن انجام می‌شود، این است که لیست گروه‌های شما نمایش داده می‌شود. بنابر این لازم است به طریقی بتوانید لیست گروه‌های کاربران را دریافت کنید.

نمونه کد زیر به شما اجازه می‌دهد این لیست را دریافت کرده و log کنید:

// Get list of groups
BacktoryChat.Group.MyGroups ((response) =>
{
    // Check if groups list is retrieved successfully
    if (response.Successful) {
        Debug.Log("List of my groups is:");
        IList<BacktoryChat.Group> groups = response.Body;
        for (int i = 0; i < groups.Count; i++) {
            Debug.Log(i + ". " + groups[i].GroupId + " -> " + groups[i].GroupName);
        }
    } else {
        Debug.Log("Fetching list of groups failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

دریافت لیست اعضای گروه

اگر با اپلیکیشن‌های چت مانند تلگرام یا WhatsApp کار کرده باشید و در گروهی عضو باشید، می‌بینید که با کلیک بر روی نام یا آیکون گروه، می‌توانید لیست اعضای گروه را مشاهده کنید. برای این کار در بکتوری کافیست با داشتن شناسه GroupId لیست اعضای گروه را درخواست دهید.

کد زیر با فرض اینکه شناسه گروه را به کمک سرویس لیست گروه‌ها مطابق مثال قبل به دست آورده‌اید، لیست اعضای آن گروه را از بکتوری دریافت می‌کند:

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group (myGroupId);

// Get group members
backtoryChatGroup.MembersInfo ((response) =>
{
    // Check if members list is retrieved successfully
    if (response.Successful) {
        var members = response.Body;
        for (int i = 0; i < members.Count; i++)
        {
            Debug.Log(i + ". " + members[i].UserId + " -> " + members[i].Role);
        }
    } else {
        Debug.Log("Fetching group members failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

همانطور که در کد دیده می‌شود، جواب لیست اعضای گروه فیلدی به نام GroupMembers دارد که هر عضو یک شناسه UserId و یک نقش (Role) دارد. مقادیری که برای نقش وجود دارد دو حالت است:

افزودن عضو به گروه

جهت فراخوانی این سرویس، یا گروه مورد نظر شما باید Public باشد و یا کاربر CurrentUser ادمین آن گروه باشد.

از آنجایی که گروه بدون کاربران عضو بی‌معنی است، شما باید بتوانید عضوی به گروه خود اضافه کنید. برای این کار نیاز است تا شناسه GroupId و UserId را بدانید.

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group ("<YOUR-GROUP-ID-HERE>");

// Adding a user to a group
backtoryChatGroup.AddMember ("<YOUR-USER-ID-HERE>", (response) =>
{
    // Check if addition is done successfully
    if (response.Successful) {
        Debug.Log("Group member added successfully.");
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

حذف یک کاربر از یک گروه

این امکان فقط برای مدیر یک گروه Private وجود دارد، و از آنجایی که در یک گروه Public همه کاربران می‌توانند دوباره عضو شوند، حذف کردن آنها معنی ندارد.

جهت حذف یک کاربر، در صورتی که کاربر فعلی SDK صاحب (Owner) گروه باشد، می‌تواند با دادن شناسه UserId یک کاربر را از گروه دلخواه خود حذف کنه. نمونه کد زیر یک کاربر فرضی را از یک گروه فرضی حذف می‌کند:

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group ("<YOUR-GROUP-ID-HERE>");

// Removing a user from a group
backtoryChatGroup.RemoveMember("<YOUR-USER-ID-HERE>", (response) =>
{
    // Check if removal is done successfully
    if (response.Successful) {
        Debug.Log("Group member removed successfully.");
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

ارسال پیام در گروه

در صورتی که می‌خواهید از طریق کاربر فعلی دستگاه (CurrentUser) به یک گروه پیامی ارسال کنید، کافیست تابع SendMessage را فراخوانی کنید. این تابع از ورودی شناسه GroupId و متن پیام را دریافت می‌کند. نمونه کد ساده‌ای که این کار را انجام دهد به صورت زیر است:

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group ("<YOUR-GROUP-ID-HERE>");

// Sending a message to the group
backtoryChatGroup.SendMessage ("Hello Everybody!", (response) =>
{
    // Check if message is sent successfully
    if (response.Successful) {
        Debug.Log("Message Sent Successfully.");
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

دادن دسترسی Owner به کاربر عضو

این سرویس فقط برای Owner فعلی سیستم قابل استفاده است. یعنی CurrentUser در SDK باید ادمین گروه مورد نظر باشد.

گاهی نیاز دارید که دسترسی ادمین گروه (Owner) را به بیش از یک نفر بدهید. در صورتی که کاربر فعلی یعنی CurrentUser ادمین گروه باشد می‌تواند با کدی شبیه زیر دسترسی ادمین گروه به کاربر دیگری بدهد.

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group ("<YOUR-GROUP-ID-HERE>");

// Add a new admin
backtoryChatGroup.MakeMemberOwner("<YOUR-USER-ID-HERE>", (response) =>
{
    // Check if admin addition is done successfully
    if (response.Successful) {
        Debug.Log("User is set as new admin successfully.");
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

دعوت کاربران به یک گروه (Invite)

جهت فراخوانی این سرویس، یا گروه مورد نظر شما باید Public باشد و یا کاربر CurrentUser ادمین آن گروه باشد.

سرویس دعوت کردن کاربران، پیامی مبنی بر دعوت شدن به یک گروه را برای کاربر مورد نظر شما ارسال خواهد کرد. کاربر دعوت شده باید دعوت اتفاق افتاده را بپذیرد و در صورت پذیرش، آن کاربر به گروه اضافه خواهد شد.

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

نمونه کد زیر یک کاربر را به یک گروه دعوت می‌کند:

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group ("<YOUR-GROUP-ID-HERE>");

// Invite user to group chat
backtoryChatGroup.InviteToGroup(<YOUR-USER-ID-HERE>", (response) =>
{
    // Check if invitation is sent successfully
    if (response.Successful) {
        Debug.Log("Invitation is sent to backtory successfully.");
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

عضویت در گروه دیگران

برای آنکه بتوانید در یک گروه عضو شوید باید یکی از دو حالت زیر درست باشد:

در صورتی که درخواست Invite برای اپلیکیشن (کاربر CurrentUser) ارسال شود، SDK بکتوری آن را از طریق مکانیزم Listener به شما اعلام خواهد کرد و می‌توانید اقدام مقتضی را انجام دهید. برای آشنایی دقیق با Listener های مربوط به چت به امکانات پیشرفته چت - بخش دوم مراجعه کنید.

در نهایت شما یک شناسه GroupId دارید که می‌خواهید در آن عضو شوید. به کمک تکه کد زیر می‌توانید در هر جای برنامه‌ی خود که هستید درخواست عضویت در یک گروه را بدهید:

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group ("<YOUR-GROUP-ID-HERE>");

// Join the group
backtoryChatGroup.JoinGroup((response) =>
{
    // Check if join was successful or not
    if (response.Successful) {
        Debug.Log("You joined the group successfully.");
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

ترک یک گروه (Leave)

در صورتی که قصد خروج از یک گروه را دارید باید از این سرویس استفاده کنید. به محض خروج از یک گروه، دیگر پیام‌های آن گروه به دست شما نخواهد رسید. برای خروج از یک گروه باید شناسه GroupId را داشته باشید. با داشتن این شناسه، کافیست تکه کدی مانند زیر را اجرا کنید:

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group ("<YOUR-GROUP-ID-HERE>");

// Leave the group
bgc.LeaveGroup ((response) =>
{
    // Check if leave was successful or not
    if (response.Successful) {
        Debug.Log("You left the group successfully.");
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

Owner گروهی که تنها یک owner دارد نمی‌تواند گروه را ترک کند و لذا در صورت تمایل به ترک گروه، باید پیش از انجام این کار فرد یا افراد دیگری را به عنوان owner گروه تعیین کند.

تاریخچه چت‌های یک گروه

زمانی که عضو یک گروه هستید، یکی از کارهای رایجی که می‌خواهید انجام دهید، این است که تاریخچه‌ی چت‌های آن گروه را ببینید. فرض بر این است که GroupId گروه مورد نظر را دانسته و پیام‌های آن گروه را از «تاریخ و ساعت» مشخصی به بعد دارید؛ به عنوان مثال، اگر هیچ پیامی از آن گروه را ندارید، منظور از این «تاریخ و ساعت» مشخص همان زمان حال می‌شود! در این صورت، کدی مانند زیر به شما بسته‌ای از پیام‌های گروه را که به ترتیب و بلافاصله قبل از آن تاریخ و ساعت قرار دارند، در اختیار شما قرار می‌دهد. در مورد این بسته جلوتر صحبت می‌کنیم.

BacktoryChat.Group backtoryChatGroup = new BacktoryChat.Group ("<YOUR-GROUP-ID-HERE>");

// Compute spent time from January 1st, 1970, in milliseconds
DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long currentTimeMillis = (long) (DateTime.UtcNow - Jan1st1970).TotalMilliseconds;

// Request chat group history
backtoryChatGroup.History(currentTimeMillis, (response) =>
{
    // Check if request was successful
    if (response.Successful) {
        var messageList = response.Body;
        foreach (AbsGroupChatMessage message in messageList) {
            // Cast message to its appropriate type
            if (message is BacktoryGroupChatMessage) {
                var msg = (BacktoryGroupChatMessage) message;
                Debug.Log("Group message from " + msg.SenderUserId + ": "
                        + msg.Content);
            }
            else if (message is BacktoryUserAddedToGroupMessage) {
                var msg = (BacktoryUserAddedToGroupMessage) message;
                Debug.Log("User " + msg.AddedUserId + " is added to group by "
                        + msg.AdderUserId);
            }
            else if (message is BacktoryUserJoinedGroupMessage) {
                var msg = (BacktoryUserJoinedGroupMessage) message;
                Debug.Log("User " + msg.JoinedUserId + " joined the group.");
            }
            else if (message is BacktoryUserLeftGroupMessage) {
                var msg = (BacktoryUserLeftGroupMessage) message;
                Debug.Log("User " + msg.DepartedUserId + " left the group.");
            }
            else if (message is BacktoryUserRemovedFromGroupMessage) {
                var msg = (BacktoryUserRemovedFromGroupMessage) message;
                Debug.Log("User " + msg.RemovedUserId + " is removed by "
                        + msg.RemoverUserId);
            }
        }
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

همان‌طور که مشاهده می‌کنید، ابتدا باید زمان گذشته از تاریخ ۱ ژانویه‌ی ۱۹۷۰ را بر حسب میلی‌ثانیه حساب کرده و در یک متغیر long بریزیم و سپس، این متغیر را به عنوان آرگومان تابع History بدهیم. پیام‌های بکتوری هم همگی یک مشخصه از جنس long به نام Date دارند که زمان ارسال پیام را بر حسب میلی‌ثانیه‌ی گذشته از تاریخ ۱ ژانویه‌ی ۱۹۷۰ نشان می‌دهد. با این حساب، با صدازدن متد بالا، همه‌ی پیام‌های این گروه را تا تاریخ و ساعت «آخرین پیام موجود در لیست» داریم و سری بعدی، کافیست که این متد را با تاریخ و ساعت همان آخرین پیام فراخوانی کنیم.

هم‌چنین، گفته شد که با هربار صدا زدن تابع بالا، یک بسته از پیام‌های گروه به دست ما می‌رسد. سایز این بسته حداکثر یک عدد ثابت است که این عدد ثابت سمت سرور تعیین می‌شود و هم‌اکنون برابر ۲۵ است. در صورتی که بیش از ۲۵ عدد پیام قبل از تاریخ و ساعت مشخص‌شده وجود داشته باشند، دقیقا ۲۵ پیام منتهی به تاریخ و ساعت مشخص‌شده بارگذاری می‌شوند و برای دسترسی به بقیه‌ی پیام‌ها، دوباره باید متد بالا را صدا کنیم (با تاریخ و ساعت جدید!). در غیر این‌صورت، چون پیام‌های منتهی به زمان مشخص‌شده کمتر یا مساوی ۲۵ تا هستند، همه‌ی آن‌ها با موفقیت دریافت می‌شوند.

تاریخچه چت‌های کاربر

مشابه قسمت قبل، یکی از کارهای رایج دیگر این است که تاریخچه‌ی چت‌های خود با یک کاربر خاص را ببینید. فرض بر اینست که UserId کاربر مورد نظر را دانسته و پیام‌های چت با او را از «تاریخ و ساعت» مشخصی به بعد دارید. به عنوان مثال، اگر هیچ پیامی از آن گروه را ندارید، منظور از این «تاریخ و ساعت» مشخص همان زمان حال می‌شود! در این صورت، کدی مانند زیر به شما بسته‌ای از پیام‌های چت با آن کاربر را که به ترتیب و بلافاصله قبل از آن تاریخ و ساعت قرار دارند، در اختیار شما قرار می‌دهد. ساختار این بسته‌ها به لحاظ تعداد از سناریوی مشابه در قسمت قبل پیروی می‌کند.

BacktoryChat.Direct backtoryDirectChat = new BacktoryChat.Direct ("<YOUR-USER-ID-HERE>");

// Compute spent time from January 1st, 1970, in milliseconds
DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long currentTimeMillis = (long) (DateTime.UtcNow - Jan1st1970).TotalMilliseconds;

// Request chat history
backtoryDirectChat.History(currentTimeMillis, (response) =>
{
    // Check if request was successful
    if (response.Successful) {
        var messageList = response.Body;
        foreach (BacktoryDirectChatMessage message in messageList) {
            Debug.Log("Direct message from " + message.SenderUserId + ": "
                    + message.Content);
        }
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

دریافت پیام‌های Offline

وقتی یک کاربر به سرویس بلادرنگ اتصال پیدا می‌کند، می‌توانید پیام‌هایی را که در مدت وصل نبودنش به سرویس بلادرنگ بکتوری برای او ارسال شده است (اصطلاحا می‌گوییم پیام‌های Offline)، برای او نمایش دهید. برای این کار به طریق زیر اقدام کنید:

BacktoryChat.OfflineMessages((response) =>
{
    // Check if request was successful
    if (response.Successful) {
        var messageList = response.Body;

        foreach (AbsChatMessage message in messageList) {
            // Cast message to its appropriate type
            if (message is BacktoryDirectChatMessage) {
                var msg = (BacktoryDirectChatMessage) message;
                Debug.Log("Direct message from " + msg.SenderUserId + ": "
                        + msg.Content);
            }
            else if (message is BacktoryInvitationToGroupMessage) {
                var msg = (BacktoryInvitationToGroupMessage) message;
                Debug.Log("Invitation to group " + msg.GroupName
                        + " by User " + msg.InviterUserId);
            }            
            else if (message is BacktoryGroupChatMessage) {
                var msg = (BacktoryGroupChatMessage) message;
                Debug.Log("Group message from " + msg.SenderUserId + ": "
                        + msg.Content);
            }
            else if (message is BacktoryUserAddedToGroupMessage) {
                var msg = (BacktoryUserAddedToGroupMessage) message;
                Debug.Log("User " + msg.AddedUserId + " is added to group by "
                        + msg.AdderUserId);
            }
            else if (message is BacktoryUserJoinedGroupMessage) {
                var msg = (BacktoryUserJoinedGroupMessage) message;
                Debug.Log("User " + msg.JoinedUserId + " joined the group.");
            }
            else if (message is BacktoryUserLeftGroupMessage) {
                var msg = (BacktoryUserLeftGroupMessage) message;
                Debug.Log("User " + msg.DepartedUserId + " left the group.");
            }
            else if (message is BacktoryUserRemovedFromGroupMessage) {
                var msg = (BacktoryUserRemovedFromGroupMessage) message;
                Debug.Log("User " + msg.RemovedUserId + " is removed by "
                        + msg.RemoverUserId);
            }
        }
    } else {
        Debug.Log("Operation failed with code: "
            + response.Code
            + " and message: "
            + response.Message);
    }
});

در این‌جا هم پیام‌ها در بسته‌هایی به ما عرضه می‌شود که این بسته‌ها به لحاظ تعدادشان مشابه دو قسمت قبلی هستند.

نکته: پیام‌های درون بسته‌های دریافت شده در درخواست‌های history بر اساس زمان مرتب‌شده هستند و درایه‌ی صفرم آرایه از همه جدیدتر است. هم‌چنین، پیام‌های درون بسته‌های دریافت شده در درخواست offline نیز بر اساس زمان مرتب‌شده هستند؛ اما درایه‌ی صفرم آرایه از همه قدیمی‌تر است.

برای جا افتادن بهتر نحوه‌ی کار با درخواست OfflineMessages مثالی می‌زنیم. فرض کنید می‌خواهید برنامه‌ای مانند تلگرام پیاده‌سازی کنید که به هنگام بالا آمدن، همه‌ی پیام‌هایی را که به هنگام آف‌لاین بودن برای کاربر ارسال شده است، دریافت کند. برای این هدف باید آن‌قدر تابع OfflineMessages را صدا کند تا این‌که بسته‌ای با سایز کمتر از ۲۵ دریافت کند. در این حالت مطمئن می‌شوید که همه‌ی پیام‌های آف‌لاین را دریافت کرده‌اید. کد زیر این کار را انجام می‌دهد:

const int PAGE_SIZE = 25;
List<AbsChatMessage> allMessages = new List<AbsChatMessage>();

public void FetchAllOfflineMessages() {
    BacktoryChat.OfflineMessages (response => {
        if (response.Successful) {
            IList<AbsChatMessage> newPage = response.Body;
            allMessages.AddRange(newPage);

            if (newPage.Count >= PAGE_SIZE) {
                FetchAllOfflineMessages();
            }
        } else {
            Debug.Log("failed; " + response.Message);
        }
    });
}

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

گام بعدی