Beispiel #1
0
 /// <summary>Fetch the score list for a given board.</summary>
 /// <returns>Promise resolved when the operation has completed. The attached value describes a list of scores, and
 ///     provides pagination functionality.</returns>
 /// <param name="board">The name of the board to fetch scores from.</param>
 /// <param name="limit">The maximum number of results to return per page.</param>
 /// <param name="offset">Number of the first result. Needs to be a multiple of `limit`. The special value of -1 can be used
 ///     to auto-select the page where the current logged in user is located, including his score in the result. After
 ///     that, you may use the paged result handler to fetch pages nearby.</param>
 public Promise<PagedList<Score>> List(string board, int limit = 30, int offset = 0)
 {
     UrlBuilder url = new UrlBuilder("/v2.6/gamer/scores").Path(domain).Path(board).QueryParam("count", limit);
     if (offset == -1) url.QueryParam("page", "me");
     else              url.QueryParam("page", offset / limit + 1);
     return Common.RunInTask<PagedList<Score>>(Gamer.MakeHttpRequest(url), (response, task) => {
         // Pagination computing
         Bundle boardData = response.BodyJson[board];
         int currentItems = boardData["scores"].AsArray().Count;
         int total = Math.Min(boardData["maxpage"] * limit, offset + currentItems);
         // Fetch listed scores
         PagedList<Score> scores = new PagedList<Score>(response.BodyJson, offset, total);
         int rank = boardData["rankOfFirst"];
         foreach (Bundle b in boardData["scores"].AsArray()) {
             scores.Add(new Score(b, rank++));
         }
         // Handle pagination
         if (offset > 0) {
             scores.Previous = () => List(board, limit, offset - limit);
         }
         if (offset + scores.Count < scores.Total) {
             scores.Next = () => List(board, limit, offset + limit);
         }
         task.PostResult(scores);
     });
 }
Beispiel #2
0
 /// <summary>Terminates the match. You need to be the creator of the match to perform this operation.</summary>
 /// <returns>Promise resolved when the operation has completed.</returns>
 /// <param name="deleteToo">If true, deletes the match if it finishes successfully or is already finished.</param>
 /// <param name="notification">A notification that can be sent to all players currently playing the match (except you).</param>
 public Promise<Done> Finish(bool deleteToo = false, PushNotification notification = null)
 {
     UrlBuilder url = new UrlBuilder("/v1/gamer/matches").Path(MatchId).Path("finish");
     url.QueryParam("lastEventId", LastEventId);
     HttpRequest req = Gamer.MakeHttpRequest(url);
     req.BodyJson = Bundle.CreateObject("osn", notification != null ? notification.Data : null);
     return Common.RunInTask<Done>(req, (response, task) => {
         UpdateWithServerData(response.BodyJson["match"]);
         // Affect match
         Status = MatchStatus.Finished;
         // Also delete match
         if (deleteToo) {
             Gamer.Matches.Delete(MatchId).ForwardTo(task);
         }
         else {
             task.PostResult(new Done(true, response.BodyJson));
         }
     });
 }
Beispiel #3
0
 /// <summary>Draws an item from the shoe.</summary>
 /// <returns>Promise resolved when the operation has completed. The attached bundle contains an array of items drawn
 ///     from the shoe. You may do `(int)result.Value[0]` to fetch the first value as integer.</returns>
 /// <param name="count">The number of items to draw from the shoe.</param>
 /// <param name="notification">A notification that can be sent to all players currently playing the match (except you).</param>
 public Promise<DrawnItemsResult> DrawFromShoe(int count = 1, PushNotification notification = null)
 {
     UrlBuilder url = new UrlBuilder("/v1/gamer/matches").Path(MatchId).Path("shoe").Path("draw");
     url.QueryParam("count", count).QueryParam("lastEventId", LastEventId);
     HttpRequest req = Gamer.MakeHttpRequest(url);
     req.BodyJson = Bundle.CreateObject("osn", notification != null ? notification.Data : null);
     return Common.RunInTask<DrawnItemsResult>(req, (response, task) => {
         UpdateWithServerData(response.BodyJson["match"]);
         task.PostResult(new DrawnItemsResult(response.BodyJson));
     });
 }
