Skip to content

Commit

Permalink
releaseb fix blitz bracket formation
Browse files Browse the repository at this point in the history
  • Loading branch information
Sammers21 committed Sep 11, 2024
1 parent a938095 commit 1bccbee
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 113 deletions.
164 changes: 61 additions & 103 deletions src/io/github/sammers/pla/blizzard/BlizzardAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,84 +99,61 @@ public Maybe<WowAPICharacter> character(String region, String realm, String name
String absoluteURI = "https://" + realRegion + ".api.blizzard.com/profile/wow/character/" + realmSearch + "/" + nameSearch;
return token().flatMapMaybe(blizzardAuthToken -> {
long tick = System.nanoTime();
return maybeResponse(realNamespace, absoluteURI)
.flatMap(json -> {
Maybe<WowAPICharacter> res;
if (json.getInteger("code") != null && json.getInteger("code") == 404) {
log.debug("Character not found: " + name + " on " + realm + " in " + realRegion);
res = Maybe.empty();
} else {
log.debug("Found Character: " + name + " on " + realm + " in " + realRegion);
res = maybeResponse(realNamespace, json.getJsonObject("pvp_summary").getString("href"))
.flatMap(pvp -> {
JsonArray bracketFromJson = pvp.getJsonArray("brackets");
if (bracketFromJson == null) {
bracketFromJson = new JsonArray();
}
Single<List<JsonObject>> bracketList = Maybe.concatEager(
bracketFromJson.stream()
.map(o -> ((JsonObject) o).getString("href"))
.map(ref -> maybeResponse(realNamespace, ref)
).toList()
).toList();
Maybe<JsonObject> achievementsRx = maybeResponse(realNamespace, absoluteURI + "/achievements");
Maybe<JsonObject> mediaRx = maybeResponse(realNamespace, absoluteURI + "/character-media").onErrorReturnItem(new JsonObject());
Maybe<JsonObject> petsRx = maybeResponse(realNamespace, absoluteURI + "/collections/pets");
Maybe<JsonObject> specsRx = maybeResponse(realNamespace, absoluteURI + "/specializations");
return Single.zip(
bracketList,
Maybe.concatEager(List.of(achievementsRx, mediaRx, petsRx, specsRx)).toList(),
Pair::new).flatMapMaybe(pair -> {
List<JsonObject> brackets = pair.getValue0();
List<JsonObject> otherStuff = pair.getValue1();
Optional<WowAPICharacter> prev = Optional.ofNullable(characterCache.getByFullName(Character.fullNameByRealmAndName(name, realm)));
Optional<Cutoffs> ctfs = Optional.ofNullable(cutoffs.get(realRegion));
WowAPICharacter parsed = WowAPICharacter.parse(characterCache, prev, refs, ctfs, json, pvp,
brackets, otherStuff.get(0), otherStuff.get(1), otherStuff.get(3), otherStuff.get(2), realRegion);
return Maybe.just(parsed);
}).doOnSuccess(wowAPICharacter -> {
long elapsed = System.nanoTime() - tick;
log.debug("Parsed character {} in {} ms", wowAPICharacter.fullName(), elapsed / 1000000);
});
})
.doOnError(e -> log.error("Error parsing character: " + name + " on " + realm + " in " + realRegion, e))
.onErrorResumeNext(Maybe.empty());
}
return res;
});
return maybeResponse(realNamespace, absoluteURI).flatMap(json -> {
Maybe<WowAPICharacter> res;
if (json.getInteger("code") != null && json.getInteger("code") == 404) {
log.debug("Character not found: " + name + " on " + realm + " in " + realRegion);
res = Maybe.empty();
} else {
log.debug("Found Character: " + name + " on " + realm + " in " + realRegion);
res = maybeResponse(realNamespace, json.getJsonObject("pvp_summary").getString("href")).flatMap(pvp -> {
JsonArray bracketFromJson = pvp.getJsonArray("brackets");
if (bracketFromJson == null) {
bracketFromJson = new JsonArray();
}
Single<List<JsonObject>> bracketList = Maybe.concatEager(bracketFromJson.stream().map(o -> ((JsonObject) o).getString("href")).map(ref -> maybeResponse(realNamespace, ref)).toList()).toList();
Maybe<JsonObject> achievementsRx = maybeResponse(realNamespace, absoluteURI + "/achievements");
Maybe<JsonObject> mediaRx = maybeResponse(realNamespace, absoluteURI + "/character-media").onErrorReturnItem(new JsonObject());
Maybe<JsonObject> petsRx = maybeResponse(realNamespace, absoluteURI + "/collections/pets");
Maybe<JsonObject> specsRx = maybeResponse(realNamespace, absoluteURI + "/specializations");
return Single.zip(bracketList, Maybe.concatEager(List.of(achievementsRx, mediaRx, petsRx, specsRx)).toList(), Pair::new).flatMapMaybe(pair -> {
List<JsonObject> brackets = pair.getValue0();
List<JsonObject> otherStuff = pair.getValue1();
Optional<WowAPICharacter> prev = Optional.ofNullable(characterCache.getByFullName(Character.fullNameByRealmAndName(name, realm)));
Optional<Cutoffs> ctfs = Optional.ofNullable(cutoffs.get(realRegion));
WowAPICharacter parsed = WowAPICharacter.parse(characterCache, prev, refs, ctfs, json, pvp,
brackets, otherStuff.get(0), otherStuff.get(1), otherStuff.get(3), otherStuff.get(2), realRegion);
return Maybe.just(parsed);
}).doOnSuccess(wowAPICharacter -> {
long elapsed = System.nanoTime() - tick;
log.debug("Parsed character {} in {} ms", wowAPICharacter.fullName(), elapsed / 1000000);
});
}).doOnError(e -> log.error("Error parsing character: " + name + " on " + realm + " in " + realRegion, e)).onErrorResumeNext(Maybe.empty());
}
return res;
});
});
}

