انواع Webhook

توجه: این مستند فقط برای رقابت آنلاین است و برای نیازمندی‌های چت کاربردی ندارد

در این مستند، قصد داریم لیست دقیق وب‌هوک‌ها به همراه داده‌های ورودی و خروجی آنها را به شما نشان دهیم.

پیش‌نیازها

  1. در صورتی که با سرویس بلادرنگ آشنایی ندارید، به معرفی سرویس بلادرنگ مراجعه کنید.
  2. در صورتی که هنوز با تنظیمات پنل سرویس بلادرنگ آشنا نشده اید، به تنظیمات پنل سرویس بلادرنگ مراجعه کنید.
  3. اگر با مفهوم وب‌هوک (Webhook) در سرویس بلادرنگ آشنایی ندارید، به افزودن منطق دلخواه به مسابقه مراجعه کنید.

وب‌هوک Pre-Matchmaking

هنگامی که یک کاربر درخواست matchmaking ارسال می‌کند، در صورتی که این وب‌هوک تنظیم شده باشد، اطلاعات کاربر از سمت کلاینت به این وب‌هوک ارسال می‌شود که در کد این اطلاعات رو مشاهده می‌کنید. خروجی این تابع، به عنوان مقدار skill جدید کاربر در نظر گرفته می‌شود. به عنوان مثال، کد زیر یک نمونه‌ی ساده از وب‌هوک Pre-Matchmaking است:

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
  /* requestBody is like this:
   * {
   *    userId: "<USER-ID>",
   *    skill: 50,
   *    matchmakingName: "<MATCHMAKING-NAME>",
   *    metaData: "<META-DATA>"
   * }
   */

   // TODO: return new skill for this user
   context.succeed(requestBody.skill + 10);
};

این وب‌هوکِ sync کمک می‌کند تا بتوانیم در سمت سرور skill کاربران را override کرده و در نتیجه بدون این‌که نیاز باشد تا کلاینت تغییر بکند، منطق سمت سرور برای match شدن کاربران را تغییر داد.

یک مثال کاربردی از این وب‌هوک به این صورت است: فرض کنید بازی شما به گونه‌ای است که نفرات تقریبا هم‌امتیاز در leaderboard با یکدیگر match می‌شوند. با این حساب، ممکن است این مشکل برای شما پیش بیاید که نفرات بالای لیدربورد شما به سختی بتوانند یک match مناسب پیدا کنند! چون پیدا شدن کاربری هم‌رده‌ی آن‌ها امر دشواری است! در نتیجه، به کمک این وب‌هوک می‌توانید تعیین کنید کسانی که امتیاز آن‌ها از حد مشخصی، مثلا ۲۰۰۰، بالاتر است، به امتیاز زیر ۲۰۰۰ برای matchmaking نگاشت شوند.

در صورتی که این وب‌هوک fail یا timeout شود، ارسال درخواست matchmaking متوقف شده و کلاینت خطای matchmaking webhook failed می‌گیره. بنابراین، در هنگام نوشتن کد این تابع دقت کنید که خطای غیر منتظره‌ای رخ ندهد! هم‌چنین، می‌توانید به جای برگرداندن عدد جدید skill، مقدار null را خروجی دهید که در این صورت، درخواست matchmaking لغو شده و به کلاینت خطای matchmaking is not allowed for you برگردانده می‌شود.

وب‌هوک Update

وب‌هوک Update از مجموعه وب‌هوک‌های مربوط به عملیات Match-Making است. یعنی در حین پیدا شدن بازیکنان جدید برای یک Match این وب‌هوک فراخوانی می‌شود. مثلا وقتی به دنبال ایجاد یک Match ده نفره هستید، به ازای هر یک نفری که به مجموعه این ده نفر اضافه می‌شود، یک بار این وب‌هوک فراخوانی می‌شود. یعنی برای این Match ده نفره، در مجموع نه بار فراخوانی خواهد شد.

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