Beispiel #4
0
 private Promise<IndexSearchResult> Search(string query, Bundle jsonData, List<string> sortingProperties, int limit, int offset)
 {
     UrlBuilder url = new UrlBuilder("/v1/index").Path(Domain).Path(IndexName).Path("search");
     if (query != null) url.QueryParam("q", query);
     url.QueryParam("from", offset).QueryParam("max", limit);
     // Build sort property
     if (sortingProperties != null) {
         Bundle sort = Bundle.CreateArray();
         foreach (string s in sortingProperties) sort.Add(s);
         url.QueryParam("sort", sort.ToJson());
     }
     var request = Cloud.MakeUnauthenticatedHttpRequest(url);
     request.Method = "POST";
     if (jsonData != null) request.BodyJson = jsonData;
     return Common.RunInTask<IndexSearchResult>(request, (response, task) => {
         // Fetch listed scores
         IndexSearchResult result = new IndexSearchResult(response.BodyJson, offset);
         foreach (Bundle b in response.BodyJson["hits"].AsArray()) {
             result.Hits.Add(new IndexResult(b));
         }
         // Handle pagination
         if (offset > 0) {
             result.Hits.Previous = () => {
                 var promise = new Promise<PagedList<IndexResult>>();
                 Search(query, jsonData, sortingProperties, limit, offset - limit)
                     .Then(r => promise.Resolve(r.Hits))
                     .Catch(e => promise.Reject(e));
                 return promise;
             };
         }
         if (offset + result.Hits.Count < result.Hits.Total) {
             result.Hits.Next = () => {
                 var promise = new Promise<PagedList<IndexResult>>();
                 Search(query, jsonData, sortingProperties, limit, offset + limit)
                     .Then(r => promise.Resolve(r.Hits))
                     .Catch(e => promise.Reject(e));
                 return promise;
             };
         }
         task.PostResult(result);
     });
 }
Beispiel #5
0
 /// <summary>Method used to retrieve the application's friends of the currently logged in profile.</summary>
 /// <returns>Promise resolved when the operation has completed, with the fetched list of friends.</returns>
 /// <param name="filterBlacklisted">When set to true, restricts to blacklisted friends.</param>
 public Promise<NonpagedList<GamerInfo>> ListFriends(bool filterBlacklisted = false)
 {
     UrlBuilder url = new UrlBuilder("/v2.6/gamer/friends").Path(domain);
     if (filterBlacklisted) url.QueryParam("status", "blacklist");
     HttpRequest req = Gamer.MakeHttpRequest(url);
     return Common.RunInTask<NonpagedList<GamerInfo>>(req, (response, task) => {
         var result = new NonpagedList<GamerInfo>(response.BodyJson);
         foreach (Bundle f in response.BodyJson["friends"].AsArray()) {
             result.Add(new GamerInfo(f));
         }
         task.PostResult(result);
     });
 }
Beispiel #6
0
 /// <summary>Post a score.</summary>
 /// <returns>Promise resolved when the operation has completed. The attached value contains the new rank of the
 ///     player as well as whether the score was saved.</returns>
 /// <param name="score">The score (numeric value) to record.</param>
 /// <param name="board">The name of the board to post the score to. You may have as many boards as you like for your
 ///     game, and scores are scoped between them.</param>
 /// <param name="order">The order for this board. As board are not configured on the server, any client can create a
 ///     board dynamically. This parameter serves as as a description for the board and is used only upon
 ///     creation (that is, the first player posting to the named board).</param>
 /// <param name="scoreInfo">An optional string used to describe the score made by the user.</param>
 /// <param name="forceSave">When set to true, the score is saved even if its value is less than the past best score
 ///     for this player.</param>
 public Promise<PostedGameScore> Post(long score, string board, ScoreOrder order, string scoreInfo = null, bool forceSave = false)
 {
     UrlBuilder url = new UrlBuilder("/v2.6/gamer/scores").Path(domain).Path(board);
     switch (order) {
         case ScoreOrder.HighToLow: url.QueryParam("order", "hightolow"); break;
         case ScoreOrder.LowToHigh: url.QueryParam("order", "lowtohigh"); break;
     }
     url.QueryParam("mayvary", forceSave);
     HttpRequest req = Gamer.MakeHttpRequest(url);
     req.BodyJson = Bundle.CreateObject("score", score, "info", scoreInfo);
     return Common.RunInTask<PostedGameScore>(req, (response, task) => {
         task.PostResult(new PostedGameScore(response.BodyJson));
     });
 }