Maybe<JsonObject> maybeResponse(String namespace, String url) {
return token().flatMapMaybe(blizzardAuthToken ->
rpsToken().andThen(
Maybe.defer(() -> {
log.debug("Getting " + url);
return webClient.getAbs(url)
.addQueryParam("namespace", namespace)
.addQueryParam("locale", LOCALE)
.bearerTokenAuthentication(blizzardAuthToken.accessToken())
.timeout(TimeUnit.MINUTES.toMillis(10))
.rxSend()
.onErrorResumeNext(er -> {
log.error("Error getting " + url, er);
return Single.error(er);
})
.flatMapMaybe(resp -> {
log.debug("Got response to" + url + " " + resp.statusCode());
if (resp.statusCode() == 200) {
return Maybe.just(resp.bodyAsJsonObject());
} else if (resp.statusCode() == 429 || resp.statusCode() / 100 == 5) {
int code = resp.statusCode();
log.info(code + " Retrying " + url + " " + resp.statusMessage());
return rpsToken().andThen(rpsToken()).andThen(maybeResponse(namespace, url));
} else {
return Maybe.error(new IllegalStateException("Error getting " + url + " " + resp.statusCode() + " " + resp.statusMessage() + " " + resp.bodyAsString()));
}
});
})
)
);
return token().flatMapMaybe(blizzardAuthToken -> rpsToken().andThen(Maybe.defer(() -> {
log.debug("Getting " + url);
return webClient.getAbs(url).addQueryParam("namespace", namespace).addQueryParam("locale", LOCALE).bearerTokenAuthentication(blizzardAuthToken.accessToken()).timeout(TimeUnit.MINUTES.toMillis(10)).rxSend().onErrorResumeNext(er -> {
log.error("Error getting " + url, er);
return Single.error(er);
}).flatMapMaybe(resp -> {
log.debug("Got response to" + url + " " + resp.statusCode());
if (resp.statusCode() == 200) {
return Maybe.just(resp.bodyAsJsonObject());
} else if (resp.statusCode() == 429 || resp.statusCode() / 100 == 5) {
int code = resp.statusCode();
log.info(code + " Retrying " + url + " " + resp.statusMessage());
return rpsToken().andThen(rpsToken()).andThen(maybeResponse(namespace, url));
} else {
return Maybe.error(new IllegalStateException("Error getting " + url + " " + resp.statusCode() + " " + resp.statusMessage() + " " + resp.bodyAsString()));
}
});
})));
}

