package com.merakianalytics.orianna.datapipeline.kernel.data; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.Days; import org.joda.time.Duration; import org.joda.time.Weeks; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; import com.merakianalytics.datapipelines.PipelineContext; import com.merakianalytics.datapipelines.iterators.CloseableIterator; import com.merakianalytics.datapipelines.iterators.CloseableIterators; import com.merakianalytics.datapipelines.sources.Get; import com.merakianalytics.datapipelines.sources.GetMany; import com.merakianalytics.orianna.datapipeline.common.HTTPClient; import com.merakianalytics.orianna.datapipeline.common.Utilities; import com.merakianalytics.orianna.datapipeline.kernel.data.Kernel.Configuration; import com.merakianalytics.orianna.types.common.Platform; import com.merakianalytics.orianna.types.data.match.Match; import com.merakianalytics.orianna.types.data.match.MatchList; import com.merakianalytics.orianna.types.data.match.Timeline; import com.merakianalytics.orianna.types.data.match.TournamentMatches; public class MatchAPI extends KernelService { private static final Duration HISTORY_LENGTH = Days.days(730).toStandardDuration(); // 2 Years private static final int MAX_MATCH_INDEX_DIFFERENCE = 100; private static final long ONE_WEEK_IN_MILLISECONDS = Weeks.ONE.toStandardDuration().getMillis(); public MatchAPI(final Configuration config, final HTTPClient client) { super(config, client); } @SuppressWarnings("unchecked") @GetMany(Match.class) public CloseableIterator<Match> getManyMatch(final Map<String, Object> query, final PipelineContext context) { final Platform platform = (Platform)query.get("platform"); final Iterable<Number> matchIds = (Iterable<Number>)query.get("matchIds"); final String tournamentCode = (String)query.get("tournamentCode"); Utilities.checkNotNull(platform, "platform", matchIds, "matchIds"); final Iterator<Number> iterator = matchIds.iterator(); return CloseableIterators.from(new Iterator<Match>() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public Match next() { final Number matchId = iterator.next(); String endpoint; Match data; if(tournamentCode == null) { endpoint = "lol/match/v4/matches/" + matchId; data = get(Match.class, endpoint, ImmutableMap.of("platform", platform.getTag())); } else { endpoint = "lol/match/v4/matches/" + matchId + "/by-tournament-code/" + tournamentCode; data = get(Match.class, endpoint, ImmutableMap.of("platform", platform.getTag())); } if(data == null) { return null; } return data; } @Override public void remove() { throw new UnsupportedOperationException(); } }); } @SuppressWarnings("unchecked") @GetMany(MatchList.class) public CloseableIterator<MatchList> getManyMatchList(final Map<String, Object> query, final PipelineContext context) { final Platform platform = (Platform)query.get("platform"); final Iterable<String> accountIds = (Iterable<String>)query.get("accountIds"); final Set<Integer> queues = query.get("queues") == null ? Collections.<Integer> emptySet() : (Set<Integer>)query.get("queues"); final Set<Integer> seasons = query.get("seasons") == null ? Collections.<Integer> emptySet() : (Set<Integer>)query.get("seasons"); final Set<Integer> champions = query.get("champions") == null ? Collections.<Integer> emptySet() : (Set<Integer>)query.get("champions"); Number beginTime = (Number)query.get("beginTime"); Number endTime = (Number)query.get("endTime"); Number beginIndex = (Number)query.get("beginIndex"); Number endIndex = (Number)query.get("endIndex"); Utilities.checkNotNull(platform, "platform", accountIds, "accountIds"); final DateTime now = DateTime.now(DateTimeZone.UTC); final DateTime historyStart = now.minusYears(3); // Time Handling if(beginTime != null && beginTime.longValue() < historyStart.getMillis()) { beginTime = historyStart.getMillis(); } if(endTime != null && endTime.longValue() > now.getMillis()) { endTime = now.getMillis(); } if(endTime != null && (beginTime == null || endTime.longValue() - beginTime.longValue() > ONE_WEEK_IN_MILLISECONDS)) { beginTime = Math.max(endTime.longValue() - ONE_WEEK_IN_MILLISECONDS, 0); } // Index Handling if(beginIndex != null && endIndex != null && beginIndex.intValue() + MAX_MATCH_INDEX_DIFFERENCE < endIndex.intValue()) { endIndex = beginIndex.intValue() + MAX_MATCH_INDEX_DIFFERENCE; } if(beginIndex != null && endIndex == null && endTime == null) { endIndex = beginIndex.intValue() + MAX_MATCH_INDEX_DIFFERENCE; } if(endIndex != null && beginIndex == null) { beginIndex = Math.max(endIndex.intValue() - MAX_MATCH_INDEX_DIFFERENCE, 0); } final Multimap<String, String> parameters = HashMultimap.create(); parameters.put("platform", platform.getTag()); if(beginTime != null) { parameters.put("beginTime", beginTime.toString()); } if(endTime != null) { parameters.put("endTime", endTime.toString()); } if(beginIndex != null) { parameters.put("beginIndex", beginIndex.toString()); } if(endIndex != null) { parameters.put("endIndex", endIndex.toString()); } for(final Integer queue : queues) { parameters.put("queue", queue.toString()); } for(final Integer season : seasons) { parameters.put("season", season.toString()); } for(final Integer champion : champions) { parameters.put("champion", champion.toString()); } final Number bTime = beginTime; final Number eTime = endTime; final Number bIndex = beginIndex; final Number eIndex = endIndex; final Iterator<String> iterator = accountIds.iterator(); return CloseableIterators.from(new Iterator<MatchList>() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public MatchList next() { final String accountId = iterator.next(); final String endpoint = "lol/match/v4/matchlists/by-account/" + accountId; final MatchList data = get(MatchList.class, endpoint, parameters); if(data == null) { final MatchList empty = new MatchList(); empty.setPlatform(platform.getTag()); empty.setAccountId(accountId); empty.setQueues(queues); empty.setSeasons(seasons); empty.setChampions(champions); empty.setStartTime(new DateTime(bTime == null ? 0L : bTime.longValue())); empty.setEndTime(new DateTime(eTime == null ? 0L : eTime.longValue())); empty.setStartIndex(bIndex == null ? 0 : bIndex.intValue()); empty.setEndIndex(eIndex == null ? 0 : eIndex.intValue()); empty.setMaxSize(bTime != null && eTime != null ? Integer.MAX_VALUE : MAX_MATCH_INDEX_DIFFERENCE); empty.setMaxTimeRange(Duration.millis(eTime != null ? Long.MAX_VALUE : ONE_WEEK_IN_MILLISECONDS)); empty.setHistoryLength(HISTORY_LENGTH); return empty; } return data; } @Override public void remove() { throw new UnsupportedOperationException(); } }); } @SuppressWarnings("unchecked") @GetMany(Timeline.class) public CloseableIterator<Timeline> getManyTimeline(final Map<String, Object> query, final PipelineContext context) { final Platform platform = (Platform)query.get("platform"); final Iterable<Number> matchIds = (Iterable<Number>)query.get("matchIds"); Utilities.checkNotNull(platform, "platform", matchIds, "matchIds"); final Iterator<Number> iterator = matchIds.iterator(); return CloseableIterators.from(new Iterator<Timeline>() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public Timeline next() { final Number matchId = iterator.next(); final String endpoint = "lol/match/v4/timelines/by-match/" + matchId; final Timeline data = get(Timeline.class, endpoint, ImmutableMap.of("platform", platform.getTag())); if(data == null) { return null; } return data; } @Override public void remove() { throw new UnsupportedOperationException(); } }); } @SuppressWarnings("unchecked") @GetMany(TournamentMatches.class) public CloseableIterator<TournamentMatches> getManyTournamentMatches(final Map<String, Object> query, final PipelineContext context) { final Platform platform = (Platform)query.get("platform"); final Iterable<String> tournamentCodes = (Iterable<String>)query.get("tournamentCodes"); Utilities.checkNotNull(platform, "platform", tournamentCodes, "tournamentCodes"); final Iterator<String> iterator = tournamentCodes.iterator(); return CloseableIterators.from(new Iterator<TournamentMatches>() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public TournamentMatches next() { final String tournamentCode = iterator.next(); final String endpoint = "lol/match/v4/matches/by-tournament-code/" + tournamentCode + "/ids"; final TournamentMatches data = get(TournamentMatches.class, endpoint, ImmutableMap.of("platform", platform.getTag())); if(data == null) { return null; } return data; } @Override public void remove() { throw new UnsupportedOperationException(); } }); } @Get(Match.class) public Match getMatch(final Map<String, Object> query, final PipelineContext context) { final Platform platform = (Platform)query.get("platform"); final Number matchId = (Number)query.get("matchId"); final String tournamentCode = (String)query.get("tournamentCode"); Utilities.checkNotNull(platform, "platform", matchId, "matchId"); String endpoint; Match data; if(tournamentCode == null) { endpoint = "lol/match/v4/matches/" + matchId; data = get(Match.class, endpoint, ImmutableMap.of("platform", platform.getTag())); } else { endpoint = "lol/match/v4/matches/" + matchId + "/by-tournament-code/" + tournamentCode; data = get(Match.class, endpoint, ImmutableMap.of("platform", platform.getTag())); } if(data == null) { return null; } return data; } @SuppressWarnings("unchecked") @Get(MatchList.class) public MatchList getMatchList(final Map<String, Object> query, final PipelineContext context) { final Platform platform = (Platform)query.get("platform"); final String accountId = (String)query.get("accountId"); final Set<Integer> queues = query.get("queues") == null ? Collections.<Integer> emptySet() : (Set<Integer>)query.get("queues"); final Set<Integer> seasons = query.get("seasons") == null ? Collections.<Integer> emptySet() : (Set<Integer>)query.get("seasons"); final Set<Integer> champions = query.get("champions") == null ? Collections.<Integer> emptySet() : (Set<Integer>)query.get("champions"); Number beginTime = (Number)query.get("beginTime"); Number endTime = (Number)query.get("endTime"); Number beginIndex = (Number)query.get("beginIndex"); Number endIndex = (Number)query.get("endIndex"); Utilities.checkNotNull(platform, "platform", accountId, "accountId"); final DateTime now = DateTime.now(DateTimeZone.UTC); final DateTime historyStart = now.minusYears(3); // Time Handling if(beginTime != null && beginTime.longValue() < historyStart.getMillis()) { beginTime = historyStart.getMillis(); } if(endTime != null && endTime.longValue() > now.getMillis()) { endTime = now.getMillis(); } if(endTime != null && (beginTime == null || endTime.longValue() - beginTime.longValue() > ONE_WEEK_IN_MILLISECONDS)) { beginTime = Math.max(endTime.longValue() - ONE_WEEK_IN_MILLISECONDS, 0); } // Index Handling if(beginIndex != null && endIndex != null && beginIndex.intValue() + MAX_MATCH_INDEX_DIFFERENCE < endIndex.intValue()) { endIndex = beginIndex.intValue() + MAX_MATCH_INDEX_DIFFERENCE; } if(beginIndex != null && endIndex == null && endTime == null) { endIndex = beginIndex.intValue() + MAX_MATCH_INDEX_DIFFERENCE; } if(endIndex != null && beginIndex == null) { beginIndex = Math.max(endIndex.intValue() - MAX_MATCH_INDEX_DIFFERENCE, 0); } final String endpoint = "lol/match/v4/matchlists/by-account/" + accountId; final Multimap<String, String> parameters = HashMultimap.create(); parameters.put("platform", platform.getTag()); if(beginTime != null) { parameters.put("beginTime", beginTime.toString()); } if(endTime != null) { parameters.put("endTime", endTime.toString()); } if(beginIndex != null) { parameters.put("beginIndex", beginIndex.toString()); } if(endIndex != null) { parameters.put("endIndex", endIndex.toString()); } for(final Integer queue : queues) { parameters.put("queue", queue.toString()); } for(final Integer season : seasons) { parameters.put("season", season.toString()); } for(final Integer champion : champions) { parameters.put("champion", champion.toString()); } final MatchList data = get(MatchList.class, endpoint, parameters); if(data == null) { final MatchList empty = new MatchList(); empty.setPlatform(platform.getTag()); empty.setAccountId(accountId); empty.setQueues(queues); empty.setSeasons(seasons); empty.setChampions(champions); empty.setStartTime(new DateTime(beginTime == null ? 0L : beginTime.longValue())); empty.setEndTime(new DateTime(endTime == null ? 0L : endTime.longValue())); empty.setStartIndex(beginIndex == null ? 0 : beginIndex.intValue()); empty.setEndIndex(endIndex == null ? 0 : endIndex.intValue()); empty.setMaxSize(beginTime != null && endTime != null ? Integer.MAX_VALUE : MAX_MATCH_INDEX_DIFFERENCE); empty.setMaxTimeRange(Duration.millis(endTime != null ? Long.MAX_VALUE : ONE_WEEK_IN_MILLISECONDS)); empty.setHistoryLength(HISTORY_LENGTH); return empty; } return data; } @Get(Timeline.class) public Timeline getTimeline(final Map<String, Object> query, final PipelineContext context) { final Platform platform = (Platform)query.get("platform"); final Number matchId = (Number)query.get("matchId"); Utilities.checkNotNull(platform, "platform", matchId, "matchId"); final String endpoint = "lol/match/v4/timelines/by-match/" + matchId; final Timeline data = get(Timeline.class, endpoint, ImmutableMap.of("platform", platform.getTag())); if(data == null) { return null; } return data; } @Get(TournamentMatches.class) public TournamentMatches getTournamentMatches(final Map<String, Object> query, final PipelineContext context) { final Platform platform = (Platform)query.get("platform"); final String tournamentCode = (String)query.get("tournamentCode"); Utilities.checkNotNull(platform, "platform", tournamentCode, "tournamentCode"); final String endpoint = "lol/match/v4/matches/by-tournament-code/" + tournamentCode + "/ids"; final TournamentMatches data = get(TournamentMatches.class, endpoint, ImmutableMap.of("platform", platform.getTag())); if(data == null) { return null; } return data; } }