Skip to content

Commit

Permalink
event filtering for scheduled games #136
Browse files Browse the repository at this point in the history
  • Loading branch information
isuru89 committed Jan 1, 2024
1 parent b1683bf commit 3ca87ea
Show file tree
Hide file tree
Showing 30 changed files with 717 additions and 70 deletions.
3 changes: 3 additions & 0 deletions core/src/main/java/io/github/oasis/core/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public class Game implements Serializable {
@EqualsAndHashCode.Include private String logoRef;
@EqualsAndHashCode.Include private int version;

private Long startTime;
private Long endTime;

private long createdAt;
private long updatedAt;
@EqualsAndHashCode.Include private boolean active;
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/io/github/oasis/core/ID.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public final class ID {

public static final String EVENT_API_CACHE_USERS_KEY = "oasis.eventapi.users";
public static final String EVENT_API_CACHE_SOURCES_KEY = "oasis.eventapi.sources";
public static final String EVENT_API_CACHE_GAMES_KEY = "oasis.eventapi.games";

public static final String ENGINE_STATUS_CHANNEL = "game.status.channel";
public static final String GAME_ENGINES = "oasis.engines.games";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,22 @@

package io.github.oasis.services.events.client;

import io.github.oasis.core.Game;
import io.github.oasis.core.exception.OasisRuntimeException;
import io.github.oasis.core.model.PlayerWithTeams;
import io.github.oasis.core.model.TeamObject;
import io.github.oasis.core.utils.Texts;
import io.github.oasis.core.utils.Utils;
import io.github.oasis.services.events.db.DataService;
import io.github.oasis.services.events.model.EventSource;
import io.github.oasis.services.events.model.GameInfo;
import io.github.oasis.services.events.model.UserInfo;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -52,6 +54,8 @@
import static io.github.oasis.services.events.client.AdminConstants.STATUS_NOT_FOUND;
import static io.github.oasis.services.events.client.AdminConstants.STATUS_SUCCESS;
import static io.github.oasis.services.events.client.AdminConstants.TRUE;
import static io.vertx.core.Future.failedFuture;
import static io.vertx.core.Future.succeededFuture;

/**
* @author Isuru Weerarathna
Expand All @@ -66,6 +70,7 @@ public class AdminApiClient implements DataService {

private final String getPlayerInfoUrl;
private final String getEventSourceInfoUrl;
private final String getGameInfoUrl;

private final String apiKey;
private final String secretKey;
Expand All @@ -79,6 +84,8 @@ public AdminApiClient(WebClient webClient, JsonObject configs) {

getPlayerInfoUrl = baseUrl + adminApiConf.getString("playerGet");
getEventSourceInfoUrl = baseUrl + adminApiConf.getString("eventSourceGet");
getGameInfoUrl = baseUrl + adminApiConf.getString("gameGet", "/games");

apiKey = adminApiConf.getString("apiKey");
secretKey = adminApiConf.getString("secretKey");
}
Expand All @@ -95,11 +102,11 @@ public DataService readUserInfo(String email, Handler<AsyncResult<UserInfo>> res
.onSuccess(res -> {
if (res.statusCode() == STATUS_NOT_FOUND) {
// no user exists
resultHandler.handle(Future.failedFuture("No user exists by given email " + email));
resultHandler.handle(failedFuture("No user exists by given email " + email));
return;
} else if (res.statusCode() != STATUS_SUCCESS) {
// service down
resultHandler.handle(Future.failedFuture("Unable to connect to admin api!"));
resultHandler.handle(failedFuture("Unable to connect to admin api!"));
return;
}

Expand All @@ -119,9 +126,9 @@ public DataService readUserInfo(String email, Handler<AsyncResult<UserInfo>> res
}

UserInfo userInfo = UserInfo.create(email, jsonObject);
resultHandler.handle(Future.succeededFuture(userInfo));
resultHandler.handle(succeededFuture(userInfo));

}).onFailure(err -> resultHandler.handle(Future.failedFuture(err)));
}).onFailure(err -> resultHandler.handle(failedFuture(err)));
return this;
}

Expand All @@ -137,11 +144,11 @@ public DataService readSourceInfo(String token, Handler<AsyncResult<EventSource>
.onSuccess(res -> {
if (res.statusCode() == STATUS_NOT_FOUND) {
// no user exists
resultHandler.handle(Future.failedFuture("No event source exists by given token " + token));
resultHandler.handle(failedFuture("No event source exists by given token " + token));
return;
} else if (res.statusCode() != STATUS_SUCCESS) {
// service down
resultHandler.handle(Future.failedFuture("Unable to connect to admin api!"));
resultHandler.handle(failedFuture("Unable to connect to admin api!"));
return;
}

Expand All @@ -153,11 +160,40 @@ public DataService readSourceInfo(String token, Handler<AsyncResult<EventSource>
if (eventSource.getSecrets() != null && Texts.isNotEmpty(eventSource.getSecrets().getPublicKey())) {
jsonObject.put(EventSource.KEY, eventSource.getSecrets().getPublicKey());
EventSource info = EventSource.create(token, jsonObject);
resultHandler.handle(Future.succeededFuture(info));
resultHandler.handle(succeededFuture(info));
} else {
resultHandler.handle(Future.failedFuture(new OasisRuntimeException("The public key not received for source " + token)));
resultHandler.handle(failedFuture(new OasisRuntimeException("The public key not received for source " + token)));
}
}).onFailure(err -> resultHandler.handle(Future.failedFuture(err)));
}).onFailure(err -> resultHandler.handle(failedFuture(err)));
return this;
}

@Override
public DataService readGameInfo(int gameId, Handler<AsyncResult<GameInfo>> resultHandler) {
webClient.getAbs(getGameInfoUrl + "/" + gameId)
.putHeader(HEADER_APP_ID, apiKey)
.putHeader(HEADER_APP_KEY, secretKey)
.putHeader(HEADER_ACCEPT, MEDIA_TYPE_JSON)
.send()
.onSuccess(res -> {
if (res.statusCode() == STATUS_NOT_FOUND) {
// no user exists
resultHandler.handle(failedFuture("No game exists by given game id " + gameId));
return;
} else if (res.statusCode() != STATUS_SUCCESS) {
// service down
resultHandler.handle(failedFuture("Unable to connect to admin api to get game info!"));
return;
}

var game = res.bodyAsJson(Game.class);
JsonObject jsonObject = new JsonObject()
.put(GameInfo.ID, game.getId())
.put(GameInfo.START_TIME, ObjectUtils.firstNonNull(game.getStartTime(), game.getCreatedAt()))
.put(GameInfo.END_TIME, ObjectUtils.firstNonNull(game.getEndTime(), Long.MAX_VALUE - 1));
GameInfo gameInfo = GameInfo.create(game.getId(), jsonObject);
resultHandler.handle(succeededFuture(gameInfo));
}).onFailure(err -> resultHandler.handle(failedFuture(err)));
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@
import io.github.oasis.services.events.db.DataService;
import io.github.oasis.services.events.db.RedisService;
import io.github.oasis.services.events.model.EventSource;
import io.github.oasis.services.events.model.GameInfo;
import io.github.oasis.services.events.model.UserInfo;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static io.vertx.core.Future.failedFuture;
import static io.vertx.core.Future.succeededFuture;

/**
* @author Isuru Weerarathna
*/
Expand All @@ -56,7 +59,7 @@ public DataService readUserInfo(String email, Handler<AsyncResult<UserInfo>> res
UserInfo user = res.result();
if (user != null) {
// cache hit
resultHandler.handle(Future.succeededFuture(user));
resultHandler.handle(succeededFuture(user));
return;
}

Expand All @@ -66,7 +69,7 @@ public DataService readUserInfo(String email, Handler<AsyncResult<UserInfo>> res
persistBackToCache(email, promise, resultHandler);

} else {
resultHandler.handle(Future.failedFuture(res.cause()));
resultHandler.handle(failedFuture(res.cause()));
}
});
return this;
Expand All @@ -83,10 +86,31 @@ public DataService readSourceInfo(String sourceToken, Handler<AsyncResult<EventS
loadEventSourceFromApi(sourceToken, apiPromise);
persistEventSourceBackToCache(sourceToken, apiPromise, resultHandler);
} else {
resultHandler.handle(Future.succeededFuture(resultInCache));
resultHandler.handle(succeededFuture(resultInCache));
}
} else {
resultHandler.handle(failedFuture(res.cause()));
}
});
return this;
}