public static String realRegion(String region) {
Expand Down Expand Up @@ -223,23 +200,13 @@ public Maybe<PvpLeaderBoard> pvpLeaderboard(String region, Integer pvpSeasonId,
realPvpBracket = pvpBracket;
}
String url = "https://" + realRegion + ".api.blizzard.com/data/wow/pvp-season/" + pvpSeasonId + "/pvp-leaderboard/" + realPvpBracket;
return Maybe.defer(() ->
token().flatMapMaybe(blizzardAuthToken -> maybeResponse(realNamespace, url)).map(PvpLeaderBoard::fromJson)
)
.doOnSubscribe(disposable -> log.info("Getting leaderboard for region={} ssn={} bracket={}", realRegion, pvpSeasonId, realPvpBracket))
.doOnError(er -> log.error("Error fetching Blizzard PVP leaderboard", er))
.onErrorResumeNext(Maybe.empty());
return Maybe.defer(() -> token().flatMapMaybe(blizzardAuthToken -> maybeResponse(realNamespace, url)).map(PvpLeaderBoard::fromJson)).doOnSubscribe(disposable -> log.info("Getting leaderboard for region={} ssn={} bracket={}", realRegion, pvpSeasonId, realPvpBracket)).doOnError(er -> log.error("Error fetching Blizzard PVP leaderboard", er)).onErrorResumeNext(Maybe.empty());
}

private Single<BlizzardAuthToken> authorize() {
MultiMap form = MultiMap.caseInsensitiveMultiMap();
form.set("grant_type", "client_credentials");
return webClient.postAbs(AUTH_URL)
.addQueryParam("grant_type", "client_credentials")
.basicAuthentication(clientId, clientSecret)
.rxSendForm(form)
.map(response -> BlizzardAuthToken.fromJson(response.bodyAsJsonObject()))
.doOnSuccess(token -> log.info("Got token: {}", token));
return webClient.postAbs(AUTH_URL).addQueryParam("grant_type", "client_credentials").basicAuthentication(clientId, clientSecret).rxSendForm(form).map(response -> BlizzardAuthToken.fromJson(response.bodyAsJsonObject())).doOnSuccess(token -> log.info("Got token: {}", token));
}

