Skip to content

Commit f55dc0e

Browse files
authored
Merge pull request #113 from jabbink/fix-threadSafeServerRequest
Make server requests work over multiple threads at once
2 parents 0a2fdb4 + 580d752 commit f55dc0e

7 files changed

Lines changed: 128 additions & 41 deletions

File tree

src/main/java/com/pokegoapi/api/PokemonGo.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,13 @@ private PlayerDataOuterClass.PlayerData getPlayerAndUpdateInventory(PlayerProfil
100100

101101
GetPlayerMessage getPlayerReqMsg = GetPlayerMessage.newBuilder().build();
102102
ServerRequest getPlayerServerRequest = new ServerRequest(RequestType.GET_PLAYER, getPlayerReqMsg);
103-
getRequestHandler().request(getPlayerServerRequest);
104103

105104
GetInventoryMessage invReqMsg = GetInventoryMessage.newBuilder()
106105
.setLastTimestampMs(this.lastInventoryUpdate)
107106
.build();
108107
ServerRequest getInventoryServerRequest = new ServerRequest(RequestType.GET_INVENTORY, invReqMsg);
109-
getRequestHandler().request(getInventoryServerRequest);
110108

111-
getRequestHandler().sendServerRequests();
109+
getRequestHandler().sendServerRequests(getPlayerServerRequest, getInventoryServerRequest);
112110

113111
GetPlayerResponse getPlayerResponse;
114112
GetInventoryResponse getInventoryResponse;

src/main/java/com/pokegoapi/api/inventory/Bag.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,9 @@ public Result removeItem(ItemId id, int quantity) throws RemoteServerException,
6767
.build();
6868

6969
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.RECYCLE_INVENTORY_ITEM, msg);
70-
pgo.getRequestHandler().request(serverRequest);
71-
pgo.getRequestHandler().sendServerRequests();
70+
pgo.getRequestHandler().sendServerRequests(serverRequest);
7271

73-
RecycleInventoryItemResponseOuterClass.RecycleInventoryItemResponse response = null;
72+
RecycleInventoryItemResponseOuterClass.RecycleInventoryItemResponse response;
7473
try {
7574
response = RecycleInventoryItemResponseOuterClass.RecycleInventoryItemResponse.parseFrom(serverRequest.getData());
7675
} catch (InvalidProtocolBufferException e) {

src/main/java/com/pokegoapi/api/map/Map.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,7 @@ public MapObjects getMapObjects(List<Long> cellIds) throws LoginFailedException,
267267
}
268268