دقت کنید که هر چیزی در جواب وب‌هوک برگردانده شود، از دید بلادرنگ بی‌معنی است و صرفا محتوای شما را به همه اپلیکیشن‌های درگیر در Match ارسال خواهد کرد و شما باید آن را از طریق SDK خوانده و به صورت مناسب نمایش دهید. در واقع، پاسخ این وب‌هوک از طریق مشخصه‌ی extraMessage در لیسنر onMatchUpdate در اندروید و در لیسنر OnMatchmakingUpdate در یونیتی دریافت می‌شود. به علاوه، دقت کنید که اگرچه این وب‌هوک sync است، اما اگر به هر دلیلی fail شود، روند ارسال پیام match update به کلاینت‌ها مختل نمی‌شود و صرفا extraMessage آن پیامی که به کلاینت‌ها ارسال می‌شود، مقداردهی نشده و null خواهد بود.

اگر آدرس وب‌هوک Update را به یکی از توابعی که در سرویس رایانش بکتوری تعریف کرده‌اید، بدهید، تابع شما با کدی مانند زیر می‌تواند نیاز شما را برآورده کند.

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
  /* requestBody is like this:
   * {
   *   "participants": [
   *     { "userId": "<USER-ID-1>", "requestId": "<SOME-RANDOM-ID>" },
   *     { "userId": "<USER-ID-2>", "requestId": "<SOME-RANDOM-ID>" },
   *     { "userId": "<USER-ID-3>", "requestId": "<SOME-RANDOM-ID>" }
   *   ]
   * }
   */

   // TODO: Fetch avatar images and nick names from database
   context.succeed({
     profiles: [
       { nickName: "flower_72", avatarImage: "https://storage.backtory.com/myApp/user1.png" },
       { nickName: "zeus", avatarImage: null },
       { nickName: "dark_knight", avatarImage: "https://storage.backtory.com/myApp/user3.png" },
     ]
   });
};

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

وب‌هوک Match Found

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

تفاوت این وب‌هوک با وب‌هوک Update در دو چیز است. اول تعداد فراخوانی است، اگر به دنبال یک بازی ۱۰ نفره هستید، وب‌هوک Update نه بار فراخوانی خواهد شد. در حالی که وب‌هوک Match Found تنها یک بار فراخوانی می‌شود. دومین تفاوت در این است که وقتی تعداد بازیکنان یک Match به حد نصاب برسد، بکتوری یک شناسه یکتا به آن Match اختصاص می‌دهد که به کمک این شناسه می‌توانید کارهای بعدی را انجام دهید.

کاربرد: فرض کنید رقابت آنلاین شما سوال و جواب چند گزینه‌ای است. زمان مناسب برای اینکه سوالات انتخاب شده را به کاربران بدهید، زمانی است که یک Match پیدا شود. پس باید در جواب وب‌هوک Match Found لیست سوالات را بازگردانید. سرویس بلادرنگ نیز، لیست سوالات را به دست اپلیکیشن شما خواهد رساند.

اگر آدرس وب‌هوک Match Found را به یکی از توابعی که در سرویس رایانش بکتوری تعریف کرده‌اید، بدهید، تابع شما با کدی مانند زیر می‌تواند نیاز شما را برآورده کند. مشابه وب‌هوک match update، خروجی این وب‌هوک در مشخصه‌ی extraMessage در لیسنر onMatchFound در اندروید و لیسنر OnMatchFound در یونیتی قابل دریافت است. هم‌چنین، اگر این وب‌هوک fail شود، مشابه وب‌هوک update روند اصلی ادامه پیدا می‌کند و فقط extraMessage به null مقداردهی می‌شود.

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
  /* requestBody is like this:
   * {
   *   "realtimeChallengeId": "<REALTIME-GAME-ID>",
   *   "matchmakingName": "<NAME-OF-MATCH-MAKING>",
   *   "participants": [
   *     { "userId": "<USER-ID-1>", "skill": 110, "metaData": "<META-DATA>" },
   *     { "userId": "<USER-ID-2>", "skill": 120, "metaData": "<META-DATA>" },
   *     { "userId": "<USER-ID-3>", "skill": 130, "metaData": "<META-DATA>" }
   *   ]
   * }
   */

  var matchId = requestBody.realtimeChallengeId;
  var participants = requestBody.participants;

  // TODO: Save matchId and participants if needed

  // Return selected questions for this challenge
  context.succeed({
    welcomeMessage: "Welcome to this match",
    questions: [
      { question: "Which city is capital of Iran?", choices: ["Esfahan", "Tehran", "Shiraz", "Ahvaz"] },
      { question: "How tall is Eiffel Tower?", choices: ["324m", "342m", "318m", "381m"] }
    ]
  });
};

