示例#1
0
        /// <summary>
        ///     Prepares the <see cref="RequestEnvelope" /> to be sent with <see cref="_httpClient" />.
        /// </summary>
        /// <param name="requestEnvelope">The <see cref="RequestEnvelope" /> that will be send.</param>
        /// <returns><see cref="StreamContent" /> to be sent with <see cref="_httpClient" />.</returns>
        private ByteArrayContent PrepareRequestEnvelope(RequestEnvelope requestEnvelope)
        {
            var messageBytes = requestEnvelope.ToByteArray();

            // TODO: Compression?

            return(new ByteArrayContent(messageBytes));
        }
示例#2
0
        private async Task <ByteString> PerformRemoteProcedureCallAsync(RequestEnvelope requestEnvelope)
        {
            try
            {
                using (var requestData = new ByteArrayContent(requestEnvelope.ToByteArray()))
                {
                    Logger.Debug($"Sending RPC Request: '{string.Join(", ", requestEnvelope.Requests.Select(x => x.RequestType))}'");
                    Logger.Debug($"=> Platform Request: '{string.Join(", ", requestEnvelope.PlatformRequests.Select(x => x.Type))}'");

                    using (var response = await _session.HttpClient.PostAsync(_requestUrl ?? Constants.ApiUrl, requestData))
                    {
                        if (!response.IsSuccessStatusCode)
                        {
                            Logger.Debug(await response.Content.ReadAsStringAsync());

                            throw new Exception("Received a non-success HTTP status code from the RPC server, see the console for the response.");
                        }

                        var responseBytes    = response.Content.ReadAsByteArrayAsync().Result;
                        var responseEnvelope = ResponseEnvelope.Parser.ParseFrom(responseBytes);

                        switch (responseEnvelope.StatusCode)
                        {
                        // Valid response.
                        case ResponseEnvelope.Types.StatusCode.Ok:
                            // Success!?
                            break;

                        // Valid response and new rpc url.
                        case ResponseEnvelope.Types.StatusCode.OkRpcUrlInResponse:
                            if (Regex.IsMatch(responseEnvelope.ApiUrl, "pgorelease\\.nianticlabs\\.com\\/plfe\\/\\d+"))
                            {
                                _requestUrl = $"https://{responseEnvelope.ApiUrl}/rpc";
                            }
                            else
                            {
                                throw new Exception($"Received an incorrect API url: '{responseEnvelope.ApiUrl}', status code was: '{responseEnvelope.StatusCode}'.");
                            }
                            break;

                        // A new rpc endpoint is available.
                        case ResponseEnvelope.Types.StatusCode.Redirect:
                            if (Regex.IsMatch(responseEnvelope.ApiUrl, "pgorelease\\.nianticlabs\\.com\\/plfe\\/\\d+"))
                            {
                                _requestUrl = $"https://{responseEnvelope.ApiUrl}/rpc";

                                return(await PerformRemoteProcedureCallAsync(requestEnvelope));
                            }
                            throw new Exception($"Received an incorrect API url: '{responseEnvelope.ApiUrl}', status code was: '{responseEnvelope.StatusCode}'.");

                        // The login token is invalid.
                        // TODO: Make cleaner to reduce duplicate code with the GetRequestEnvelopeAsync method.
                        case ResponseEnvelope.Types.StatusCode.InvalidAuthToken:
                            Logger.Debug("Received StatusCode 102, reauthenticating.");

                            _session.AccessToken.Expire();
                            await _session.Reauthenticate();

                            // Apply new token.
                            requestEnvelope.AuthInfo = new RequestEnvelope.Types.AuthInfo
                            {
                                Provider = _session.AccessToken.ProviderID,
                                Token    = new RequestEnvelope.Types.AuthInfo.Types.JWT
                                {
                                    Contents = _session.AccessToken.Token,
                                    Unknown2 = 59
                                }
                            };

                            // Re-sign envelope.
                            var signature = requestEnvelope.PlatformRequests.FirstOrDefault(x => x.Type == PlatformRequestType.SendEncryptedSignature);
                            if (signature != null)
                            {
                                requestEnvelope.PlatformRequests.Remove(signature);
                            }

                            requestEnvelope.PlatformRequests.Insert(0, await _rpcEncryption.GenerateSignatureAsync(requestEnvelope));

                            // Re-send envelope.
                            return(await PerformRemoteProcedureCallAsync(requestEnvelope));

                        default:
                            Logger.Info($"Unknown status code: {responseEnvelope.StatusCode}");
                            break;
                        }

                        LastRpcRequest = DateTime.UtcNow;

                        if (requestEnvelope.Requests[0].RequestType == RequestType.GetMapObjects)
                        {
                            LastRpcMapObjectsRequest           = LastRpcRequest;
                            LastGeoCoordinateMapObjectsRequest = _session.Player.Coordinate;
                        }

                        if (responseEnvelope.AuthTicket != null)
                        {
                            _session.AccessToken.AuthTicket = responseEnvelope.AuthTicket;
                            Logger.Debug("Received a new AuthTicket from Pokemon!");
                        }

                        var mapPlatform = responseEnvelope.PlatformReturns.FirstOrDefault(x => x.Type == PlatformRequestType.UnknownPtr8);
                        if (mapPlatform != null)
                        {
                            var unknownPtr8Response = UnknownPtr8Response.Parser.ParseFrom(mapPlatform.Response);
                            _mapKey = unknownPtr8Response.Message;
                        }

                        return(HandleResponseEnvelope(requestEnvelope, responseEnvelope));
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error($"SendRemoteProcedureCall exception: {e}");
                return(null);
            }
        }
示例#3
0
        /// <summary>
        /// Tries to send the <see cref="RequestEnvelope"/> message to the network.
        /// Returns an <typeparamref name="TResponseType"/> when completed.
        /// </summary>
        /// <param name="envelope">Envolope to send.</param>
        /// <returns>An awaitable future result.</returns>
        public IFuture <IEnumerable <TResponseType> > SendRequestAsFutures <TResponseType, TFutureType>(RequestEnvelope envelope, TFutureType responseMessageFuture, string url)
            where TResponseType : class, IResponseMessage, IMessage <TResponseType>, IMessage, new()
            where TFutureType : IFuture <IEnumerable <TResponseType> >, IAsyncCallBackTarget
        {
            //TODO: Add URL/URI
            //TODO: Verify header stuff
            IRestRequest request = new RestRequest(url).AddParameter("application/x-www-form-urlencoded", envelope.ToByteArray(), ParameterType.RequestBody);

            request.Method = Method.POST;

            var requestFuture = new RestSharpAsyncRequestFuturesDeserializationDecorator <TFutureType, TResponseType>(responseMessageFuture);

            //To send protobuf requests
            httpClient.ExecuteAsync(request, (res, hand) =>
            {
                requestFuture.OnResponse(res);
            });             //we have to provide the future as the callback

            return(requestFuture);
        }
示例#4
0
        /// <summary>
        /// Tries to send the <see cref="RequestEnvelope"/> message to the network.
        /// Returns an <see cref="IFuture{ResponseEnvelope}"/> when completed.
        /// </summary>
        /// <param name="envelope">Envolope to send.</param>
        /// <returns>An awaitable future result.</returns>
        public IFuture <ResponseEnvelope> SendRequestAsResponseFuture <TFutureType>(RequestEnvelope envelope, TFutureType responseEnvelopeFuture, string url)
            where TFutureType : IFuture <ResponseEnvelope>, IAsyncCallBackTarget
        {
            //TODO: Add URL/URI
            //TODO: Verify header stuff
            IRestRequest request = new RestRequest(url).AddParameter("application/x-www-form-urlencoded", envelope.ToByteArray(), ParameterType.RequestBody);

            request.Method = Method.POST;

            var requestFuture = new RestSharpAsyncRequestFutureDeserializationDecorator <TFutureType>(responseEnvelopeFuture);

            httpClient.ExecuteAsync(request, (res, hand) =>
            {
                requestFuture.OnResponse(res);
            });

            return(requestFuture);
        }
示例#5
0
        private async Task <ByteString> PerformRemoteProcedureCallAsync(RequestEnvelope requestEnvelope)
        {
            if (requestEnvelope == null)
            {
                return(null);
            }

            try
            {
                switch (_session.State)
                {
                case SessionState.Stopped:
                    _session.Logger.Error("We tried to send a request while the session was stopped.");
                    return(null);

                case SessionState.Banned:
                    _session.Logger.Error("We tried to send a request while the session was temporal banned.");
                    return(null);

                case SessionState.Paused:
                    break;
                }

                using (var requestData = new ByteArrayContent(requestEnvelope.ToByteArray()))
                {
                    if (requestData == null)
                    {
                        await Task.Delay(10000); //wait 10 secs on grave bug

                        throw new SessionStateException($"RequestData is null");
                    }

                    using (var response = await _session.HttpClient.PostAsync(_requestUrl ?? Constants.ApiUrl, requestData))
                    {
                        if (response == null)
                        {
                            await Task.Delay(10000); //wait 10 secs on grave bug

                            throw new SessionStateException($"RequestData response is null");
                        }

                        _session.Logger.Debug("Sending RPC Request: '" + string.Join(", ", requestEnvelope.Requests.Select(x => x.RequestType)) + "'");
                        _session.Logger.Debug("=> Platform Request: '" + string.Join(", ", requestEnvelope.PlatformRequests.Select(x => x.Type)) + "'");

                        if (!response.IsSuccessStatusCode)
                        {
                            _session.Logger.Warn(await response.Content.ReadAsStringAsync());
                            await Task.Delay(10000); //wait 10 secs on grave bug

                            throw new Exception("Received a non-success HTTP status code from the RPC server, see the console for the response.");
                        }

                        var responseBytes = await response.Content.ReadAsByteArrayAsync();

                        var responseEnvelope = ResponseEnvelope.Parser.ParseFrom(responseBytes);

                        switch (responseEnvelope.StatusCode)
                        {
                        // Valid response.
                        case ResponseEnvelope.Types.StatusCode.Ok:
                            // Success!?
                            break;

                        // Valid response and new rpc url.
                        case ResponseEnvelope.Types.StatusCode.OkRpcUrlInResponse:
                            if (Regex.IsMatch(responseEnvelope.ApiUrl, "pgorelease\\.nianticlabs\\.com\\/plfe\\/\\d+"))
                            {
                                _requestUrl = $"https://{responseEnvelope.ApiUrl}/rpc";
                            }
                            else
                            {
                                await Task.Delay(10000);     //wait 10 secs on grave bug

                                throw new Exception($"Received an incorrect API url: '{responseEnvelope.ApiUrl}', status code was: '{responseEnvelope.StatusCode}'.");
                            }
                            break;

                        // A new rpc endpoint is available.
                        case ResponseEnvelope.Types.StatusCode.Redirect:
                            if (Regex.IsMatch(responseEnvelope.ApiUrl, "pgorelease\\.nianticlabs\\.com\\/plfe\\/\\d+"))
                            {
                                _requestUrl = $"https://{responseEnvelope.ApiUrl}/rpc";
                                return(await PerformRemoteProcedureCallAsync(requestEnvelope));
                            }
                            await Task.Delay(10000);     //wait 10 secs on grave bug

                            throw new Exception($"Received an incorrect API url: '{responseEnvelope.ApiUrl}', status code was: '{responseEnvelope.StatusCode}'.");

                        // The login token is invalid.
                        // TODO: Make cleaner to reduce duplicate code with the GetRequestEnvelopeAsync method.
                        case ResponseEnvelope.Types.StatusCode.InvalidAuthToken:
                            _session.Logger.Debug("Received StatusCode 102, reauthenticating.");

                            await _session.GetValidAccessToken(true);

                            // Apply new token.
                            requestEnvelope.AuthInfo = new RequestEnvelope.Types.AuthInfo
                            {
                                Provider = _session.AccessToken.ProviderID,
                                Token    = new RequestEnvelope.Types.AuthInfo.Types.JWT
                                {
                                    Contents = _session.AccessToken.Token,
                                    Unknown2 = 59
                                }
                            };

                            // Clear all PlatformRequests.
                            requestEnvelope.PlatformRequests.Clear();

                            // Re-send envelope.
                            ByteString resend = null;
                            resend = await PerformRemoteProcedureCallAsync(requestEnvelope);

                            if (resend == null)
                            {
                                throw new SessionStateException("INVALID AUTH TOKEN");
                            }
                            else
                            {
                                return(resend);
                            }
                            throw new SessionStateException("INVALID AUTH TOKEN");

                        case ResponseEnvelope.Types.StatusCode.BadRequest:
                            await Task.Delay(10000);     //wait 10 secs on grave bug

                            throw new APIBadRequestException("BAD REQUEST");

                        case ResponseEnvelope.Types.StatusCode.SessionInvalidated:
                            await Task.Delay(10000);     //wait 10 secs on grave bug

                            throw new SessionInvalidatedException("SESSION INVALIDATED");

                        case ResponseEnvelope.Types.StatusCode.Unknown:
                            await Task.Delay(10000);     //wait 10 secs on grave bug

                            throw new SessionUnknowException("UNKNOWN");

                        case ResponseEnvelope.Types.StatusCode.InvalidPlatformRequest:
                            await Task.Delay(10000);     //wait 10 secs on grave bug

                            throw new InvalidPlatformException("INVALID PLATFORM REQUEST");

                        case ResponseEnvelope.Types.StatusCode.InvalidRequest:
                            await Task.Delay(10000);     //wait 10 secs on grave bug

                            throw new InvalidPlatformException("INVALID REQUEST");

                        default:
                            await Task.Delay(10000);     //wait 10 secs on grave bug

                            throw new Exception($"Unknown status code: {responseEnvelope.StatusCode}");
                        }

                        LastRpcRequest = DateTime.UtcNow;

                        if (requestEnvelope.Requests[0].RequestType == RequestType.CreateOrUpdatePlayer)
                        {
                            LastRpcMapObjectsRequest           = LastRpcRequest;
                            LastGeoCoordinateMapObjectsRequest = _session.Player.Coordinate;
                        }

                        if (responseEnvelope.AuthTicket != null)
                        {
                            _session.AccessToken.AuthTicket = responseEnvelope.AuthTicket;
                            _session.Logger.Debug("Received a new AuthTicket from Wizards!");
                        }

                        return(HandleResponseEnvelope(requestEnvelope, responseEnvelope));
                    }
                }
            }
            catch (SessionInvalidatedException ex)
            {
                throw ex;
            }
            catch (InvalidPlatformException ex)
            {
                throw ex;
            }
            catch (APIBadRequestException ex)
            {
                throw new APIBadRequestException(ex.Message);
            }
            catch (Exception ex)
            {
                throw new SessionStateException($"Your account may be temporary banned! please try from the official client." + ex);
            }
        }
示例#6
0
        /// <summary>
        ///     Prepares the <see cref="RequestEnvelope" /> to be sent with <see cref="_httpClient" />.
        /// </summary>
        /// <param name="requestEnvelope">The <see cref="RequestEnvelope" /> that will be send.</param>
        /// <returns><see cref="StreamContent" /> to be sent with <see cref="_httpClient" />.</returns>
        private ByteArrayContent PrepareRequestEnvelope(RequestEnvelope requestEnvelope)
        {
            var messageBytes = requestEnvelope.ToByteArray();

            // TODO: Compression?

            return new ByteArrayContent(messageBytes);
        }