@Override
public DataService readGameInfo(int gameId, Handler<AsyncResult<GameInfo>> resultHandler) {
cacheService.readGameInfo(gameId, res -> {
if (res.succeeded()) {
GameInfo resultInCache = res.result();
if (resultInCache == null) {
LOG.debug("Game by id '{}' not found in cache!", gameId);
Promise<GameInfo> apiPromise = Promise.promise();
loadGameInfoFromApi(gameId, apiPromise);
persistGameInfoBackToCache(gameId, apiPromise, resultHandler);
} else {
resultHandler.handle(succeededFuture(resultInCache));
}
} else {
resultHandler.handle(Future.failedFuture(res.cause()));
LOG.error("Failed to load from cache!", res.cause());
resultHandler.handle(failedFuture(res.cause()));
}
});
return this;
Expand All @@ -95,13 +119,26 @@ public DataService readSourceInfo(String sourceToken, Handler<AsyncResult<EventS
private void persistEventSourceBackToCache(String sourceToken, Promise<EventSource> apiPromise, Handler<AsyncResult<EventSource>> handler) {
apiPromise.future().onSuccess(eventSource -> cacheService.persistSourceInfo(sourceToken, eventSource, res -> {
if (res.succeeded()) {
handler.handle(Future.succeededFuture(eventSource));
handler.handle(succeededFuture(eventSource));
} else {
handler.handle(Future.failedFuture(res.cause()));
handler.handle(failedFuture(res.cause()));
}
})).onFailure(err -> {
LOG.error("Unable to persist source details to the cache!", err);
handler.handle(Future.failedFuture(err));
handler.handle(failedFuture(err));
});
}

private void persistGameInfoBackToCache(int gameId, Promise<GameInfo> apiPromise, Handler<AsyncResult<GameInfo>> handler) {
apiPromise.future().onSuccess(gameInfo -> cacheService.persistGameInfo(gameId, gameInfo, res -> {
if (res.succeeded()) {
handler.handle(succeededFuture(gameInfo));
} else {
handler.handle(failedFuture(res.cause()));
}
})).onFailure(err -> {
LOG.error("Unable to fetch game details from api server!", err);
handler.handle(failedFuture(err));
});
}

Expand All @@ -115,16 +152,26 @@ private void loadEventSourceFromApi(String sourceId, Promise<EventSource> promis
});
}