توضیح: در مثال بالا ما دو سوال “پایتخت ایران کجاست؟” و “ارتفاع برج ایفل چند متر است؟” سوالاتی است که به کاربران بازگرداندیم. در کاربرد واقعی شما باید یک تعداد سوال تصادفی از پایگاه داده انتخاب کنید، که ما برای ساده شدن مثال از این کار اجتناب کردیم. همچنین عبارت matchId در کد بالا همان شناسه یکتای Match یافت شده است.

وب‌هوک Challenge Ready

این وب‌هوک بسیار مشابه وب‌هوک Match Found است. تنها تفاوت آن، در بدنه‌ی درخواستی است که به این وب‌هوک ارسال می‌شود و در کد زیر مشاهده می‌کنید:

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
  /* requestBody is like this:
   * {
   *   "realtimeChallengeId": "<REALTIME-GAME-ID>",
   *   "challengeName": "<NAME-OF-CHALLENGE>",
   *   "participants": [
   *     { "userId": "<USER-ID-1>", "metaData": "<META-DATA>" },
   *     { "userId": "<USER-ID-2>", "metaData": "<META-DATA>" },
   *     { "userId": "<USER-ID-3>", "metaData": "<META-DATA>" }
   *   ]
   * }
   */

   // TODO: rest of the code ...
};

خروجی این وب‌هوک در مشخصه‌ی extraMessage در لیسنر onChallengeReady در اندروید و لیسنر OnChallengeReadyListener در یونیتی قابل دریافت است. هم‌چنین، اگر این وب‌هوک fail شود، مشابه وب‌هوک match found روند اصلی ادامه پیدا می‌کند و فقط extraMessage به null مقداردهی می‌شود.

وب‌هوک Join

این وب‌هوک وقتی فراخوانی می‌شود که هر یک از بازیکنان یک Match درخواست بازی را Accept کنند. یعنی در SDK پس از آنکه رخداد Match Found اجرا شد، یا از کاربر درخواست Accept جهت آمادگی برای شروع رقابت را دریافت و به بکتوری اعلام کنند و یا بدون دخالت کاربر خود اپلیکیشن Accept را اعلام کند. در این حالت به ازای هر Accept که اتفاق بیفتد یک بار این وب‌هوک فراخوانی می‌شود.

مفهوم Accept:‌ در SDK مفهوم Accept کردن بدین معنی است که پس از آنکه پیام Match Found توسط شما دریافت شد، شما تابع connect به Match یافت‌شده را اجرا کنید. ممکن است علاقه‌مند باشید قبل از اجرای connect از کاربر تایید بگیرید که حاضر است به چنین بازی برود یا خیر. در هر دو صورت در نهایت وقتی تابع connect را فراخوانی کنید، اصطلاحا گفته می‌شود که شما Accept کرده‌اید.

کاربرد:‌ یکی از کاربردهای جذاب این وب‌هوک آن است که می‌توانید کاربرانی که تعداد زیادی از Match ها را Accept نمی‌کنند، شناسایی کنید و امکان انجام Match-Makingهای بعدی را از او بگیرید. برای مثال بازی Dota 2 هر بار که یک کاربر درخواست Match-Making کند ولی بعد از پیدا شدن Match درخواست را Accept نکند، تا پنج دقیقه از دادن درخواست Match-Making جدید محروم می‌کند. به این ترتیب نرخ دادن درخواست‌های Match-Making نادرست که منجر به ناراحتی بقیه کاربران می‌شود کاسته خواهد شد.