269269
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.GET_MAP_OBJECTS, builder.build());
270-
api.getRequestHandler().request(serverRequest);
271-
api.getRequestHandler().sendServerRequests();
270+
api.getRequestHandler().sendServerRequests(serverRequest);
272271
GetMapObjectsResponseOuterClass.GetMapObjectsResponse response = null;
273272
try {
274273
response = GetMapObjectsResponseOuterClass.GetMapObjectsResponse.parseFrom(serverRequest.getData());
@@ -353,8 +352,7 @@ public FortDetails getFortDetails(String id, long lon, long lat) throws LoginFai
353352
.build();
354353

355354
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.FORT_DETAILS, reqMsg);
356-
api.getRequestHandler().request(serverRequest);
357-
api.getRequestHandler().sendServerRequests();
355+
api.getRequestHandler().sendServerRequests(serverRequest);
358356
FortDetailsResponseOuterClass.FortDetailsResponse response = null;
359357
try {
360358
response = FortDetailsResponseOuterClass.FortDetailsResponse.parseFrom(serverRequest.getData());
@@ -382,9 +380,10 @@ public FortSearchResponse searchFort(FortData fortData) throws LoginFailedExcept
382380
.setPlayerLongitude(api.getLongitude())
383381
.build();
384382
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.FORT_SEARCH, reqMsg);
385-
api.getRequestHandler().request(serverRequest);
386-
api.getRequestHandler().sendServerRequests();
387-
FortSearchResponse response = null;
383+
384+
api.getRequestHandler().sendServerRequests(serverRequest);
385+
386+
FortSearchResponse response;
388387
try {
389388
response = FortSearchResponse.parseFrom(serverRequest.getData());
390389
} catch (InvalidProtocolBufferException e) {
@@ -412,9 +411,9 @@ public EncounterResponse encounterPokemon(MapPokemon catchablePokemon)
412411
.setSpawnpointId(catchablePokemon.getSpawnpointId())
413412
.build();
414413
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.ENCOUNTER, reqMsg);
415-
api.getRequestHandler().request(serverRequest);
416-
api.getRequestHandler().sendServerRequests();
417-
EncounterResponse response = null;
414+
api.getRequestHandler().sendServerRequests(serverRequest);
415+
416+
EncounterResponse response;
418417
try {
419418
response = EncounterResponse.parseFrom(serverRequest.getData());
420419
} catch (InvalidProtocolBufferException e) {
@@ -454,9 +453,9 @@ public CatchPokemonResponse catchPokemon(
454453
.setPokeball(pokeball)
455454
.build();
456455
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.CATCH_POKEMON, reqMsg);
457-
api.getRequestHandler().request(serverRequest);
458-
api.getRequestHandler().sendServerRequests();
459-
CatchPokemonResponse response = null;
456+
api.getRequestHandler().sendServerRequests(serverRequest);
457+
458+
CatchPokemonResponse response;
460459
try {
461460
response = CatchPokemonResponse.parseFrom(serverRequest.getData());
462461
} catch (InvalidProtocolBufferException e) {

src/main/java/com/pokegoapi/api/map/fort/Pokestop.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ public PokestopLootResult loot() throws LoginFailedException, RemoteServerExcept
9898
.build();
9999

100100
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.FORT_SEARCH, searchMessage);
101-
api.getRequestHandler().request(serverRequest);
102-
api.getRequestHandler().sendServerRequests();
101+
api.getRequestHandler().sendServerRequests(serverRequest);
103102
FortSearchResponseOuterClass.FortSearchResponse response;
104103
try {
105104
response = FortSearchResponseOuterClass.FortSearchResponse.parseFrom(serverRequest.getData());
@@ -125,8 +124,7 @@ public FortDetails getDetails() throws LoginFailedException, RemoteServerExcepti
125124
.build();
126125

127126
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.FORT_DETAILS, reqMsg);
128-
api.getRequestHandler().request(serverRequest);
129-
api.getRequestHandler().sendServerRequests();
127+
api.getRequestHandler().sendServerRequests(serverRequest);
130128
FortDetailsResponseOuterClass.FortDetailsResponse response = null;
131129
try {
132130
response = FortDetailsResponseOuterClass.FortDetailsResponse.parseFrom(serverRequest.getData());

src/main/java/com/pokegoapi/api/map/pokemon/CatchablePokemon.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,7 @@ public EncounterResult encounterPokemon() throws LoginFailedException, RemoteSer
108108
.setSpawnpointId(getSpawnpointId())
109109
.build();
110110
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.ENCOUNTER, reqMsg);
111-
api.getRequestHandler().request(serverRequest);
112-
api.getRequestHandler().sendServerRequests();
111+
api.getRequestHandler().sendServerRequests(serverRequest);
113112
EncounterResponseOuterClass.EncounterResponse response = null;
114113
try {
115114
response = EncounterResponseOuterClass.EncounterResponse.parseFrom(serverRequest.getData());
@@ -121,17 +120,23 @@ public EncounterResult encounterPokemon() throws LoginFailedException, RemoteSer
121120
}
122121

123122
/**
124-
* Tries to catch a pokemon (will attempt to use a pokeball, if you have none will use greatball etc)
123+
* Tries to catch a pokemon (will attempt to use a pokeball, if you have none will use greatball etc).
125124
*
126125
* @return CatchResult
127126
* @throws LoginFailedException if failed to login
128127
* @throws RemoteServerException if the server failed to respond
129128
*/
130129
public CatchResult catchPokemon() throws LoginFailedException, RemoteServerException {
131130
Pokeball ball = Pokeball.POKEBALL;
132-
if (api.getBag().getItem(ItemIdOuterClass.ItemId.ITEM_POKE_BALL).getCount() == 0) ball = Pokeball.GREATBALL;
133-
if (api.getBag().getItem(ItemIdOuterClass.ItemId.ITEM_GREAT_BALL).getCount() == 0) ball = Pokeball.ULTRABALL;
134-
if (api.getBag().getItem(ItemIdOuterClass.ItemId.ITEM_ULTRA_BALL).getCount() == 0) ball = Pokeball.MASTERBALL;
131+
if (api.getBag().getItem(ItemIdOuterClass.ItemId.ITEM_POKE_BALL).getCount() == 0) {
132+
ball = Pokeball.GREATBALL;
133+
}
134+
if (api.getBag().getItem(ItemIdOuterClass.ItemId.ITEM_GREAT_BALL).getCount() == 0) {
135+
ball = Pokeball.ULTRABALL;
136+
}
137+
if (api.getBag().getItem(ItemIdOuterClass.ItemId.ITEM_ULTRA_BALL).getCount() == 0) {
138+
ball = Pokeball.MASTERBALL;
139+
}
135140
return catchPokemon(ball);
136141
}
137142

@@ -193,8 +198,7 @@ public CatchResult catchPokemon(
193198
.setPokeball(type.getBalltype())
194199
.build();
195200
ServerRequest serverRequest = new ServerRequest(RequestTypeOuterClass.RequestType.CATCH_POKEMON, reqMsg);
196-
api.getRequestHandler().request(serverRequest);
197-
api.getRequestHandler().sendServerRequests();
201+
api.getRequestHandler().sendServerRequests(serverRequest);
198202

199203
try {
200204
response = CatchPokemonResponse.parseFrom(serverRequest.getData());

src/main/java/com/pokegoapi/api/pokemon/Pokemon.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ public Result transferPokemon() throws LoginFailedException, RemoteServerExcepti
6464
ReleasePokemonMessage reqMsg = ReleasePokemonMessage.newBuilder().setPokemonId(getId()).build();
6565

6666
ServerRequest serverRequest = new ServerRequest(RequestType.RELEASE_POKEMON, reqMsg);
67-
pgo.getRequestHandler().request(serverRequest);
68-
pgo.getRequestHandler().sendServerRequests();
67+
pgo.getRequestHandler().sendServerRequests(serverRequest);
6968

7069
ReleasePokemonResponse response;
7170
try {
@@ -100,8 +99,7 @@ public NicknamePokemonResponse.Result renamePokemon(String nickname)
10099
.build();
101100

102101
ServerRequest serverRequest = new ServerRequest(RequestType.NICKNAME_POKEMON, reqMsg);
103-
pgo.getRequestHandler().request(serverRequest);
104-
pgo.getRequestHandler().sendServerRequests();
102+
pgo.getRequestHandler().sendServerRequests(serverRequest);
105103

106104
NicknamePokemonResponse response;
107105
try {
@@ -124,8 +122,7 @@ public EvolutionResult evolve() throws LoginFailedException, RemoteServerExcepti
124122
EvolvePokemonMessage reqMsg = EvolvePokemonMessage.newBuilder().setPokemonId(getId()).build();
125123

126124
ServerRequest serverRequest = new ServerRequest(RequestType.EVOLVE_POKEMON, reqMsg);
127-
pgo.getRequestHandler().request(serverRequest);
128-
pgo.getRequestHandler().sendServerRequests();
125+
pgo.getRequestHandler().sendServerRequests(serverRequest);
129126

130127
EvolvePokemonResponse response;
131128
try {

src/main/java/com/pokegoapi/main/RequestHandler.java

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ public RequestHandler(PokemonGo api, RequestEnvelopeOuterClass.RequestEnvelope.A
5858
this.client = client;
5959
apiEndpoint = ApiSettings.API_ENDPOINT;
6060
this.auth = auth;
61-
serverRequests = new ArrayList<ServerRequest>();
61+
serverRequests = new ArrayList<>();
62+
/* TODO: somehow fix it so people using the deprecated functions will still work,
63+
while not calling this deprecated stuff ourselves */
6264
resetBuilder();
6365
}
6466

@@ -67,18 +69,100 @@ public RequestHandler(PokemonGo api, RequestEnvelopeOuterClass.RequestEnvelope.A
6769
*
6870
* @param requestIn the request in
6971
*/
72+
@Deprecated
7073
public void request(ServerRequest requestIn) {
7174
hasRequests = true;
7275
serverRequests.add(requestIn);
7376
builder.addRequests(requestIn.getRequest());
7477
}
7578

79+
/**
80+
* Sends multiple ServerRequests in a thread safe manner.
81+
*
82+
* @param serverRequests list of ServerRequests to be sent
83+
* @throws RemoteServerException the remote server exception
84+
* @throws LoginFailedException the login failed exception
85+
*/
86+
public void sendServerRequests(ServerRequest... serverRequests) throws RemoteServerException, LoginFailedException {
87+
if (serverRequests.length == 0) {
88+
return;
89+
}
90+
RequestEnvelopeOuterClass.RequestEnvelope.Builder builder = RequestEnvelopeOuterClass.RequestEnvelope.newBuilder();
91+
resetBuilder(builder);
92+
93+
for (ServerRequest serverRequest : serverRequests) {
94+
builder.addRequests(serverRequest.getRequest());
95+
}
96+
97+
ByteArrayOutputStream stream = new ByteArrayOutputStream();
98+
RequestEnvelopeOuterClass.RequestEnvelope request = builder.build();
99+
try {
100+
request.writeTo(stream);
101+
} catch (IOException e) {
102+
Log.wtf(TAG, "Failed to write request to bytearray ouput stream. This should never happen", e);
103+
}
104+
105+
RequestBody body = RequestBody.create(null, stream.toByteArray());
106+
okhttp3.Request httpRequest = new okhttp3.Request.Builder()
107+
.url(apiEndpoint)
108+
.post(body)
109+
.build();
110+
Response response;
111+
try {
112+
response = client.newCall(httpRequest).execute();
113+
} catch (IOException e) {
114+
throw new RemoteServerException(e);
115+
}
116+
117+
if (response.code() != 200) {
118+
throw new RemoteServerException("Got a unexcepted http code : " + response.code());
119+
}
120+
121+
ResponseEnvelopeOuterClass.ResponseEnvelope responseEnvelop;
122+
try (InputStream content = response.body().byteStream()) {
123+
responseEnvelop = ResponseEnvelopeOuterClass.ResponseEnvelope.parseFrom(content);
124+
} catch (IOException e) {
125+
// retrieved garbage from the server
126+
throw new RemoteServerException("Received malformed response : " + e);
127+
}
128+
129+
if (responseEnvelop.getApiUrl() != null && responseEnvelop.getApiUrl().length() > 0) {
130+
apiEndpoint = "https://" + responseEnvelop.getApiUrl() + "/rpc";
131+
}
132+
133+
if (responseEnvelop.hasAuthTicket()) {
134+
lastAuth = responseEnvelop.getAuthTicket();
135+
}
136+
137+
if (responseEnvelop.getStatusCode() == 102) {
138+
throw new LoginFailedException();
139+
} else if (responseEnvelop.getStatusCode() == 53) {
140+
// 53 means that the api_endpoint was not correctly set, should be at this point, though, so redo the request
141+
sendServerRequests(serverRequests);
142+
return;
143+
}
144+
145+
/* map each reply to the numeric response,
146+
ie first response = first request and send back to the requests to handle. */
147+
int count = 0;
148+
for (ByteString payload : responseEnvelop.getReturnsList()) {
149+
ServerRequest serverReq = serverRequests[count];
150+
/* TODO: Probably all other payloads are garbage as well in this case,
151+
so might as well throw an exception and leave this loop */
152+
if (payload != null) {
153+
serverReq.handleData(payload);
154+
}
155+
count++;
156+
}
157+
}
158+
76159
/**
77160
* Send server requests.
78161
*
79162
* @throws RemoteServerException the remote server exception
80163
* @throws LoginFailedException the login failed exception
81164
*/
165+
@Deprecated
82166
public void sendServerRequests() throws RemoteServerException, LoginFailedException {
83167
setLatitude(api.getLatitude());
84168
setLongitude(api.getLongitude());
@@ -97,7 +181,7 @@ public void sendServerRequests() throws RemoteServerException, LoginFailedExcept
97181
.url(apiEndpoint)
98182
.post(body)
99183
.build();
100-
Response response = null;
184+
Response response;
101185
try {
102186
response = client.newCall(httpRequest).execute();
103187
} catch (IOException e) {
@@ -147,8 +231,15 @@ public void sendServerRequests() throws RemoteServerException, LoginFailedExcept
147231
resetBuilder();
148232
}
149233

234+
@Deprecated
150235
private void resetBuilder() {
151236
builder = RequestEnvelopeOuterClass.RequestEnvelope.newBuilder();
237+
resetBuilder(builder);
238+
hasRequests = false;
239+
serverRequests.clear();
240+
}
241+
242+
private void resetBuilder(RequestEnvelopeOuterClass.RequestEnvelope.Builder builder) {
152243
builder.setStatusCode(2);
153244
builder.setRequestId(8145806132888207460L);
154245
if (lastAuth != null && lastAuth.getExpireTimestampMs() > 0) {
@@ -157,8 +248,9 @@ private void resetBuilder() {
157248
builder.setAuthInfo(auth);
158249
}
159250
builder.setUnknown12(989);
160-
hasRequests = false;
161-
serverRequests.clear();
251+
builder.setLatitude(api.getLatitude());
252+
builder.setLongitude(api.getLongitude());
253+
builder.setAltitude(api.getAltitude());
162254
}
163255

164256

0 commit comments

Comments
 (0)