public Single<Realms> realms(String region) {
Expand All @@ -248,15 +215,14 @@ public Single<Realms> realms(String region) {
String realRegion = realRegion(region);
String namespace = "dynamic-" + realRegion;
String url = "https://" + realRegion + ".api.blizzard.com/data/wow/connected-realm/index";
return maybeResponse(namespace, url)
.flatMapSingle(index -> {
List<String> hrefs = index.getJsonArray("connected_realms").stream().map(o -> ((JsonObject) o).getString("href")).toList();
List<Maybe<JsonObject>> list = hrefs.stream().map(href -> maybeResponse(namespace, href)).toList();
return Maybe.merge(list).toList().map(responses -> {
log.info("Realms for {} fetched in {}ms", realRegion, System.currentTimeMillis() - tick);
return Realms.fromBlizzardJson(realRegion, index, responses);
});
return maybeResponse(namespace, url).flatMapSingle(index -> {
List<String> hrefs = index.getJsonArray("connected_realms").stream().map(o -> ((JsonObject) o).getString("href")).toList();
List<Maybe<JsonObject>> list = hrefs.stream().map(href -> maybeResponse(namespace, href)).toList();
return Maybe.merge(list).toList().map(responses -> {
log.info("Realms for {} fetched in {}ms", realRegion, System.currentTimeMillis() - tick);
return Realms.fromBlizzardJson(realRegion, index, responses);
});
});
});
}

Expand All @@ -266,14 +232,6 @@ public Single<Cutoffs> cutoffs(String region) {

public Single<Cutoffs> cutoffs(String region, Integer pvpSsnId) {
String realRegion = realRegion(region);
return token().flatMap(blizzardAuthToken ->
webClient.getAbs("https://" + realRegion + ".api.blizzard.com/data/wow/pvp-season/" + pvpSsnId + "/pvp-reward/index")
.addQueryParam("namespace", "dynamic-" + realRegion)
.addQueryParam("locale", LOCALE)
.bearerTokenAuthentication(blizzardAuthToken.accessToken())
.rxSend()
.map(HttpResponse::bodyAsJsonObject)
.map(res -> Cutoffs.fromBlizzardJson(realRegion, res))
);
return token().flatMap(blizzardAuthToken -> webClient.getAbs("https://" + realRegion + ".api.blizzard.com/data/wow/pvp-season/" + pvpSsnId + "/pvp-reward/index").addQueryParam("namespace", "dynamic-" + realRegion).addQueryParam("locale", LOCALE).bearerTokenAuthentication(blizzardAuthToken.accessToken()).rxSend().map(HttpResponse::bodyAsJsonObject).map(res -> Cutoffs.fromBlizzardJson(realRegion, res)));
}
}
5 changes: 4 additions & 1 deletion src/io/github/sammers/pla/blizzard/PvpBracket.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ public static PvpBracket parse(JsonObject wowApiBracket, Optional<PvpBracket> pr
String type = wowApiBracket.getJsonObject("bracket").getString("type");
Long rating = wowApiBracket.getLong("rating");
Optional<JsonObject> stats;
if (type.equals("SHUFFLE")) {
if (type.equals("SHUFFLE") || type.equals("BLITZ")) {
type = type + "-" + wowApiBracket.getJsonObject("specialization").getString("name");
stats = Optional.ofNullable(wowApiBracket.getJsonObject("season_round_statistics"));
if (stats.isEmpty()) {
stats = Optional.ofNullable(wowApiBracket.getJsonObject("season_match_statistics"));
}
} else {
stats = Optional.ofNullable(wowApiBracket.getJsonObject("season_match_statistics"));
}
Expand Down
4 changes: 2 additions & 2 deletions src/io/github/sammers/pla/blizzard/WowAPICharacter.java
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public static WowAPICharacter parse(
return foundChars.get(0).pos();
} else {
Long finalPos = -1L;
if (btype.equals("SHUFFLE")) {
if (btype.equals("SHUFFLE") || btype.equals("BLITZ")) {
String spec = wowApiBracket.getJsonObject("specialization").getString("name");
finalPos = foundChars.stream().filter(c -> c.fullSpec().contains(spec)).findFirst().map(Character::pos).orElse(-1L);
}
Expand All @@ -207,7 +207,7 @@ public static WowAPICharacter parse(
}).orElse(-1L);
Long cutoffByBracketType;
Optional<PvpBracket> prevBracket;
if (btype.equals("SHUFFLE")) {
if (btype.equals("SHUFFLE") || btype.equals("BLITZ")) {
String spec = wowApiBracket.getJsonObject("specialization").getString("name");
Long id = wowApiBracket.getJsonObject("specialization").getLong("id");
String specCode = Cutoffs.specCodeNameById(spec, id);
Expand Down
7 changes: 0 additions & 7 deletions src/io/github/sammers/pla/logic/CharUpdater.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,22 @@

import io.github.sammers.pla.Main;
import io.github.sammers.pla.blizzard.BlizzardAPI;
import io.github.sammers.pla.blizzard.PvpBracket;
import io.github.sammers.pla.blizzard.WowAPICharacter;
import io.github.sammers.pla.db.Character;
import io.github.sammers.pla.db.DB;
import io.github.sammers.pla.db.Snapshot;
import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.Single;

import org.javatuples.Pair;
import org.javatuples.Triplet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;

import static io.github.sammers.pla.logic.Conts.*;

Expand Down

0 comments on commit 1bccbee

Please sign in to comment.