در صورتی که آدرس وب‌هوک Join را به یک سرویس رایانش دهید، نمونه کد زیر می‌تواند اطلاعات Accept کاربر را به پایگاه داده بکتوری ذخیره کند:

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
  /* requestBody is like this:
   * {
   *   "userId": "1234",
   *   "username": "changiz_khan",
   *   "challengeId": "<REALTIME-GAME-ID>"
   * }
   */

  var gameId = requestBody.challengeId;
  var userId = requestBody.userId;

  // Create a new JoinInfo to save info of current join
  var JoinInfo = sdk.Object.extend("JoinInfo");
  var newJoin = new JoinInfo();

  // Filling userId and matchId fields
  newJoin.set("userId", userId);
  newJoin.set("gameId", gameId);

  // Saving join to backtory database
  newJoin.save({
      success: function(newJoin) {
        context.succeed({
          message: "Thanks for joining this game: " + requestBody.username
        });
      },

      error: function(error) {
        context.fail({
          message: "Failed to save your Accept to Database."
        });
      }
  });

};

توضیح: در مثال بالا سه فیلد userId و username و challengeId ورودی‌های تابع Join است که توسط بلادرنگ برای تابع شما در رایانش ارسال می‌شود. در ادامه کار ما یک شیء از جنس JoinInfo ساختیم و آن را ذخیره کردیم تا بدانیم که کدام کاربران درخواست Accept را پذیرفته‌اند. توجه کنید که در این مثال فرض شده است شما سرویس پایگاه‌داده بکتوری را در پروژه خود دارید و در آن جدولی به نام JoinInfo ساخته‌اید.

نکته‌ی مهم: پاسخ وب‌هوک join حتما باید شامل کلید message با مقدار رشته باشد تا مقدار متناظر با این کلید به کلاینت ارسال شود.

دقت کنید که این وب‌هوک به صورت sync صدا زده می‌شود و پاسخ آن در لیسنر onJoinedWebhookMessage در اندروید و در لیسنر OnPlayerJoinedWebhook در یونیتی و فقط برای همان کاربری که join شده است، دریافت می‌شود. (در صورتی که این وب‌هوک fail شود، صرفا لیسنرهای بالا صدا زده نمی‌شوند و اتفاق خاص دیگری نمی‌افتد.) با توجه به sync بودن این وب‌هوک و عدم شروع بازی تا اجرای تمام وب‌هوک‌ها و این که به ازای هر کاربر این وب‌هوک صدا زده می‌شود، طبیعی است که استفاده از این وب‌هوک شروع بازی را به تأخیر می‌اندازد و بنابراین پیشنهاد می‌شود که از آن استفاده نشود.

وب‌هوک Start

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

مثال کاربردی: فرض کنید در بازی سوالات چهارگزینه‌ای شما، یک مدل از مسابقه به این صورت است که کاربران ۳۰ ثانیه وقت دارند که به بیشترین تعداد سوالات پاسخ صحیح دهند. شما در این وب‌هوک می‌توانید زمان پایان ۳۰ ثانیه را محاسبه و در دیتابیس برای آن Game ذخیره کنید، تا اگر کاربری برای تقلب بعد از آن ۳۰ ثانیه به سوالی پاسخ داد، پاسخ او پذیرفته نشود.