private void loadGameInfoFromApi(int gameId, Promise<GameInfo> promise) {
apiClient.readGameInfo(gameId, res -> {
if (res.succeeded()) {
promise.complete(res.result());
} else {
promise.fail(res.cause());
}
});
}

private void persistBackToCache(String email, Promise<UserInfo> promise, Handler<AsyncResult<UserInfo>> finalHandler) {
promise.future().onSuccess(userInfo -> cacheService.persistUserInfo(email, userInfo, resultHandler -> {
if (resultHandler.succeeded()) {
finalHandler.handle(Future.succeededFuture(userInfo));
finalHandler.handle(succeededFuture(userInfo));
} else {
finalHandler.handle(Future.failedFuture(resultHandler.cause()));
finalHandler.handle(failedFuture(resultHandler.cause()));
}
})).onFailure(err -> {
LOG.error("Unable to persist user details into the cache!", err);
finalHandler.handle(Future.failedFuture(err));
finalHandler.handle(failedFuture(err));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package io.github.oasis.services.events.db;

import io.github.oasis.services.events.model.EventSource;
import io.github.oasis.services.events.model.GameInfo;
import io.github.oasis.services.events.model.UserInfo;
import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.ProxyGen;
Expand All @@ -44,4 +45,7 @@ static DataService createProxy(Vertx vertx, String address) {

@Fluent
DataService readSourceInfo(String sourceId, Handler<AsyncResult<EventSource>> resultHandler);

@Fluent
DataService readGameInfo(int gameId, Handler<AsyncResult<GameInfo>> resultHandler);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package io.github.oasis.services.events.db;

import io.github.oasis.services.events.model.EventSource;
import io.github.oasis.services.events.model.GameInfo;
import io.github.oasis.services.events.model.UserInfo;
import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.ProxyGen;
Expand Down Expand Up @@ -54,4 +55,10 @@ static RedisService createProxy(Vertx vertx, String address) {

@Fluent
RedisService deleteKey(String key, Handler<AsyncResult<Boolean>> resultHandler);

@Fluent
RedisService readGameInfo(int gameId, Handler<AsyncResult<GameInfo>> resultHandler);

@Fluent
RedisService persistGameInfo(int gameId, GameInfo gameInfo, Handler<AsyncResult<GameInfo>> resultHandler);
}
Loading

0 comments on commit 3ca87ea

Please sign in to comment.