/*
* Copyright 2014-2015 GameUp
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.gameup.android;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.squareup.okhttp.Request;
import java.util.List;
import io.gameup.android.entity.Achievement;
import io.gameup.android.entity.Gamer;
import io.gameup.android.entity.LeaderboardAndRank;
import io.gameup.android.entity.Match;
import io.gameup.android.entity.MatchList;
import io.gameup.android.entity.Message;
import io.gameup.android.entity.MessageList;
import io.gameup.android.entity.Ping;
import io.gameup.android.entity.PurchaseVerification;
import io.gameup.android.entity.Rank;
import io.gameup.android.entity.SharedStorage;
import io.gameup.android.entity.TurnList;
import io.gameup.android.http.RequestFactory;
import io.gameup.android.entity.AchievementList;
import io.gameup.android.http.RequestSender;
import io.gameup.android.json.AchievementProgress;
import io.gameup.android.json.GamerUpdate;
import io.gameup.android.json.GsonFactory;
import io.gameup.android.json.LeaderboardSubmission;
import io.gameup.android.json.MatchAction;
import io.gameup.android.json.MatchPlayers;
import io.gameup.android.json.MatchTurn;
import io.gameup.android.json.PurchaseVerify;
import io.gameup.android.json.PushRegistration;
import io.gameup.android.json.StorageGetWrapper;
import io.gameup.android.push.Push;
import lombok.Getter;
import lombok.NonNull;
/**
* Represents a session for an authenticated user.
*
* All operations are thread-safe.
*
* Since this represents a particular user, the token is fixed - if it needs to
* change then a new session should be created via the GameUp.login() method.
*
* Call the ping() method to check that the remote service is reachable, and
* that the session is accepted with the given API key.
*/
@Getter
public class GameUpSession {
/** The API key this session is bound to. */
private final String apiKey;
/** The user identification token for this session. */
private final String token;
/** Rough local device timestamp when this session was created. */
private final long createdAt;
/**
* Initialise with the given token.
*
* @param apiKey The API key to use, must not be null.
* @param token The token key to use, must not be null.
*/
GameUpSession(final @NonNull String apiKey, final @NonNull String token) {
this.apiKey = apiKey;
this.token = token;
this.createdAt = System.currentTimeMillis();
}
/**
* Serialise this instance to a String, safe for storage or transmission.
* The resulting String is ~230 bytes long.
*
* @return A String representation of this instance.
*/
@Override
public String toString() {
return GsonFactory.get().toJson(this);
}
/**
* Load a session from the given String. Will fail hard if the input does
* not represent a GameUpSession instance.
*
* @param gameUpSession The String to attempt to load from.
* @return The retrieved GameUpSession instance.
*/
public static GameUpSession fromString(final @NonNull String gameUpSession) {
try {
return GsonFactory.get().fromJson(
gameUpSession, GameUpSession.class);
}
catch (final JsonParseException e) {
throw new RuntimeException("Input is not a valid GameUpSession", e);
}
}
/**
* Ping the GameUp service to check it is reachable and ready to handle
* requests.
*
* Completes successfully if the service is reachable, responds correctly,
* and accepts the API key and token combination.
*
* Throws a GameUpException otherwise.
*/
public void ping() {
final Request request = RequestFactory.head(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.build(),
apiKey,
token);
RequestSender.send(request);
}
/**
* Ping the GameUp service to check it is reachable and ready to handle
* requests.
*
* Completes successfully if the service is reachable, responds correctly,
* and accepts the API key and token combination.
*
* Throws a GameUpException otherwise.
*
* @return A Ping object containing the server time.
*/
public Ping pingGet() {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.build(),
apiKey,
token);
return RequestSender.send(request, Ping.class);
}
/**
* Get information about the gamer who owns this session.
*
* @return An entity containing gamer information.
*/
public Gamer gamer() {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.build(),
apiKey,
token);
return RequestSender.send(request, Gamer.class);
}
/**
* Update a gamer's account or profile information. Currently only nickname
* changes are exposed.
*/
public void gamer(final @NonNull String nickname) {
final Request request = RequestFactory.post(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.ACCOUNTS_SERVER)
.appendPath("v0")
.appendPath("gamer")
.build(),
apiKey,
token,
GsonFactory.get().toJson(new GamerUpdate(nickname)));
RequestSender.send(request);
}
/**
* Perform a key-value storage write operation, storing data as JSON. Data
* is private per-user and per-game.
*
* NOTE: This is not designed to store confidential data, such as payment
* information etc.
*
* @param key The key to store the given data under.
* @param value The object to serialise and store.
*/
public void storagePut(final @NonNull String key,
final @NonNull Object value) {
final Request request = RequestFactory.put(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("storage")
.appendPath(key)
.build(),
apiKey,
token,
GsonFactory.get().toJson(value));
RequestSender.send(request);
}
/**
* Perform a key-value storage read operation.
*
* @param key The key to attempt to read data from.
* @param type The class literal to attempt to deserialise as.
* @return The entity requested, or null if there was no data.
*/
public <T> T storageGet(final @NonNull String key,
final @NonNull Class<T> type) {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("storage")
.appendPath(key)
.build(),
apiKey,
token);
final StorageGetWrapper wrapper;
try {
wrapper = RequestSender.send(request, StorageGetWrapper.class);
}
catch (final GameUpException e) {
if (e.getStatus() == 404) {
return null;
}
else {
throw e;
}
}
try {
return GsonFactory.get().fromJson(wrapper.getValue(), type);
}
catch (final JsonParseException e) {
throw new GameUpException(400,
"Response data does not match expected entity");
}
}
/**
* Perform a key-value storage delete operation. Will silently ignore absent
* data.
*
* @param key The key to delete data from.
*/
public void storageDelete(final @NonNull String key) {
final Request request = RequestFactory.delete(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("storage")
.appendPath(key)
.build(),
apiKey,
token);
RequestSender.send(request);
}
/**
* Directly get a shared storage key.
*
* @param key The key to look up and retrieve.
* @return A SharedStorage instance containing the requested data.
*/
public SharedStorage sharedStorageGet(final @NonNull String key) {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("storage")
.appendPath(key)
.build(),
apiKey,
token);
return RequestSender.send(request, SharedStorage.class);
}
/**
* Completely replace the public portion of a shared storage key with the
* given value.
*
* @param key The key to replace the public portion for.
* @param value The value to replace it with.
*/
public void sharedStoragePut(final @NonNull String key,
final @NonNull Object value) {
final Request request = RequestFactory.put(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("shared")
.appendPath(key)
.appendPath("public")
.build(),
apiKey,
token,
GsonFactory.get().toJson(value));
RequestSender.send(request);
}
/**
* Perform a JSON merge on the public portion of a shared storage key.
*
* @param key The key to update the public portion for.
* @param value The value to use in the merge operation.
*/
public void sharedStorageUpdate(final @NonNull String key,
final @NonNull Object value) {
final Request request = RequestFactory.patch(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("shared")
.appendPath(key)
.appendPath("public")
.build(),
apiKey,
token,
GsonFactory.get().toJson(value));
RequestSender.send(request);
}
/**
* Delete the public portion of a shared storage key.
*
* @param key The key to delete the public portion for.
*/
public void sharedStorageDelete(final @NonNull String key) {
final Request request = RequestFactory.delete(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("shared")
.appendPath(key)
.appendPath("public")
.build(),
apiKey,
token);
RequestSender.send(request);
}
/**
* Report progress towards a given achievement. Equivalent to calling
* achievement(apiKey, achievementId, 1) below.
*
* Progress will be "1". This method is intended for convenience when
* triggering "normal"-type achievements, but will still add 1 to an
* "incremental"-type achievement if needed.
*
* @param achievementId The internal Achievement ID to interact with.
* @return An Achievement instance if this call results in an achievement
* being completed or progress is reported, null otherwise.
*/
public Achievement achievement(final @NonNull String achievementId) {
return achievement(achievementId, 1);
}
/**
* Report progress towards a given achievement.
*
* @param achievementId The internal Achievement ID to interact with.
* @param count The progress amount to report.
* @return An Achievement instance if this call results in an achievement
* being completed or progress is reported, null otherwise.
*/
public Achievement achievement(final @NonNull String achievementId,
final int count) {
final Request request = RequestFactory.post(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("achievement")
.appendPath(achievementId)
.build(),
apiKey,
token,
GsonFactory.get().toJson(new AchievementProgress(count)));
return RequestSender.send(request, Achievement.class);
}
/**
* Get a list of achievements available for the game, including any gamer
* data such as progress or completed timestamps.
*
* @return A List containing Achievement instances, may be empty if none are
* returned for the current game.
*/
public AchievementList achievement() {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("achievement")
.build(),
apiKey,
token);
return RequestSender.send(request, AchievementList.class);
}
/**
* Submit a new score to the specified leaderboard. The new score will only
* overwrite any previously submitted value if it's "better" according to
* the sorting rules of the leaderboard, but updated ranking details are
* returned in all cases.
*
* @param leaderboardId The private ID of the leaderboard to submit to.
* @param score The score to submit.
* @return A Rank instance containing updated detailed rank data for the
* current gamer.
*/
public Rank leaderboard(final @NonNull String leaderboardId,
final long score) {
final Request request = RequestFactory.post(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("leaderboard")
.appendPath(leaderboardId)
.build(),
apiKey,
token,
GsonFactory.get().toJson(new LeaderboardSubmission(score)));
return RequestSender.send(request, Rank.class);
}
/**
* Request leaderboard metadata, the current top ranked gamers, and the
* current gamer's detailed ranking on a specified leaderboard.
*
* @param leaderboardId The private ID of the leaderboard to request.
* @return A corresponding LeaderboardAndRank instance.
*/
public LeaderboardAndRank leaderboard(final @NonNull String leaderboardId) {
return leaderboard(leaderboardId, 50, 0, false);
}
/**
* Request leaderboard metadata, and a page of entries on the leaderboard,
* containing up to 'limit' number of entries and paginated to the page that
* contains the current gamer's score on this leaderboard, if possible.
*
* Includes the current gamer's detailed ranking on this leaderboard.
*
* @param leaderboardId The private ID of the leaderboard to request.
* @param limit The maximum number of leaderboard entries to return.
* @param withScoretags true if each entry's scoretags should be included in
* the response, false otherwise.
* @return A corresponding LeaderboardAndRank instance.
*/
public LeaderboardAndRank leaderboard(final @NonNull String leaderboardId,
final int limit,
final boolean withScoretags) {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("leaderboard")
.appendPath(leaderboardId)
.appendQueryParameter("limit",
Integer.toString(limit))
.appendQueryParameter("auto_offset", "true")
.appendQueryParameter("with_scoretags",
Boolean.toString(withScoretags))
.build(),
apiKey,
token);
return RequestSender.send(request, LeaderboardAndRank.class);
}
/**
* Request leaderboard metadata, and a page of entries on the leaderboard,
* identified by the limit and offset parameters provided.
*
* Includes the current gamer's detailed ranking on this leaderboard.
*
* @param leaderboardId The private ID of the leaderboard to request.
* @param limit The maximum number of leaderboard entries to return.
* @param offset The offset to start entries from, used for pagination.
* @param withScoretags true if each entry's scoretags should be included in
* the response, false otherwise.
* @return A corresponding LeaderboardAndRank instance.
*/
public LeaderboardAndRank leaderboard(final @NonNull String leaderboardId,
final int limit,
final int offset,
final boolean withScoretags) {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("leaderboard")
.appendPath(leaderboardId)
.appendQueryParameter("limit",
Integer.toString(limit))
.appendQueryParameter("offset",
Integer.toString(offset))
.appendQueryParameter("with_scoretags",
Boolean.toString(withScoretags))
.build(),
apiKey,
token);
return RequestSender.send(request, LeaderboardAndRank.class);
}
/**
* Get a list of all matches the gamer is part of.
*
* @return A MatchList entity containing all matches relevant to the gamer.
*/
public MatchList matchList() {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("match")
.build(),
apiKey,
token);
return RequestSender.send(request, MatchList.class);
}
/**
* Get status and metadata for a single match identified by its string ID.
*
* @param matchId The String match identifier to retrieve data for.
* @return The corresponding Match entity.
*/
public Match matchGet(final @NonNull String matchId) {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("match")
.appendPath(matchId)
.build(),
apiKey,
token);
return RequestSender.send(request, Match.class);
}
/**
* Request a new match to be created by the GameUp service, with the total
* number of gamers indicated; this player count includes the gamer making
* the request.
*
* If there aren't enough waiting gamers to populate the match with, the
* gamer will be added to the match queue instead, and the method will
* return null.
*
* @param players The total number of gamers to populate the new match with.
* @return The newly created Match entity, or null if the gamer was queued.
*/
@Nullable
public Match matchCreate(final int players) {
final Request request = RequestFactory.post(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("match")
.build(),
apiKey,
token,
GsonFactory.get().toJson(new MatchPlayers(players)));
return RequestSender.send(request, Match.class);
}
/**
* Leave an existing match. Leaving is allowed only when it is NOT the
* gamer's turn.
*
* @param matchId The match ID to leave.
*/
public void matchLeave(final @NonNull String matchId) {
matchAction(matchId, MatchAction.Type.LEAVE);
}
/**
* End an existing match. Ending is allowed only when it is the gamer's
* turn. Ending closes the match, no more data submissions will be allowed.
*
* @param matchId The match ID to end.
*/
public void matchEnd(final @NonNull String matchId) {
matchAction(matchId, MatchAction.Type.END);
}
private void matchAction(final @NonNull String matchId,
final @NonNull MatchAction.Type action) {
final Request request = RequestFactory.post(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("match")
.appendPath(matchId)
.build(),
apiKey,
token,
GsonFactory.get().toJson(new MatchAction(action)));
RequestSender.send(request);
}
/**
* Get all turns for the specified match.
*
* @param matchId The match ID to retrieve turns for.
* @return A TurnList containing all existing turns for the specified match.
*/
public TurnList matchGetTurns(final @NonNull String matchId) {
return matchGetTurns(matchId, 0);
}
/**
* For the specified match, get turns newer than the turn number specified.
*
* For example if lastTurn is 4, the response will contain turns 5+.
*
* @param matchId The match ID to retrieve turns for.
* @param lastTurn The lower threshold for turn numbers.
* @return A TurnList containing only the specified turns for the selected
* match.
*/
public TurnList matchGetTurns(final @NonNull String matchId,
final int lastTurn) {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("match")
.appendPath(matchId)
.appendPath("turn")
.appendPath(Integer.toString(lastTurn))
.build(),
apiKey,
token);
return RequestSender.send(request, TurnList.class);
}
/**
* Submit a new turn to the specified match.
*
* @param matchId The match ID to submit the turn to.
* @param lastTurn The number of the last turn seen by this client.
* @param nextGamer The nickname of the gamer to select as the next
* turn-taker.
* @param data Arbitrary turn data. Can be a string or serialised object.
*/
public void matchSubmitTurn(final @NonNull String matchId,
final int lastTurn,
final @NonNull String nextGamer,
final @NonNull String data) {
final Request request = RequestFactory.post(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("match")
.appendPath(matchId)
.appendPath("turn")
.build(),
apiKey,
token,
GsonFactory.get().toJson(
new MatchTurn(lastTurn, nextGamer, data)));
RequestSender.send(request);
}
/**
* Maintain the gamer's subscription to push messages. Must be called after
* login, and if possible each time the application resumes from sleep or is
* restarted.
*
* Includes a handler to be called each time a notification is opened.
*
* @param context The parent context calling this operation.
* @param multiplayer Whether the gamer wishes to be subscribed to
* background push notifications about multiplayer data.
* @param segments Custom segments the gamer will receive updates about.
*/
public void push(final @NonNull Context context,
final boolean multiplayer,
final @NonNull List<String> segments) {
final String id = Push.registerForPush(context);
final Request request = RequestFactory.put(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("push")
.build(),
apiKey,
token,
GsonFactory.get().toJson(new PushRegistration(
id, multiplayer, segments)));
RequestSender.send(request);
}
/**
* Verify an individual, one-off product purchase.
*
* @param purchase_token The token returned in the original product purchase
* response from Google.
* @param productId The ID of the product that was purchased.
* @return A PurchaseVerification entity containing details about the
* purchase status and recommended actions.
*/
public PurchaseVerification purchaseVerifyProduct(
final @NonNull String purchase_token,
final @NonNull String productId) {
return purchaseVerify(purchase_token, productId,
PurchaseVerify.Type.PRODUCT);
}
/**
* Verify a subscription purchase, may or may not be auto-renewable.
*
* @param purchase_token The token returned in the original subscription
* purchase response from Google.
* @param subscriptionId The ID of the subscription that was purchased.
* @return A PurchaseVerification entity containing details about the
* purchase status and recommended actions.
*/
public PurchaseVerification purchaseVerifySubscription(
final @NonNull String purchase_token,
final @NonNull String subscriptionId) {
return purchaseVerify(purchase_token, subscriptionId,
PurchaseVerify.Type.SUBSCRIPTION);
}
private PurchaseVerification purchaseVerify(
final @NonNull String purchase_token,
final @NonNull String productId,
final @NonNull PurchaseVerify.Type type) {
final Request request = RequestFactory.post(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("purchase")
.appendPath("verify")
.appendPath("google")
.build(),
apiKey,
token,
GsonFactory.get().toJson(new PurchaseVerify(
purchase_token, productId, type)));
return RequestSender.send(request, PurchaseVerification.class);
}
/**
* Execute the given script, within the scope of the current gamer session.
*
* Ignore the result, useful when expected return is HTTP 204 No Body.
* Send no input to the script.
*
* @param scriptId The identifier of the script to run.
*/
public void script(final @NonNull String scriptId) {
GameUp.scriptNoReturn(scriptId, null, token);
}
/**
* Execute the given script, within the scope of the current gamer session.
*
* Ignore the result, useful when expected return is HTTP 204 No Body.
* Send `data` as input to the script.
*
* @param scriptId The identifier of the script to run.
* @param data The data to send to the script as input.
*/
public void script(final @NonNull String scriptId,
final @NonNull Object data) {
GameUp.scriptNoReturn(scriptId, data, token);
}
/**
* Execute the given script, within the scope of the current gamer session.
*
* Expect a result of the given `type`.
* Send no input to the script.
*
* @param scriptId The identifier of the script to run.
* @param type The class type to deserialize the response to.
* @return An instance of the expected type.
*/
public <T> T script(final @NonNull String scriptId,
final @NonNull Class<T> type) {
return GameUp.scriptWithReturn(scriptId, type, null, token);
}
/**
* Execute the given script, within the scope of the current gamer session.
*
* Expect a result of the given `type`.
* Send `data` as input to the script.
*
* @param scriptId The identifier of the script to run.
* @param type The class type to deserialize the response to.
* @param data The data to send to the script as input.
* @return An instance of the expected type.
*/
public <T> T script(final @NonNull String scriptId,
final @NonNull Class<T> type,
final @NonNull Object data) {
return GameUp.scriptWithReturn(scriptId, type, data, token);
}
/**
* Get all available messages, without their bodies.
*
* @return A corresponding MessageList instance.
*/
public MessageList messageList() {
return messageList(0, false);
}
/**
* Get all messages created after the UTC timestamp specified, without their
* message bodies.
*
* @param since A UTC timestamp to use as a message filter, only messages
* with a `createdAt` value greater than this will be returned.
* @return A corresponding MessageList instance.
*/
public MessageList messageList(final long since) {
return messageList(since, false);
}
/**
* Get all messages created after the UTC timestamp specified, with or
* without their message bodies based on the `withBody` flag.
*
* @param since A UTC timestamp to use as a message filter, only messages
* with a `createdAt` value greater than this will be returned.
* @param withBody true if message bodies should be returned,
* false otherwise.
* @return A corresponding MessageList instance.
*/
public MessageList messageList(final long since,
final boolean withBody) {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("message")
.appendQueryParameter("since", Long.toString(since))
.appendQueryParameter("with_body",
Boolean.toString(withBody))
.build(),
apiKey,
token);
return RequestSender.send(request, MessageList.class);
}
/**
* Mark a message as read, and return its metadata, including its body.
*
* @param messageId The identifier of the message to mark as read.
* @return A corresponding Message instance.
*/
public Message messageRead(final @NonNull String messageId) {
return messageRead(messageId, true);
}
/**
* Mark a message as read, and return its metadata, optionally including its
* body.
*
* @param messageId The identifier of the message to mark as read.
* @param withBody true if the message body should be included,
* false otherwise.
* @return A corresponding Message instance.
*/
public Message messageRead(final @NonNull String messageId,
final boolean withBody) {
final Request request = RequestFactory.get(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("message")
.appendPath(messageId)
.appendQueryParameter("with_body",
Boolean.toString(withBody))
.build(),
apiKey,
token);
return RequestSender.send(request, Message.class);
}
/**
* Delete the specified message.
*
* @param messageId The identifier of the message to delete.
*/
public void messageDelete(final @NonNull String messageId) {
final Request request = RequestFactory.delete(
new Uri.Builder().scheme(GameUp.SCHEME)
.encodedAuthority(GameUp.API_SERVER)
.appendPath("v0")
.appendPath("gamer")
.appendPath("message")
.appendPath(messageId)
.build(),
apiKey,
token);
RequestSender.send(request);
}
}