در صورتی که برای وب‌هوک خود از سرویس رایانش بکتوری استفاده کنید، کدی مشابه نمونه پایین، می‌تواند زمان پایان را محاسبه و ذخیره کند:

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
    /* requestBody is like this:
    * {
    *   "usersId": ["1234", "3243", "32lkj"],
    *   "challengeId": "<REALTIME-GAME-ID>"
    * }
    */

    var matchId = requestBody.challengeId;

    // 1. Find the saved match from Database
    var Match = sdk.Object.extend("Match");
    var query = new sdk.Query(Match);
    query.get(matchId, {
        success: function(match) {
            // 2. Check if it is NOT a SPEED match
            if (match.get("type") != "SPEED") {
                context.succeed({
                    message: "Take it easy, haste is waste."
                });
                return;
            }

            // 3. Otherwise, Add 30 seconds to NOW and set as expiration
            match.set("expireDate", new Date().getTime() + 30 * 1000);

            // 5. Save match to Database
            match.save({
                success: function(match) {
                    // 6. Send extra data (for start) to your application
                    context.succeed({
                        message: "Be as fast as possible, time is the cruelest court."
                    });
                },

                error: function(error) {
                    context.fail();
                }
            });
        },

        error: function(object, error) {
            context.fail();
        }
    });
};

توضیح: در مثال بالا فرض کردیم که شما از سرویس دیتابیس بکتوری استفاده می‌کنید و یک جدول به نام Match در آن دارید که تمامی Matchهای خود را از طریق وب‌هوک‌های دیگر مانند Match Found پیش از این در آن ساخته‌اید. ما در کد بالا، با یک درخواست ساده به کمک matchId اطلاعات Match را از دیتابیس آوردیم و چک کردیم که اگر نوع مسابقه برابر سرعت (SPEED) است، برایش زمان expireDate سی ثانیه گذاشتیم.

این وب‌هوک به صورت async صدا زده می‌شود و پاسخ آن در لیسنر onStartedWebhookMessage در اندروید و در لیسنر OnGameStartedWebhook در یونیتی قابل دریافت است.

نکته‌ی مهم: پاسخ وب‌هوک start حتما باید شامل کلید message با مقدار رشته باشد تا مقدار متناظر با این کلید به کلاینت ارسال شود.

وب‌هوک Leave

در صورتی که بعد از شروع بازی یکی از کاربران از بازی قطع شود، این وب‌هوک فراخوانی خواهد شد. در این وب‌هوک شما شناسه کاربر و شناسه Gameای که عملیات خروج در آن اتفاق افتاده را دارید و می‌توانید کار لازم را انجام دهید. دقت کنید که خروج بازیکنان از بازی بعد از اتمام بازی منجر به اجرای این وب‌هوک نمی‌شود. یعنی اگر بازی تمام شود و در سمت کلاینت‌ها لیسنر onMatchEndedMessage در اندروید و لیسنر onGameEnded در یونیتی صدا زده شود، دیگر وب‌هوک leave با خروج بازیکنان از بازی صدا زده نمی‌شود.

مثال کاربردی: در بسیاری از بازی‌های خوب، وقتی یک کاربر وسط یک بازی از آن خارج شود، تنبیه می‌شود. برای مثال در بازی Dota 2 وقتی یک کاربر یک بازی را نیمه‌کاره رها کند، برای ۵ بازی آینده خود امکان Match-Making عادی ندارد و باید Match-Makingهایی با افراد دیگری که آنها نیز بازی‌ها را نیمه‌کاره رها می‌کنند انجام دهد. در نتیجه بازیکن خاطی، باید با افراد بد رفتار و یا ضعیف بازی کند که باعث می‌شود دفعات بعدی به صورت عمدی اقدام به خروج از بازی نکند.

در صورتی که برای پیاده‌سازی منطق وب‌هوک خود از رایانش استفاده می‌کنید، کدی مانند زیر می‌تواند کاربر را یافته و او را به دسته کاربران خاطی وارد کند:

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
  /* requestBody is like this:
   * {
   *   "userId": "1234",
   *   "username": "changiz_khan",
   *   "challengeId": "<UNIQUE-MATCH-ID>" 
   * }
   */

  var userId = requestBody.userId;

  // 1. Find the user's profile in database by userId
  var Profile = sdk.Object.extend("Profile");
  var query = new Backtory.Query(Profile);
  query.equalTo("userId", userId);
  query.find({
      success: function(profiles) {
          // 2. Check if profile exists
          if (profiles.length == 0) {
              var message = "No profile found for userId: " + userId;
              context.log(message);
              context.fail({ message: message })
              return;
          }

          // 3. Change profile
          var profile = profiles[0];
          profile.set("remainingPunishmentGames", 5);
          profile.save({
                success: function(match) {
                    // 6. Return result
                    context.succeed({
                        message: "He/she is sent to bad matchmaking seed as punishment";
                    });
                },

                error: function(error) {
                    context.fail(error);
                }
          });

      },

      error: function(error) {
          console.fail(error);
      }
  });

};

