diff --git a/.travis.yml b/.travis.yml index ecb449389..2011a38fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,14 @@ language: java jdk: - oraclejdk8 +branches: + only: + - master + before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ cache: directories: - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ \ No newline at end of file + - $HOME/.gradle/wrapper/ diff --git a/src/main/java/com/pokegoapi/api/PokemonGo.java b/src/main/java/com/pokegoapi/api/PokemonGo.java index a839201d0..4ef858e7e 100644 --- a/src/main/java/com/pokegoapi/api/PokemonGo.java +++ b/src/main/java/com/pokegoapi/api/PokemonGo.java @@ -15,36 +15,13 @@ package com.pokegoapi.api; -import POGOProtos.Data.Player.CurrencyOuterClass; -import POGOProtos.Data.Player.PlayerStatsOuterClass; -import POGOProtos.Data.PlayerDataOuterClass; -import POGOProtos.Enums.PokemonFamilyIdOuterClass.PokemonFamilyId; -import POGOProtos.Enums.PokemonIdOuterClass; -import POGOProtos.Inventory.InventoryItemOuterClass; -import POGOProtos.Inventory.ItemIdOuterClass; import POGOProtos.Networking.Envelopes.RequestEnvelopeOuterClass; -import POGOProtos.Networking.Requests.Messages.GetInventoryMessageOuterClass.GetInventoryMessage; -import POGOProtos.Networking.Requests.Messages.GetPlayerMessageOuterClass.GetPlayerMessage; -import POGOProtos.Networking.Requests.RequestTypeOuterClass.RequestType; -import POGOProtos.Networking.Responses.GetInventoryResponseOuterClass.GetInventoryResponse; -import POGOProtos.Networking.Responses.GetPlayerResponseOuterClass.GetPlayerResponse; -import com.google.protobuf.InvalidProtocolBufferException; -import com.pokegoapi.api.inventory.Bag; -import com.pokegoapi.api.inventory.CandyJar; -import com.pokegoapi.api.inventory.Item; -import com.pokegoapi.api.inventory.PokeBank; +import com.pokegoapi.api.inventory.Inventories; import com.pokegoapi.api.map.Map; -import com.pokegoapi.api.player.ContactSettings; -import com.pokegoapi.api.player.DailyBonus; -import com.pokegoapi.api.player.PlayerAvatar; import com.pokegoapi.api.player.PlayerProfile; -import com.pokegoapi.api.player.Team; -import com.pokegoapi.api.pokemon.Pokemon; -import com.pokegoapi.exceptions.InvalidCurrencyException; import com.pokegoapi.exceptions.LoginFailedException; import com.pokegoapi.exceptions.RemoteServerException; import com.pokegoapi.main.RequestHandler; -import com.pokegoapi.main.ServerRequest; import com.pokegoapi.util.Log; import lombok.Getter; import lombok.Setter; @@ -57,15 +34,12 @@ public class PokemonGo { @Getter RequestHandler requestHandler; @Getter - PokeBank pokebank; - @Getter - Bag bag; - @Getter Map map; @Getter - CandyJar candyjar; private PlayerProfile playerProfile; @Getter + private Inventories inventories; + @Getter @Setter private double latitude; @Getter @@ -75,7 +49,6 @@ public class PokemonGo { @Setter private double altitude; - private long lastInventoryUpdate; /** * Instantiates a new Pokemon go. @@ -83,80 +56,22 @@ public class PokemonGo { * @param auth the auth * @param client the client */ - public PokemonGo(RequestEnvelopeOuterClass.RequestEnvelope.AuthInfo auth, OkHttpClient client) { + public PokemonGo(RequestEnvelopeOuterClass.RequestEnvelope.AuthInfo auth, OkHttpClient client) + throws LoginFailedException, RemoteServerException { playerProfile = null; // send profile request to get the ball rolling requestHandler = new RequestHandler(this, auth, client); - getPlayerProfile(); - // should have proper end point now. - - map = new Map(this); - lastInventoryUpdate = 0; - } - - private PlayerDataOuterClass.PlayerData getPlayerAndUpdateInventory(PlayerProfile playerProfile) - throws LoginFailedException, RemoteServerException { - - GetPlayerMessage getPlayerReqMsg = GetPlayerMessage.newBuilder().build(); - ServerRequest getPlayerServerRequest = new ServerRequest(RequestType.GET_PLAYER, getPlayerReqMsg); - getRequestHandler().request(getPlayerServerRequest); - - GetInventoryMessage invReqMsg = GetInventoryMessage.newBuilder() - .setLastTimestampMs(this.lastInventoryUpdate) - .build(); - ServerRequest getInventoryServerRequest = new ServerRequest(RequestType.GET_INVENTORY, invReqMsg); - getRequestHandler().request(getInventoryServerRequest); - getRequestHandler().sendServerRequests(); + playerProfile = new PlayerProfile(this); + inventories = new Inventories(this); - GetPlayerResponse getPlayerResponse; - GetInventoryResponse getInventoryResponse; - try { - getPlayerResponse = GetPlayerResponse.parseFrom(getPlayerServerRequest.getData()); - getInventoryResponse = GetInventoryResponse.parseFrom(getInventoryServerRequest.getData()); - } catch (InvalidProtocolBufferException e) { - throw new RemoteServerException(e); - } - - pokebank = new PokeBank(this); - bag = new Bag(this); - candyjar = new CandyJar(this); - - for (InventoryItemOuterClass.InventoryItem item : - getInventoryResponse.getInventoryDelta().getInventoryItemsList()) { - - if (item.getInventoryItemData().getPokemonData().getPokemonId() != PokemonIdOuterClass.PokemonId.MISSINGNO) { - pokebank.addPokemon(new Pokemon(item.getInventoryItemData().getPokemonData())); - } - - if (item.getInventoryItemData().getItem().getItemId() != ItemIdOuterClass.ItemId.ITEM_UNKNOWN) { - bag.addItem(new Item(item.getInventoryItemData().getItem())); - } - - if (item.getInventoryItemData().getPokemonFamily().getFamilyId() != PokemonFamilyId.UNRECOGNIZED) { - candyjar.setCandy( - item.getInventoryItemData().getPokemonFamily().getFamilyId(), - item.getInventoryItemData().getPokemonFamily().getCandy()); - } - - if (item.getInventoryItemData().hasPlayerStats()) { - PlayerStatsOuterClass.PlayerStats stats = item.getInventoryItemData().getPlayerStats(); - playerProfile.setStats(stats); - } + playerProfile.updateProfile(); + inventories.updateInventories(); - } - - return getPlayerResponse.getPlayerData(); - } + // should have proper end point now. - /** - * Gets player profile. - * - * @return the player profile - */ - public PlayerProfile getPlayerProfile() { - return getPlayerProfile(false); + map = new Map(this); } /** @@ -165,61 +80,15 @@ public PlayerProfile getPlayerProfile() { * @param forceUpdate the force update * @return the player profile */ + @Deprecated public PlayerProfile getPlayerProfile(boolean forceUpdate) { if (!forceUpdate && playerProfile != null) { - return playerProfile; - } - - // init here so we can set the experience and level, which is somehow contained in the inventory... - PlayerProfile tempProfile = new PlayerProfile(); - PlayerDataOuterClass.PlayerData localPlayer = null; - try { - localPlayer = getPlayerAndUpdateInventory(tempProfile); - } catch (LoginFailedException | RemoteServerException e) { - Log.e(TAG, "Failed to get profile data and update inventory", e); - } - - if (localPlayer == null) { - return null; - } - playerProfile = tempProfile; - - playerProfile.setBadge(localPlayer.getEquippedBadge()); - playerProfile.setCreationTime(localPlayer.getCreationTimestampMs()); - playerProfile.setItemStorage(localPlayer.getMaxItemStorage()); - playerProfile.setPokemonStorage(localPlayer.getMaxPokemonStorage()); - playerProfile.setTeam(Team.values()[localPlayer.getTeam()]); - playerProfile.setUsername(localPlayer.getUsername()); - - final PlayerAvatar avatarApi = new PlayerAvatar(); - final DailyBonus bonusApi = new DailyBonus(); - final ContactSettings contactApi = new ContactSettings(); - - // maybe something more graceful? - for (CurrencyOuterClass.Currency currency : localPlayer.getCurrenciesList()) { try { - playerProfile.addCurrency(currency.getName(), currency.getAmount()); - } catch (InvalidCurrencyException e) { - Log.w(TAG, "Error adding currency. You can probably ignore this.", e); + playerProfile.updateProfile(); + } catch (Exception e) { + Log.e(TAG, "Error updating Player Profile", e); } } - - avatarApi.setGender(localPlayer.getAvatar().getGender()); - avatarApi.setBackpack(localPlayer.getAvatar().getBackpack()); - avatarApi.setEyes(localPlayer.getAvatar().getEyes()); - avatarApi.setHair(localPlayer.getAvatar().getHair()); - avatarApi.setHat(localPlayer.getAvatar().getHat()); - avatarApi.setPants(localPlayer.getAvatar().getPants()); - avatarApi.setShirt(localPlayer.getAvatar().getShirt()); - avatarApi.setShoes(localPlayer.getAvatar().getShoes()); - avatarApi.setSkin(localPlayer.getAvatar().getSkin()); - - bonusApi.setNextCollectionTimestamp(localPlayer.getDailyBonus().getNextCollectedTimestampMs()); - bonusApi.setNextDefenderBonusCollectTimestamp(localPlayer.getDailyBonus().getNextDefenderBonusCollectTimestampMs()); - - playerProfile.setAvatar(avatarApi); - playerProfile.setDailyBonus(bonusApi); - return playerProfile; } diff --git a/src/main/java/com/pokegoapi/api/inventory/CandyJar.java b/src/main/java/com/pokegoapi/api/inventory/CandyJar.java index 7a1c99dce..beabe3556 100644 --- a/src/main/java/com/pokegoapi/api/inventory/CandyJar.java +++ b/src/main/java/com/pokegoapi/api/inventory/CandyJar.java @@ -17,6 +17,7 @@ import POGOProtos.Enums.PokemonFamilyIdOuterClass.PokemonFamilyId; import com.pokegoapi.api.PokemonGo; +import com.pokegoapi.api.pokemon.Pokemon; import lombok.ToString; import java.util.HashMap; @@ -31,10 +32,50 @@ public CandyJar(PokemonGo pgo) { candies = new HashMap<>(); } + /** + * Sets the number of candies in the jar. + * @param family Pokemon family id + * @param candies Amount to set it to + */ public void setCandy(PokemonFamilyId family, int candies) { this.candies.put(family, candies); } + /** + * Adds a candy to the candy jar. + * @param family Pokemon family id + * @param amount Amount of candies to add + */ + public void addCandy(PokemonFamilyId family, int amount) { + if (candies.containsKey(family)) { + candies.put(family, candies.get(family) + amount); + } else { + candies.put(family, amount); + } + } + + /** + * Remove a candy from the candy jar. + * @param family Pokemon family id + * @param amount Amount of candies to remove + */ + public void removeCandy(PokemonFamilyId family, int amount) { + if (candies.containsKey(family)) { + if (candies.get(family) - amount < 0) { + candies.put(family, 0); + } else { + candies.put(family, candies.get(family) - amount); + } + } else { + candies.put(family, 0); + } + } + + /** + * Get number of candies from the candyjar. + * @param family Pokemon family id + * @return number of candies in jar + */ public int getCandies(PokemonFamilyId family) { return this.candies.get(family); } diff --git a/src/main/java/com/pokegoapi/api/inventory/Inventories.java b/src/main/java/com/pokegoapi/api/inventory/Inventories.java new file mode 100644 index 000000000..115428794 --- /dev/null +++ b/src/main/java/com/pokegoapi/api/inventory/Inventories.java @@ -0,0 +1,140 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.pokegoapi.api.inventory; + +import POGOProtos.Data.Player.PlayerStatsOuterClass; +import POGOProtos.Enums.PokemonFamilyIdOuterClass; +import POGOProtos.Enums.PokemonIdOuterClass; +import POGOProtos.Inventory.InventoryItemDataOuterClass; +import POGOProtos.Inventory.InventoryItemOuterClass; +import POGOProtos.Inventory.ItemIdOuterClass; +import POGOProtos.Inventory.ItemOuterClass; +import POGOProtos.Networking.Requests.Messages.GetInventoryMessageOuterClass.GetInventoryMessage; +import POGOProtos.Networking.Requests.RequestTypeOuterClass; +import POGOProtos.Networking.Responses.GetInventoryResponseOuterClass.GetInventoryResponse; +import com.google.protobuf.InvalidProtocolBufferException; +import com.pokegoapi.api.PokemonGo; +import com.pokegoapi.api.pokemon.Pokemon; +import com.pokegoapi.exceptions.LoginFailedException; +import com.pokegoapi.exceptions.RemoteServerException; +import com.pokegoapi.main.ServerRequest; +import lombok.Getter; + + +public class Inventories { + + private final PokemonGo api; + @Getter + private ItemBag itemBag; + @Getter + private PokeBank pokebank; + @Getter + private CandyJar candyjar; + @Getter + private PlayerStatsOuterClass.PlayerStats stats; + + private long lastInventoryUpdate = 0; + + /** + * Creates Inventories and initializes content. + * @param api PokemonGo api + * @throws LoginFailedException the login failed exception + * @throws RemoteServerException the remote server exception + */ + public Inventories(PokemonGo api) throws LoginFailedException, RemoteServerException { + this.api = api; + itemBag = new ItemBag(api); + pokebank = new PokeBank(api); + candyjar = new CandyJar(api); + updateInventories(); + } + + /** + * Updates the inventories with latest data. + * @throws LoginFailedException the login failed exception + * @throws RemoteServerException the remote server exception + */ + public void updateInventories() throws LoginFailedException, RemoteServerException { + updateInventories(false); + } + + /** + * Updates the inventories with the latest data. + * @param forceUpdate For a full update if true + * @throws LoginFailedException the login failed exception + * @throws RemoteServerException the remote server exception + */ + public void updateInventories(boolean forceUpdate) throws LoginFailedException, RemoteServerException { + if (forceUpdate) { + lastInventoryUpdate = 0; + itemBag = new ItemBag(api); + pokebank = new PokeBank(api); + candyjar = new CandyJar(api); + } + GetInventoryMessage invReqMsg = GetInventoryMessage.newBuilder() + .setLastTimestampMs(lastInventoryUpdate) + .build(); + ServerRequest inventoryRequest = new ServerRequest(RequestTypeOuterClass.RequestType.GET_INVENTORY, invReqMsg); + api.getRequestHandler().request(inventoryRequest); + api.getRequestHandler().sendServerRequests(); + + GetInventoryResponse response = null; + try { + response = GetInventoryResponse.parseFrom(inventoryRequest.getData()); + } catch (InvalidProtocolBufferException e) { + e.printStackTrace(); + } + + for (InventoryItemOuterClass.InventoryItem inventoryItem + : response.getInventoryDelta().getInventoryItemsList()) { + InventoryItemDataOuterClass.InventoryItemData itemData = inventoryItem.getInventoryItemData(); + if (inventoryItem.getDeletedItemKey() > 0) { + if (itemData.getPokemonData().getPokemonId() != PokemonIdOuterClass.PokemonId.MISSINGNO) { + pokebank.removePokemon(new Pokemon(inventoryItem.getInventoryItemData().getPokemonData())); + } + if (itemData.getItem().getItemId() != ItemIdOuterClass.ItemId.UNRECOGNIZED) { + ItemOuterClass.Item item = inventoryItem.getInventoryItemData().getItem(); + itemBag.removeItem(inventoryItem.getInventoryItemData().getItem().getItemId(), item.getCount()); + } + if (itemData.getPokemonFamily().getFamilyId() != PokemonFamilyIdOuterClass.PokemonFamilyId.UNRECOGNIZED) { + candyjar.removeCandy( + inventoryItem.getInventoryItemData().getPokemonFamily().getFamilyId(), + inventoryItem.getInventoryItemData().getPokemonFamily().getCandy() + ); + } + } else { + if (itemData.getPokemonData().getPokemonId() != PokemonIdOuterClass.PokemonId.MISSINGNO) { + pokebank.addPokemon(new Pokemon(inventoryItem.getInventoryItemData().getPokemonData())); + } + if (itemData.getItem().getItemId() != ItemIdOuterClass.ItemId.UNRECOGNIZED) { + ItemOuterClass.Item item = inventoryItem.getInventoryItemData().getItem(); + itemBag.addItem(new Item(item)); + } + if (itemData.getPokemonFamily().getFamilyId() != PokemonFamilyIdOuterClass.PokemonFamilyId.UNRECOGNIZED) { + candyjar.addCandy( + inventoryItem.getInventoryItemData().getPokemonFamily().getFamilyId(), + inventoryItem.getInventoryItemData().getPokemonFamily().getCandy() + ); + } + if (itemData.hasPlayerStats()) { + stats = inventoryItem.getInventoryItemData().getPlayerStats(); + } + } + + lastInventoryUpdate = System.currentTimeMillis(); + } + } +} diff --git a/src/main/java/com/pokegoapi/api/inventory/Bag.java b/src/main/java/com/pokegoapi/api/inventory/ItemBag.java similarity index 95% rename from src/main/java/com/pokegoapi/api/inventory/Bag.java rename to src/main/java/com/pokegoapi/api/inventory/ItemBag.java index 906c14263..e7b08d7d9 100644 --- a/src/main/java/com/pokegoapi/api/inventory/Bag.java +++ b/src/main/java/com/pokegoapi/api/inventory/ItemBag.java @@ -33,11 +33,11 @@ /** * The type Bag. */ -public class Bag { +public class ItemBag { private PokemonGo pgo; private HashMap items; - public Bag(PokemonGo pgo) { + public ItemBag(PokemonGo pgo) { this.pgo = pgo; items = new HashMap<>(); } @@ -67,10 +67,9 @@ public Result removeItem(ItemId id, int quantity) throws RemoteServerException, .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.RECYCLE_INVENTORY_ITEM, msg); - pgo.getRequestHandler().request(serverRequest); - pgo.getRequestHandler().sendServerRequests(); + pgo.getRequestHandler().sendServerRequests(serverRequest); - RecycleInventoryItemResponseOuterClass.RecycleInventoryItemResponse response = null; + RecycleInventoryItemResponseOuterClass.RecycleInventoryItemResponse response; try { response = RecycleInventoryItemResponseOuterClass.RecycleInventoryItemResponse.parseFrom(serverRequest.getData()); } catch (InvalidProtocolBufferException e) { diff --git a/src/main/java/com/pokegoapi/api/inventory/PokeBank.java b/src/main/java/com/pokegoapi/api/inventory/PokeBank.java index 38849afde..4c87c08cd 100644 --- a/src/main/java/com/pokegoapi/api/inventory/PokeBank.java +++ b/src/main/java/com/pokegoapi/api/inventory/PokeBank.java @@ -37,11 +37,25 @@ public PokeBank(PokemonGo instance) { this.instance = instance; } - public void addPokemon(Pokemon pokemon) { + /** + * Add a pokemon to the pokebank inventory. Will not add duplicates (pokemon with same id). + * @param pokemon Pokemon to add to the inventory + */ + public void addPokemon(final Pokemon pokemon) { pokemon.setPgo(instance); - pokemons.add(pokemon); + List alreadyAdded = StreamSupport.stream(pokemons).filter(new Predicate() { + @Override + public boolean test(Pokemon testPokemon) { + return pokemon.getId() == testPokemon.getId(); + } + }).collect(Collectors.toList()); + if (alreadyAdded.size() < 1) { + pokemons.add(pokemon); + } } + + /** * Gets pokemon by pokemon id. * diff --git a/src/main/java/com/pokegoapi/api/map/Map.java b/src/main/java/com/pokegoapi/api/map/Map.java index 521ebf465..67100be99 100644 --- a/src/main/java/com/pokegoapi/api/map/Map.java +++ b/src/main/java/com/pokegoapi/api/map/Map.java @@ -26,6 +26,7 @@ import POGOProtos.Networking.Requests.Messages.EncounterMessageOuterClass; import POGOProtos.Networking.Requests.Messages.FortDetailsMessageOuterClass.FortDetailsMessage; import POGOProtos.Networking.Requests.Messages.FortSearchMessageOuterClass.FortSearchMessage; +import POGOProtos.Networking.Requests.Messages.GetMapObjectsMessageOuterClass; import POGOProtos.Networking.Requests.Messages.GetMapObjectsMessageOuterClass.GetMapObjectsMessage; import POGOProtos.Networking.Requests.RequestTypeOuterClass; import POGOProtos.Networking.Responses.CatchPokemonResponseOuterClass.CatchPokemonResponse; @@ -55,18 +56,18 @@ public class Map { - private static long NEW_MAP_OBJECTS_EXPIRY = 60000; // 60 seconds - private PokemonGo api; - private long lastMapUpdate; - private MapObjects lastMapObjects; - private double lastLong; - private double lastLat; + + private final PokemonGo api; + private MapObjects cachedMapObjects; @Getter @Setter private boolean useCache; - @Getter + @Setter - private boolean trackUpdate; + @Getter + private long mapObjectsExpiry; + + private long lastMapUpdate; /** * Instantiates a new Map. @@ -75,31 +76,16 @@ public class Map { */ public Map(PokemonGo api) { this.api = api; + cachedMapObjects = new MapObjects(api); lastMapUpdate = 0; useCache = true; - trackUpdate = true; } - /** - * Gets a new map objects if there has been a lat/long change or the last request was done greater then - * NEW_MAP_OBJECTS_EXPIRY. - * - * @return a List of CatchablePokemon at your current location - */ - private MapObjects getRetainedMapObject() throws LoginFailedException, RemoteServerException { - // get new MapObjects or used existing one - if (!useCache) { - return lastMapObjects; - } - if (api.getLatitude() != lastLat && api.getLongitude() != lastLong - || (System.currentTimeMillis() - lastMapUpdate) > NEW_MAP_OBJECTS_EXPIRY) { - getMapObjects(); // should update the lastMapObjects variable - } - - return lastMapObjects; + public void clearCache() { + this.lastMapUpdate = 0; + this.cachedMapObjects = new MapObjects(api); } - /** * Returns a list of catchable pokemon around the current location. * @@ -107,11 +93,12 @@ private MapObjects getRetainedMapObject() throws LoginFailedException, RemoteSer */ public List getCatchablePokemon() throws LoginFailedException, RemoteServerException { List catchablePokemons = new ArrayList<>(); - MapObjects objects = getRetainedMapObject(); + MapObjects objects = getMapObjects(); for (MapPokemon mapPokemon : objects.getCatchablePokemons()) { catchablePokemons.add(new CatchablePokemon(api, mapPokemon)); } + for (WildPokemonOuterClass.WildPokemon wildPokemon : objects.getWildPokemons()) { catchablePokemons.add(new CatchablePokemon(api, wildPokemon)); } @@ -119,7 +106,6 @@ public List getCatchablePokemon() throws LoginFailedException, return catchablePokemons; } - /** * Returns a list of nearby pokemon (non-catchable). * @@ -127,7 +113,7 @@ public List getCatchablePokemon() throws LoginFailedException, */ public List getNearbyPokemon() throws LoginFailedException, RemoteServerException { List pokemons = new ArrayList<>(); - MapObjects objects = getRetainedMapObject(); + MapObjects objects = getMapObjects(); for (NearbyPokemonOuterClass.NearbyPokemon pokemon : objects.getNearbyPokemons()) { pokemons.add(new NearbyPokemon(pokemon)); @@ -143,7 +129,7 @@ public List getNearbyPokemon() throws LoginFailedException, Remot */ public List getSpawnPoints() throws LoginFailedException, RemoteServerException { List points = new ArrayList<>(); - MapObjects objects = getRetainedMapObject(); + MapObjects objects = getMapObjects(); for (SpawnPointOuterClass.SpawnPoint point : objects.getSpawnPoints()) { points.add(new Point(point)); @@ -159,7 +145,7 @@ public List getSpawnPoints() throws LoginFailedException, RemoteServerExc */ public List getDecimatedSpawnPoints() throws LoginFailedException, RemoteServerException { List points = new ArrayList<>(); - MapObjects objects = getRetainedMapObject(); + MapObjects objects = getMapObjects(); for (SpawnPointOuterClass.SpawnPoint point : objects.getDecimatedSpawnPoints()) { points.add(new Point(point)); @@ -259,7 +245,14 @@ public MapObjects getMapObjects(List cellIds, double latitude, double long * @return MapObjects in the given cells */ public MapObjects getMapObjects(List cellIds) throws LoginFailedException, RemoteServerException { - GetMapObjectsMessage.Builder builder = GetMapObjectsMessage.newBuilder() + GetMapObjectsMessage.Builder builder = GetMapObjectsMessage.newBuilder(); + + if (useCache && (System.currentTimeMillis() - lastMapUpdate > mapObjectsExpiry)) { + lastMapUpdate = 0; + cachedMapObjects = new MapObjects(api); + } + + builder = GetMapObjectsMessageOuterClass.GetMapObjectsMessage.newBuilder() .setLatitude(api.getLatitude()) .setLongitude(api.getLongitude()); @@ -267,16 +260,14 @@ public MapObjects getMapObjects(List cellIds) throws LoginFailedException, for (Long cellId : cellIds) { builder.addCellId(cellId); long time = 0; - if (trackUpdate) { - time = lastMapUpdate; - } + builder.addSinceTimestampMs(lastMapUpdate); index++; + } ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.GET_MAP_OBJECTS, builder.build()); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); + api.getRequestHandler().sendServerRequests(serverRequest); GetMapObjectsResponseOuterClass.GetMapObjectsResponse response = null; try { response = GetMapObjectsResponseOuterClass.GetMapObjectsResponse.parseFrom(serverRequest.getData()); @@ -303,8 +294,12 @@ public FortType apply(FortData fortData) { result.addPokestops(groupedForts.get(FortType.CHECKPOINT)); } - lastMapObjects = result; - lastMapUpdate = System.currentTimeMillis(); + if (useCache) { + cachedMapObjects.update(result); + result = cachedMapObjects; + lastMapUpdate = System.currentTimeMillis(); + } + return result; } @@ -320,12 +315,10 @@ public List getCellIds(double latitude, double longitude, int width) { S2LatLng latLng = S2LatLng.fromDegrees(latitude, longitude); S2CellId cellId = S2CellId.fromLatLng(latLng).parent(15); - lastLat = api.getLatitude(); - lastLong = api.getLongitude(); - MutableInteger index = new MutableInteger(0); MutableInteger jindex = new MutableInteger(0); + int level = cellId.level(); int size = 1 << (S2CellId.MAX_LEVEL - level); int face = cellId.toFaceIJOrientation(index, jindex, null); @@ -359,8 +352,7 @@ public FortDetails getFortDetails(String id, long lon, long lat) throws LoginFai .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.FORT_DETAILS, reqMsg); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); + api.getRequestHandler().sendServerRequests(serverRequest); FortDetailsResponseOuterClass.FortDetailsResponse response = null; try { response = FortDetailsResponseOuterClass.FortDetailsResponse.parseFrom(serverRequest.getData()); @@ -388,9 +380,10 @@ public FortSearchResponse searchFort(FortData fortData) throws LoginFailedExcept .setPlayerLongitude(api.getLongitude()) .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.FORT_SEARCH, reqMsg); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); - FortSearchResponse response = null; + + api.getRequestHandler().sendServerRequests(serverRequest); + + FortSearchResponse response; try { response = FortSearchResponse.parseFrom(serverRequest.getData()); } catch (InvalidProtocolBufferException e) { @@ -418,9 +411,9 @@ public EncounterResponse encounterPokemon(MapPokemon catchablePokemon) .setSpawnpointId(catchablePokemon.getSpawnpointId()) .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.ENCOUNTER, reqMsg); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); - EncounterResponse response = null; + api.getRequestHandler().sendServerRequests(serverRequest); + + EncounterResponse response; try { response = EncounterResponse.parseFrom(serverRequest.getData()); } catch (InvalidProtocolBufferException e) { @@ -460,9 +453,9 @@ public CatchPokemonResponse catchPokemon( .setPokeball(pokeball) .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.CATCH_POKEMON, reqMsg); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); - CatchPokemonResponse response = null; + api.getRequestHandler().sendServerRequests(serverRequest); + + CatchPokemonResponse response; try { response = CatchPokemonResponse.parseFrom(serverRequest.getData()); } catch (InvalidProtocolBufferException e) { @@ -470,4 +463,4 @@ public CatchPokemonResponse catchPokemon( } return response; } -} \ No newline at end of file +} diff --git a/src/main/java/com/pokegoapi/api/map/MapObjects.java b/src/main/java/com/pokegoapi/api/map/MapObjects.java index 646986b6f..084881703 100644 --- a/src/main/java/com/pokegoapi/api/map/MapObjects.java +++ b/src/main/java/com/pokegoapi/api/map/MapObjects.java @@ -15,6 +15,7 @@ package com.pokegoapi.api.map; +import POGOProtos.Map.Fort.FortDataOuterClass; import POGOProtos.Map.Fort.FortDataOuterClass.FortData; import POGOProtos.Map.Pokemon.MapPokemonOuterClass.MapPokemon; import POGOProtos.Map.Pokemon.NearbyPokemonOuterClass.NearbyPokemon; @@ -159,4 +160,48 @@ public void addPokestops(Collection pokestops) { public boolean isComplete() { return complete; } + + + /** + * updates the object. + * + * + */ + public void update(MapObjects other) { + + nearbyPokemons.clear(); + addNearbyPokemons(other.getNearbyPokemons()); + + catchablePokemons.clear(); + addCatchablePokemons(other.getCatchablePokemons()); + + wildPokemons.clear(); + addWildPokemons(other.getWildPokemons()); + + decimatedSpawnPoints.clear(); + addDecimatedSpawnPoints(other.getDecimatedSpawnPoints()); + + spawnPoints.clear(); + addSpawnPoints(other.getSpawnPoints()); + + for (FortData otherGym : other.getGyms()) { + for (FortData gym : getGyms()) { + if (otherGym.getId().equals(gym.getId())) { + gyms.remove(gym); + break; + } + } + gyms.add(otherGym); + } + + for (Pokestop otherPokestop : other.getPokestops()) { + for (Pokestop pokestop : pokestops) { + if (otherPokestop.getId().equals(pokestop.getId())) { + pokestops.remove(pokestop); + break; + } + } + pokestops.add(otherPokestop); + } + } } \ No newline at end of file diff --git a/src/main/java/com/pokegoapi/api/map/fort/Pokestop.java b/src/main/java/com/pokegoapi/api/map/fort/Pokestop.java index 2266a5755..fabca72f4 100644 --- a/src/main/java/com/pokegoapi/api/map/fort/Pokestop.java +++ b/src/main/java/com/pokegoapi/api/map/fort/Pokestop.java @@ -98,8 +98,7 @@ public PokestopLootResult loot() throws LoginFailedException, RemoteServerExcept .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.FORT_SEARCH, searchMessage); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); + api.getRequestHandler().sendServerRequests(serverRequest); FortSearchResponseOuterClass.FortSearchResponse response; try { response = FortSearchResponseOuterClass.FortSearchResponse.parseFrom(serverRequest.getData()); @@ -125,8 +124,7 @@ public FortDetails getDetails() throws LoginFailedException, RemoteServerExcepti .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.FORT_DETAILS, reqMsg); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); + api.getRequestHandler().sendServerRequests(serverRequest); FortDetailsResponseOuterClass.FortDetailsResponse response = null; try { response = FortDetailsResponseOuterClass.FortDetailsResponse.parseFrom(serverRequest.getData()); diff --git a/src/main/java/com/pokegoapi/api/map/Pokemon/CatchPokemonResult.java b/src/main/java/com/pokegoapi/api/map/pokemon/CatchPokemonResult.java similarity index 100% rename from src/main/java/com/pokegoapi/api/map/Pokemon/CatchPokemonResult.java rename to src/main/java/com/pokegoapi/api/map/pokemon/CatchPokemonResult.java diff --git a/src/main/java/com/pokegoapi/api/map/Pokemon/CatchResult.java b/src/main/java/com/pokegoapi/api/map/pokemon/CatchResult.java similarity index 100% rename from src/main/java/com/pokegoapi/api/map/Pokemon/CatchResult.java rename to src/main/java/com/pokegoapi/api/map/pokemon/CatchResult.java diff --git a/src/main/java/com/pokegoapi/api/map/Pokemon/CatchablePokemon.java b/src/main/java/com/pokegoapi/api/map/pokemon/CatchablePokemon.java similarity index 90% rename from src/main/java/com/pokegoapi/api/map/Pokemon/CatchablePokemon.java rename to src/main/java/com/pokegoapi/api/map/pokemon/CatchablePokemon.java index efd01efb2..1cdb72f16 100644 --- a/src/main/java/com/pokegoapi/api/map/Pokemon/CatchablePokemon.java +++ b/src/main/java/com/pokegoapi/api/map/pokemon/CatchablePokemon.java @@ -16,6 +16,7 @@ package com.pokegoapi.api.map.pokemon; import POGOProtos.Enums.PokemonIdOuterClass; +import POGOProtos.Inventory.ItemIdOuterClass; import POGOProtos.Map.Pokemon.MapPokemonOuterClass.MapPokemon; import POGOProtos.Map.Pokemon.WildPokemonOuterClass.WildPokemon; import POGOProtos.Networking.Requests.Messages.CatchPokemonMessageOuterClass.CatchPokemonMessage; @@ -107,8 +108,7 @@ public EncounterResult encounterPokemon() throws LoginFailedException, RemoteSer .setSpawnpointId(getSpawnpointId()) .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.ENCOUNTER, reqMsg); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); + api.getRequestHandler().sendServerRequests(serverRequest); EncounterResponseOuterClass.EncounterResponse response = null; try { response = EncounterResponseOuterClass.EncounterResponse.parseFrom(serverRequest.getData()); @@ -120,14 +120,24 @@ public EncounterResult encounterPokemon() throws LoginFailedException, RemoteSer } /** - * Tries to catch a pokemon with a pokeball. + * Tries to catch a pokemon (will attempt to use a pokeball, if you have none will use greatball etc). * * @return CatchResult * @throws LoginFailedException if failed to login * @throws RemoteServerException if the server failed to respond */ public CatchResult catchPokemon() throws LoginFailedException, RemoteServerException { - return catchPokemon(Pokeball.POKEBALL); + Pokeball ball = Pokeball.POKEBALL; + if (api.getInventories().getItemBag().getItem(ItemIdOuterClass.ItemId.ITEM_POKE_BALL).getCount() == 0) { + ball = Pokeball.GREATBALL; + } + if (api.getInventories().getItemBag().getItem(ItemIdOuterClass.ItemId.ITEM_GREAT_BALL).getCount() == 0) { + ball = Pokeball.ULTRABALL; + } + if (api.getInventories().getItemBag().getItem(ItemIdOuterClass.ItemId.ITEM_ULTRA_BALL).getCount() == 0) { + ball = Pokeball.MASTERBALL; + } + return catchPokemon(ball); } @@ -188,8 +198,7 @@ public CatchResult catchPokemon( .setPokeball(type.getBalltype()) .build(); ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.CATCH_POKEMON, reqMsg); - api.getRequestHandler().request(serverRequest); - api.getRequestHandler().sendServerRequests(); + api.getRequestHandler().sendServerRequests(serverRequest); try { response = CatchPokemonResponse.parseFrom(serverRequest.getData()); diff --git a/src/main/java/com/pokegoapi/api/map/Pokemon/EncounterResult.java b/src/main/java/com/pokegoapi/api/map/pokemon/EncounterResult.java similarity index 71% rename from src/main/java/com/pokegoapi/api/map/Pokemon/EncounterResult.java rename to src/main/java/com/pokegoapi/api/map/pokemon/EncounterResult.java index 50a82c551..0d4be261b 100644 --- a/src/main/java/com/pokegoapi/api/map/Pokemon/EncounterResult.java +++ b/src/main/java/com/pokegoapi/api/map/pokemon/EncounterResult.java @@ -15,11 +15,11 @@ package com.pokegoapi.api.map.pokemon; +import POGOProtos.Data.Capture.CaptureProbabilityOuterClass; +import POGOProtos.Map.Pokemon.WildPokemonOuterClass; import POGOProtos.Networking.Responses.EncounterResponseOuterClass.EncounterResponse; -/** - * Created by mjmfighter on 7/20/2016. - */ + public class EncounterResult { private EncounterResponse response; @@ -35,4 +35,20 @@ public EncounterResponse.Status getStatus() { public boolean wasSuccessful() { return response != null && getStatus() != null && getStatus().equals(EncounterResponse.Status.ENCOUNTER_SUCCESS); } + + public EncounterResponse.Background getBackground() { + return response.getBackground(); + } + + public CaptureProbabilityOuterClass.CaptureProbability getCaptureProbability() { + return response.getCaptureProbability(); + } + + public WildPokemonOuterClass.WildPokemon getWildPokemon() { + return response.getWildPokemon(); + } + + public EncounterResponse toPrimitive() { + return response; + } } diff --git a/src/main/java/com/pokegoapi/api/map/Pokemon/EvolutionResult.java b/src/main/java/com/pokegoapi/api/map/pokemon/EvolutionResult.java similarity index 100% rename from src/main/java/com/pokegoapi/api/map/Pokemon/EvolutionResult.java rename to src/main/java/com/pokegoapi/api/map/pokemon/EvolutionResult.java diff --git a/src/main/java/com/pokegoapi/api/map/Pokemon/NearbyPokemon.java b/src/main/java/com/pokegoapi/api/map/pokemon/NearbyPokemon.java similarity index 100% rename from src/main/java/com/pokegoapi/api/map/Pokemon/NearbyPokemon.java rename to src/main/java/com/pokegoapi/api/map/pokemon/NearbyPokemon.java diff --git a/src/main/java/com/pokegoapi/api/player/PlayerProfile.java b/src/main/java/com/pokegoapi/api/player/PlayerProfile.java index 0379409ea..903b55d53 100644 --- a/src/main/java/com/pokegoapi/api/player/PlayerProfile.java +++ b/src/main/java/com/pokegoapi/api/player/PlayerProfile.java @@ -15,18 +15,28 @@ package com.pokegoapi.api.player; +import POGOProtos.Data.Player.CurrencyOuterClass; import POGOProtos.Data.Player.EquippedBadgeOuterClass; import POGOProtos.Data.Player.PlayerStatsOuterClass; +import POGOProtos.Networking.Requests.Messages.GetPlayerMessageOuterClass.GetPlayerMessage; +import POGOProtos.Networking.Requests.RequestTypeOuterClass.RequestType; +import POGOProtos.Networking.Responses.GetPlayerResponseOuterClass; +import com.google.protobuf.InvalidProtocolBufferException; +import com.pokegoapi.api.PokemonGo; import com.pokegoapi.exceptions.InvalidCurrencyException; -import lombok.Data; +import com.pokegoapi.exceptions.LoginFailedException; +import com.pokegoapi.exceptions.RemoteServerException; +import com.pokegoapi.main.ServerRequest; +import com.pokegoapi.util.Log; import lombok.Getter; import lombok.Setter; import java.util.HashMap; import java.util.Map; -@Data public class PlayerProfile { + private static final String TAG = PlayerProfile.class.getSimpleName(); + private final PokemonGo api; private long creationTime; private String username; private Team team; @@ -42,6 +52,72 @@ public class PlayerProfile { @Setter private PlayerStatsOuterClass.PlayerStats stats; + public PlayerProfile(PokemonGo api) throws LoginFailedException, RemoteServerException { + this.api = api; + updateProfile(); + } + + /** + * Updates the player profile with the latest data. + * @throws LoginFailedException the login failed exception + * @throws RemoteServerException the remote server exception + */ + public void updateProfile() throws LoginFailedException, RemoteServerException { + GetPlayerMessage getPlayerReqMsg = GetPlayerMessage.newBuilder().build(); + ServerRequest getPlayerServerRequest = new ServerRequest(RequestType.GET_PLAYER, getPlayerReqMsg); + api.getRequestHandler().request(getPlayerServerRequest); + api.getRequestHandler().sendServerRequests(); + + GetPlayerResponseOuterClass.GetPlayerResponse playerResponse = null; + try { + playerResponse = GetPlayerResponseOuterClass.GetPlayerResponse.parseFrom(getPlayerServerRequest.getData()); + } catch (InvalidProtocolBufferException e) { + e.printStackTrace(); + } + + badge = playerResponse.getPlayerData().getEquippedBadge(); + creationTime = playerResponse.getPlayerData().getCreationTimestampMs(); + itemStorage = playerResponse.getPlayerData().getMaxItemStorage(); + pokemonStorage = playerResponse.getPlayerData().getMaxPokemonStorage(); + team = Team.values()[playerResponse.getPlayerData().getTeam()]; + username = playerResponse.getPlayerData().getUsername(); + + final PlayerAvatar avatarApi = new PlayerAvatar(); + final DailyBonus bonusApi = new DailyBonus(); + final ContactSettings contactApi = new ContactSettings(); + + // maybe something more graceful? + for (CurrencyOuterClass.Currency currency : playerResponse.getPlayerData().getCurrenciesList()) { + try { + addCurrency(currency.getName(), currency.getAmount()); + } catch (InvalidCurrencyException e) { + Log.w(TAG, "Error adding currency. You can probably ignore this.", e); + } + } + + avatarApi.setGender(playerResponse.getPlayerData().getAvatar().getGender()); + avatarApi.setBackpack(playerResponse.getPlayerData().getAvatar().getBackpack()); + avatarApi.setEyes(playerResponse.getPlayerData().getAvatar().getEyes()); + avatarApi.setHair(playerResponse.getPlayerData().getAvatar().getHair()); + avatarApi.setHat(playerResponse.getPlayerData().getAvatar().getHat()); + avatarApi.setPants(playerResponse.getPlayerData().getAvatar().getPants()); + avatarApi.setShirt(playerResponse.getPlayerData().getAvatar().getShirt()); + avatarApi.setShoes(playerResponse.getPlayerData().getAvatar().getShoes()); + avatarApi.setSkin(playerResponse.getPlayerData().getAvatar().getSkin()); + + bonusApi.setNextCollectionTimestamp( + playerResponse.getPlayerData().getDailyBonus().getNextCollectedTimestampMs() + ); + bonusApi.setNextDefenderBonusCollectTimestamp( + playerResponse.getPlayerData().getDailyBonus().getNextDefenderBonusCollectTimestampMs() + ); + + avatar = avatarApi; + dailyBonus = bonusApi; + + + + } /** * Add currency. diff --git a/src/main/java/com/pokegoapi/api/pokemon/Pokemon.java b/src/main/java/com/pokegoapi/api/pokemon/Pokemon.java index fcca8cd0f..cf3d485cd 100644 --- a/src/main/java/com/pokegoapi/api/pokemon/Pokemon.java +++ b/src/main/java/com/pokegoapi/api/pokemon/Pokemon.java @@ -64,8 +64,7 @@ public Result transferPokemon() throws LoginFailedException, RemoteServerExcepti ReleasePokemonMessage reqMsg = ReleasePokemonMessage.newBuilder().setPokemonId(getId()).build(); ServerRequest serverRequest = new ServerRequest(RequestType.RELEASE_POKEMON, reqMsg); - pgo.getRequestHandler().request(serverRequest); - pgo.getRequestHandler().sendServerRequests(); + pgo.getRequestHandler().sendServerRequests(serverRequest); ReleasePokemonResponse response; try { @@ -74,13 +73,6 @@ public Result transferPokemon() throws LoginFailedException, RemoteServerExcepti return ReleasePokemonResponse.Result.FAILED; } - if (response.getResult().equals(Result.SUCCESS)) { - pgo.getCandyjar().setCandy( - this.getPokemonFamily(), - pgo.getCandyjar().getCandies(this.getPokemonFamily()) + response.getCandyAwarded()); - pgo.getPokebank().removePokemon(this); - } - return response.getResult(); } @@ -100,8 +92,7 @@ public NicknamePokemonResponse.Result renamePokemon(String nickname) .build(); ServerRequest serverRequest = new ServerRequest(RequestType.NICKNAME_POKEMON, reqMsg); - pgo.getRequestHandler().request(serverRequest); - pgo.getRequestHandler().sendServerRequests(); + pgo.getRequestHandler().sendServerRequests(serverRequest); NicknamePokemonResponse response; try { @@ -124,8 +115,7 @@ public EvolutionResult evolve() throws LoginFailedException, RemoteServerExcepti EvolvePokemonMessage reqMsg = EvolvePokemonMessage.newBuilder().setPokemonId(getId()).build(); ServerRequest serverRequest = new ServerRequest(RequestType.EVOLVE_POKEMON, reqMsg); - pgo.getRequestHandler().request(serverRequest); - pgo.getRequestHandler().sendServerRequests(); + pgo.getRequestHandler().sendServerRequests(serverRequest); EvolvePokemonResponse response; try { @@ -136,16 +126,11 @@ public EvolutionResult evolve() throws LoginFailedException, RemoteServerExcepti EvolutionResult result = new EvolutionResult(response); - if (result.isSuccessful()) { - pgo.getPokebank().removePokemon(this); - pgo.getPokebank().addPokemon(result.getEvolvedPokemon()); - } - return result; } public int getCandy() { - return pgo.getCandyjar().getCandies(getPokemonFamily()); + return pgo.getInventories().getCandyjar().getCandies(getPokemonFamily()); } public PokemonFamilyId getPokemonFamily() { diff --git a/src/main/java/com/pokegoapi/examples/TransferOnePidgeyExample.java b/src/main/java/com/pokegoapi/examples/TransferOnePidgeyExample.java index bda2ec029..bce2958af 100644 --- a/src/main/java/com/pokegoapi/examples/TransferOnePidgeyExample.java +++ b/src/main/java/com/pokegoapi/examples/TransferOnePidgeyExample.java @@ -43,7 +43,8 @@ public static void main(String[] args) { //auth = new GoogleLogin(http).login("", ""); // currently uses oauth flow so no user or pass needed PokemonGo go = new PokemonGo(auth, http); - List pidgeys = go.getPokebank().getPokemonByPokemonId(PokemonIdOuterClass.PokemonId.PIDGEY); + List pidgeys = + go.getInventories().getPokebank().getPokemonByPokemonId(PokemonIdOuterClass.PokemonId.PIDGEY); if (pidgeys.size() > 0) { Pokemon pest = pidgeys.get(0); diff --git a/src/main/java/com/pokegoapi/main/RequestHandler.java b/src/main/java/com/pokegoapi/main/RequestHandler.java index 8aa45b116..cfea09157 100644 --- a/src/main/java/com/pokegoapi/main/RequestHandler.java +++ b/src/main/java/com/pokegoapi/main/RequestHandler.java @@ -58,7 +58,9 @@ public RequestHandler(PokemonGo api, RequestEnvelopeOuterClass.RequestEnvelope.A this.client = client; apiEndpoint = ApiSettings.API_ENDPOINT; this.auth = auth; - serverRequests = new ArrayList(); + serverRequests = new ArrayList<>(); + /* TODO: somehow fix it so people using the deprecated functions will still work, + while not calling this deprecated stuff ourselves */ resetBuilder(); } @@ -67,18 +69,104 @@ public RequestHandler(PokemonGo api, RequestEnvelopeOuterClass.RequestEnvelope.A * * @param requestIn the request in */ + @Deprecated public void request(ServerRequest requestIn) { hasRequests = true; serverRequests.add(requestIn); builder.addRequests(requestIn.getRequest()); } + /** + * Sends multiple ServerRequests in a thread safe manner. + * + * @param serverRequests list of ServerRequests to be sent + * @throws RemoteServerException the remote server exception + * @throws LoginFailedException the login failed exception + */ + public void sendServerRequests(ServerRequest... serverRequests) throws RemoteServerException, LoginFailedException { + if (serverRequests.length == 0) { + return; + } + RequestEnvelopeOuterClass.RequestEnvelope.Builder builder = RequestEnvelopeOuterClass.RequestEnvelope.newBuilder(); + resetBuilder(builder); + + for (ServerRequest serverRequest : serverRequests) { + builder.addRequests(serverRequest.getRequest()); + } + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + RequestEnvelopeOuterClass.RequestEnvelope request = builder.build(); + try { + request.writeTo(stream); + } catch (IOException e) { + Log.wtf(TAG, "Failed to write request to bytearray ouput stream. This should never happen", e); + } + + RequestBody body = RequestBody.create(null, stream.toByteArray()); + okhttp3.Request httpRequest = new okhttp3.Request.Builder() + .url(apiEndpoint) + .post(body) + .build(); + + try (Response response = client.newCall(httpRequest).execute()) { + if (response.code() != 200) { + throw new RemoteServerException("Got a unexpected http code : " + response.code()); + } + + ResponseEnvelopeOuterClass.ResponseEnvelope responseEnvelop; + try (InputStream content = response.body().byteStream()) { + responseEnvelop = ResponseEnvelopeOuterClass.ResponseEnvelope.parseFrom(content); + } catch (IOException e) { + // retrieved garbage from the server + throw new RemoteServerException("Received malformed response : " + e); + } + + if (responseEnvelop.getApiUrl() != null && responseEnvelop.getApiUrl().length() > 0) { + apiEndpoint = "https://" + responseEnvelop.getApiUrl() + "/rpc"; + } + + if (responseEnvelop.hasAuthTicket()) { + lastAuth = responseEnvelop.getAuthTicket(); + } + + if (responseEnvelop.getStatusCode() == 102) { + throw new LoginFailedException(); + } else if (responseEnvelop.getStatusCode() == 53) { + // 53 means that the api_endpoint was not correctly set, should be at this point, though, so redo the request + sendServerRequests(serverRequests); + return; + } + + /** + * map each reply to the numeric response, + * ie first response = first request and send back to the requests to handle. + * */ + int count = 0; + for (ByteString payload : responseEnvelop.getReturnsList()) { + ServerRequest serverReq = serverRequests[count]; + /** + * TODO: Probably all other payloads are garbage as well in this case, + * so might as well throw an exception and leave this loop */ + if (payload != null) { + serverReq.handleData(payload); + } + count++; + } + } catch (IOException e) { + throw new RemoteServerException(e); + } catch (RemoteServerException e) { + // catch it, so the auto-close of resources triggers, but don't wrap it in yet another RemoteServer Exception + throw e; + } + } + /** * Send server requests. * * @throws RemoteServerException the remote server exception * @throws LoginFailedException the login failed exception */ + @Deprecated public void sendServerRequests() throws RemoteServerException, LoginFailedException { setLatitude(api.getLatitude()); setLongitude(api.getLongitude()); @@ -97,7 +185,7 @@ public void sendServerRequests() throws RemoteServerException, LoginFailedExcept .url(apiEndpoint) .post(body) .build(); - Response response = null; + Response response; try { response = client.newCall(httpRequest).execute(); } catch (IOException e) { @@ -147,18 +235,29 @@ public void sendServerRequests() throws RemoteServerException, LoginFailedExcept resetBuilder(); } + @Deprecated private void resetBuilder() { builder = RequestEnvelopeOuterClass.RequestEnvelope.newBuilder(); + resetBuilder(builder); + hasRequests = false; + serverRequests.clear(); + } + + private void resetBuilder(RequestEnvelopeOuterClass.RequestEnvelope.Builder builder) { builder.setStatusCode(2); builder.setRequestId(8145806132888207460L); - if (lastAuth != null && lastAuth.getExpireTimestampMs() > 0) { + if (lastAuth != null && + lastAuth.getExpireTimestampMs() > 0 && + lastAuth.getExpireTimestampMs() > System.currentTimeMillis()) { builder.setAuthTicket(lastAuth); } else { + Log.d(TAG, "Authenticated with static token"); builder.setAuthInfo(auth); } builder.setUnknown12(989); - hasRequests = false; - serverRequests.clear(); + builder.setLatitude(api.getLatitude()); + builder.setLongitude(api.getLongitude()); + builder.setAltitude(api.getAltitude()); }