Beispiel #7
0
 /// <summary>
 /// Can be used to list the active matches for this game. In general, it is not recommended to proceed this way
 /// if your goal is to display the games that may be joined. The indexing API is better suited to this use case
 /// (index the match along with properties and look for matches matching the desired properties).
 /// </summary>
 /// <returns>Promise resolved when the operation has completed. The list of matches filtered according to the
 ///     following parameters is provided.</returns>
 /// <param name="participating">Set to true to only list matches to which this user is participating.</param>
 /// <param name="invited">Set to true to filter by matches you are invited to (only include them).</param>
 /// <param name="finished">Set to true to also include finished matchs (which are filtered out by default).</param>
 /// <param name="full">Set to true to also include games where the maximum number of players has been reached.</param>
 /// <param name="limit">For pagination, allows to set a greater or smaller page size than the default 30.</param>
 /// <param name="offset">For pagination, avoid using it explicitly.</param>
 public Promise<PagedList<MatchListResult>> List(bool participating = false, bool invited = false, bool finished = false, bool full = false, int limit = 30, int offset = 0)
 {
     UrlBuilder url = new UrlBuilder("/v1/gamer/matches");
     url.QueryParam("domain", domain).QueryParam("offset", offset).QueryParam("limit", limit);
     if (participating) url.QueryParam("participating");
     if (finished) url.QueryParam("finished");
     if (invited) url.QueryParam("invited");
     if (full) url.QueryParam("full");
     // Request for current results
     return Common.RunInTask<PagedList<MatchListResult>>(Gamer.MakeHttpRequest(url), (response, task) => {
         PagedList<MatchListResult> matches = new PagedList<MatchListResult>(response.BodyJson, offset, response.BodyJson["count"]);
         foreach (Bundle b in response.BodyJson["matches"].AsArray()) {
             matches.Add(new MatchListResult(b));
         }
         // Handle pagination
         if (offset > 0) {
             matches.Previous = () => List(participating, invited, finished, full, limit, offset - limit);
         }
         if (offset + matches.Count < matches.Total) {
             matches.Next = () => List(participating, invited, finished, full, limit, offset + limit);
         }
         task.PostResult(matches);
     });
 }
Beispiel #8
0
        private void Run()
        {
            int delay = LoopIterationDuration;
            string messageToAcknowledge = null;
            bool lastResultPositive = true;

            while (!Stopped) {
                if (!lastResultPositive) {
                    // Last time failed, wait a bit to avoid bombing the Internet.
                    Thread.Sleep(PopEventDelayThreadHold);
                }

                UrlBuilder url = new UrlBuilder("/v1/gamer/event");
                url.Path(Domain).QueryParam("timeout", delay);
                if (messageToAcknowledge != null) {
                    url.QueryParam("ack", messageToAcknowledge);
                }

                CurrentRequest = Gamer.MakeHttpRequest(url);
                CurrentRequest.RetryPolicy = HttpRequest.Policy.NonpermanentErrors;
                CurrentRequest.TimeoutMillisec = delay + 30000;
                CurrentRequest.DoNotEnqueue = true;

                Managers.HttpClient.Run(CurrentRequest, (HttpResponse res) => {
                    CurrentRequest = null;
                    try {
                        lastResultPositive = true;
                        if (res.StatusCode == 200) {
                            messageToAcknowledge = res.BodyJson["id"];
                            ProcessEvent(res);
                        }
                        else if (res.StatusCode != 204) {
                            lastResultPositive = false;
                            // Non retriable error -> kill ourselves
                            if (res.StatusCode >= 400 && res.StatusCode < 500) {
                                Stopped = true;
                            }
                        }
                    }
                    catch (Exception e) {
                        Common.LogError("Exception happened in pop event loop: " + e.ToString());
                    }
                    SynchronousRequestLock.Set();
                });

                // Wait for request (synchronous)
                SynchronousRequestLock.WaitOne();

                // Wait if suspended
                if (Paused) {
                    SynchronousRequestLock.WaitOne();
                    lastResultPositive = true;
                }
            }
            Common.Log("Finished pop event thread " + Thread.CurrentThread.ManagedThreadId);
        }