توضیح: در کد بالا فرض شده است که از سرویس دیتابیس بکتوری برای ذخیره‌سازی اطلاعات خود استفاده می‌کنید و برای هر کاربر یک جدول Profile ساخته‌اید. ما برای هر پروفایل یک فیلد به نام remainingPunishmentGames تعریف کردیم که تعداد رقابت‌های تنبیهی باقیمانده است. در صورتی که یک بازیکن از رقابت Leave دهد، تعداد مسابقات باقیمانده او عدد پنج خواهد شد، و تا وقتی این عدد صفر نشود، در اپلیکیشن می‌توانیم به او فقط امکان Match-Makingهای بد را بدهید.

دقت کنید که این وب‌هوک به صورت async صدا زده می‌شود و پاسخ آن اهمیتی ندارد و دور ریخته می‌شود. اگر فراخوانی آن fail شود نیز اتفاق خاصی نمی‌افتد.

وب‌هوک Event

مهم‌ترین وب‌هوک در بین تمام وب‌هوک‌ها این مورد است. شما هر پیامی که در بازی رد و بدل کنید از این وب‌هوک عبور خواهد کرد (البته اگر آن را در تنظیمات پنل تعریف کنید). نکاتی که در استفاده از این وب‌هوک باید دقت کنید عبارتند از:

مثال کاربردی: در بازی سوال و جواب، پاسخ‌دادن به یک سوال یک Event است. در یک بازی رزمی، هر حرکت انجام شده و یا Combo حرکات یک Event است. به صورت کلی هر اتفاقی در حین بازی که وضعیت بازی را تحت تاثیر قرار می‌دهد یک Event است.

فرض کنید می‌خواهیم در بازی سوال و جواب، گزینه را از یک Event خوانده و در صورتی که کاربر گزینه درست را انتخاب کرده بود، به همه اعلام کنیم که این کاربر ۱۰ امتیاز گرفته است. اگر از سرویس رایانش برای وب‌هوک خود استفاده کنید، کدی ساده‌ای مانند زیر این کار را انجام می‌دهد: (برای ساده‌شدن کد فرض کنید گزینه ۳ گزینه صحیح است)

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
  /* requestBody is like this:
   * {
   *   "userId": "1234",
   *   "challengeId": "<UNIQUE-MATCH-ID>",
   *   "message": {
   *      "myChoice": 3,
   *      "someOtherField": "sample text",
   *      ....  
   *    },
   *    "data": { ... }
   * }
   */

    // 1. Get his/her choice
    var userId = requestBody.userId;
    var hisChoice = requestBody.message.myChoice;

    // 2. Check correct answer
    if (hisChoice == 3) {
        result = { operation: 'addScore', userId: userId, score: 10 };
    } else {
        result = { operation: 'doNothing' };
    }

    context.succeed({
        message: JSON.stringify(result)
    });
};

توضیح: ما فرض کردیم که در اپلیکیشن شما، وقتی کاربری گزینه‌ای را انتخاب می‌کند، یک Event با Messageای به شکل گفته شده در کد بالا ارسال می‌کند. یعنی Message یک فیلد به نام myChoice دارد که گزینه انتخابی کاربر است. ما آن را از ورودی خواندیم و چک کردیم که اگر گزینه انتخاب شده ۳ بود، یک پیام به شکل زیر برای همه کاربران ارسال کنیم:

{ operation: 'addScore', user: userId, score: 10 }

این عبارت نیز در سمت اپلیکیشن معنی پیدا می‌کند و همه کاربران در صفحه نمایش خود، امتیاز کاربر مورد نظر را افزایش خواهند داد.

نکته‌ی مهم: پاسخ وب‌هوک event حتما باید شامل کلید message با مقدار رشته باشد تا مقدار متناظر با این کلید به کلاینت ارسال شود.

وب‌هوک نتیجه بازی

وب‌هوک نتیجه بازی وقتی فراخوانی خواهد شد که همه کاربران از طریق SDK نتیجه بازی را از دید خود اعلام کنند. مثلا در یک بازی ۵ به ۵، هر ۱۰ نفر از دید خود تیم برنده را انتخاب کرده باشند. همچنین برای فعال‌سازی این وب‌هوک باید در تنظیمات پنل بلادرنگ، مقدار “تعیین نتیجه بازی” برابر با “رای اکثریت کاربران” باشد. در حالت رای‌گیری، کاربران می‌توانند از طریق SDK برنده‌ها را از دید خود اعلام کنند و در صورتی که وب‌هوکی برای نتیجه بازی تنظیم نکرده باشید، سرویس بلادرنگ به صورت پیشفرض نظر اکثریت را معیار قرار خواهد داد.

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

مثال کاربردی: برای مثال شما بر اساس وب‌هوک Event، نتیجه بازی را تحلیل کرده‌اید و می‌دانید که برنده کاربر user1 است و user2 بازنده است. و می‌خواهید اگر user2 خلاف این ادعا را کرد او را تنبیه کنید. اگر از سرویس رایانش استفاده می‌کنید، کد ساده‌ای مانند زیر مکانیزم کلی را نشان می‌دهد:

var sdk = require('backtory-sdk');

exports.handler = function(requestBody, context) {
  /* requestBody is like this:
   * {
   *   "challengeId": "<UNIQUE-MATCH-ID>",
   *   "resultList": [
   *      { "userId": "user1", "winners": ["userId1"], "extraData": "<EXTRA-DATA>"},
   *      { "userId": "user2", "winners": ["userId2"], "extraData": "<EXTRA-DATA>"}
   *   ]
   * }
   */

    // 1. Find cheating users
    for (var i = 0; i < requestBody.resultList.length; i++) {
        var result = requestBody.resultList[i];

        var userId = result.userId; 
        if (result.winners.indexOf("userId2") >= 0)  { // <- if user2 is in list of winners
            // 2. TODO: report userId for punishment here
        }
    }

    // 3. return correct result to backtory realtime
    context.succeed({
        winnersId: ["userId1"],
        extraData: "some-text"
    });
};

توضیح:‌ همانطور که در مثال کاربردی بالا توضیح دادیم، جواب صحیح لیست برندگان باید فقط دارای userId1 باید و userId2 غلط است. بنابر این روی تمام resultList نگاه کردیم و هر کس را که userId2 را جز برندگان حساب کرده بود، تنبیه کردیم. در نهایت نیز به سرویس بلادرنگ با کد زیر، برندگان را اعلام کردیم:

context.succeed({
    winnersId: ["userId1"],
    extraData: "some-text"
});

دقت کنید که این وب‌هوک sync است و اگر fail شود، اگرچه سرور بازی را خاتمه داده و خاتمه‌ی بازی با صداشدن لیسنر onMatchEndedMessage در اندروید و لیسنر onGameEnded در یونیتی اعلام می‌شود، ولی این پیام دارای لیست خالی winnersId خواهد بود. ضمنا، شما می‌توانید با بهره‌گیری از extraDataای که کاربران اعلام می‌کنند، منطق‌های پیچیده‌تری را پیاده‌سازی کنید و برندگان بازی را بر اساس این اطلاعات اضافه تعیین کنید و در نهایت، اطلاعات اضافه‌تری را علاوه بر برنده در extraDataی خروجی بازگردانید.

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

گام بعدی