Esempio n. 1
0
        protected HttpResponseMessage ResponseToClient(HttpStatusCode code, Exception e = null)
        {
            HttpResponseMessage res = new HttpResponseMessage(code);

            res.Headers.TryAddWithoutValidation("Content-Type", "x-www-form-urlencoded");
            res.Headers.TryAddWithoutValidation("Connection", "keep-alive");
            res.Headers.TryAddWithoutValidation("PoGoEmulator", ".NET 4.6.2 MVC API");
            res.Headers.TryAddWithoutValidation("Date", $"{string.Format(new CultureInfo("en-GB"), "{0:ddd, dd MMM yyyy hh:mm:ss}", DateTime.UtcNow)} GMT");
            if (code == HttpStatusCode.OK)
            {
                Database.SaveChanges();
                Log.LogInformation($"succesfully responding[{Request.Host.Host}]:");
            }
            else
            {
                ProtoResponse = new ResponseEnvelope()
                {
                    RequestId  = ProtoRequest.RequestId,
                    Error      = e.Message,
                    StatusCode = 1,
                };
                Log.LogError($"{DateTime.Now.ToString()} responding error[{Request.Host.Host}]: {e.Message}");
            }

            res.Content = new ByteArrayContent(ProtoResponse.ToByteArray());
            return(res);
        }
        /**
         * <summary>
         * Wraps protocol message into a results bean.</summary>
         *
         * <param name="data">Protocol message that need to be wrapped.</param>
         * <returns>Wrapped message.</returns>
         */
        private static GridClientResponse WrapResponse(ProtoResponse data)
        {
            GridClientResponse bean = new GridClientResponse();

            //bean.RequestId = data.RequestId;
            //bean.ClientId = WrapGuid(data.ClientId);
            bean.Status = GridClientResponse.FindByCode(data.Status);

            if (data.HasErrorMessage)
            {
                bean.ErrorMessage = data.ErrorMessage;
            }

            if (data.HasResultBean)
            {
                bean.Result = WrapObject(data.ResultBean);
            }

            if (data.HasSessionToken)
            {
                bean.SessionToken = data.SessionToken.ToByteArray();
            }

            return(bean);
        }
Esempio n. 3
0
        public StaticFileContext(ProtoContext context, StaticFileOptions options, PathString matchUrl, ILogger logger, IFileProvider fileProvider, IContentTypeProvider contentTypeProvider)
        {
            _context             = context;
            _options             = options;
            _matchUrl            = matchUrl;
            _request             = context.Request;
            _response            = context.Response;
            _logger              = logger;
            _requestHeaders      = _request.GetTypedHeaders();
            _responseHeaders     = _response.GetTypedHeaders();
            _fileProvider        = fileProvider;
            _contentTypeProvider = contentTypeProvider;

            _method                 = null;
            _isGet                  = false;
            _isHead                 = false;
            _subPath                = PathString.Empty;
            _contentType            = null;
            _fileInfo               = null;
            _length                 = 0;
            _lastModified           = new DateTimeOffset();
            _etag                   = null;
            _ifMatchState           = PreconditionState.Unspecified;
            _ifNoneMatchState       = PreconditionState.Unspecified;
            _ifModifiedSinceState   = PreconditionState.Unspecified;
            _ifUnmodifiedSinceState = PreconditionState.Unspecified;
            _range                  = null;
            _isRangeRequest         = false;
        }
        /**
         * <summary>
         * Wraps results bean into a protocol message.</summary>
         *
         * <param name="bean">Results bean that need to be wrapped.</param>
         * <returns>Wrapped message.</returns>
         */
        private static ProtoResponse WrapResultBean(GridClientResponse bean)
        {
            ProtoResponse.Builder builder = ProtoResponse.CreateBuilder()
                                            //.SetRequestId(bean.RequestId)
                                            //.SetClientId(WrapGuid(bean.ClientId))
                                            .SetStatus((int)bean.Status);

            if (bean.ErrorMessage != null)
            {
                builder.SetErrorMessage(bean.ErrorMessage);
            }

            if (bean.Result != null)
            {
                builder.SetResultBean(WrapObject(bean.Result));
            }

            if (bean.SessionToken != null)
            {
                builder.SetSessionToken(ByteString.CopyFrom(bean.SessionToken));
            }

            return(builder.Build());
        }
        // Handle MAD data

        /*
         * [
         *  HttpPost("/raw"),
         *  Produces("application/json"),
         * ]
         * public async Task<ProtoResponse> PostAsync(List<ProtoData> payloads)
         * {
         *  Response.Headers["Accept"] = "application/json";
         *  Response.Headers["Content-Type"] = "application/json";
         *  var response await HandleProtoRequest(new ProtoPayload
         *  {
         *      Username = "******",
         *      Uuid = Request.Headers["Origin"],
         *      Contents = payloads,
         *  });
         *  return response;
         * }
         */

        #endregion

        #region Handlers

        private async Task <ProtoResponse> HandleProtoRequest(ProtoPayload payload)
        {
            if (payload == null)
            {
                _logger.LogError("Invalid proto payload received");
                return(null);
            }

            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var device = await _deviceRepository.GetByIdAsync(payload.Uuid).ConfigureAwait(false);

            if (device != null)
            {
                device.LastLatitude  = payload.LatitudeTarget;
                device.LastLongitude = payload.LongitudeTarget;
                device.LastSeen      = DateTime.UtcNow.ToTotalSeconds();
                await _deviceRepository.UpdateAsync(device).ConfigureAwait(false);
            }

            if (!string.IsNullOrEmpty(payload.Username) && payload.Level > 0)
            {
                if (!_levelCache.ContainsKey(payload.Username))
                {
                    _levelCache.Add(payload.Username, payload.Level);
                }
                else
                {
                    var oldLevel = _levelCache[payload.Username];
                    if (oldLevel != payload.Level)
                    {
                        var account = await _accountRepository.GetByIdAsync(payload.Username).ConfigureAwait(false);

                        if (account != null)
                        {
                            account.Level = payload.Level;
                            await _accountRepository.UpdateAsync(account).ConfigureAwait(false);
                        }
                        _levelCache[payload.Username] = payload.Level;
                    }
                }
            }
            if (payload.Contents?.Count == 0)
            {
                _logger.LogWarning($"[Proto] [{payload.Uuid}] Invalid GMO");
                return(null);
            }
            var wildPokemon   = 0;
            var nearbyPokemon = 0;
            var clientWeather = 0;
            var forts         = 0;
            var fortDetails   = new List <FortDetailsOutProto>();
            var quests        = 0;
            var fortSearch    = 0;
            var encounters    = 0;
            var cells         = new List <ulong>();
            var inventory     = new List <InventoryDeltaProto>();
            var playerData    = 0;
            //var spawnpoints = new List<Spawnpoint>();

            var isEmptyGmo   = true;
            var isInvalidGmo = true;
            var containsGmo  = false;

            if (payload.Contents == null)
            {
                _logger.LogWarning($"[Proto] [{payload.Uuid}] Empty data");
                return(null);
            }

            Coordinate targetCoord = null;
            var        inArea      = false;

            if (payload.LatitudeTarget != 0 && payload.LongitudeTarget != 0)
            {
                targetCoord = new Coordinate(payload.LatitudeTarget, payload.LongitudeTarget);
            }
            var      targetKnown  = false;
            S2CellId targetCellId = default;

            if (targetCoord != null)
            {
                // Check target is within cell id instead of checking geofences
                targetKnown  = true;
                targetCellId = S2CellId.FromLatLng(S2LatLng.FromDegrees(targetCoord.Latitude, targetCoord.Longitude));
                //_logger.LogDebug($"[Proto] [{payload.Uuid}] Data received within target area {targetCoord} and target distance {payload.TargetMaxDistance}");
            }
            //_logger.LogWarning($"[{device.Uuid}] InArea={inArea}");

            foreach (var rawData in payload.Contents)
            {
                if (string.IsNullOrEmpty(rawData.Data))
                {
                    _logger.LogWarning($"[Proto] [{payload.Uuid}] Unhandled proto {rawData.Method}: {rawData.Data}");
                    continue;
                }
                var data   = rawData.Data;
                var method = (Method)rawData.Method;
                switch (method)
                {
                case Method.GetPlayer:
                    try
                    {
                        var gpr = GetPlayerOutProto.Parser.ParseFrom(Convert.FromBase64String(data));
                        if (gpr?.Success == true)
                        {
                            await PushData(RedisChannels.ProtoAccount, new
                            {
                                gpr,
                                username = payload.Username,
                            });

                            playerData++;
                        }
                        else
                        {
                            _logger.LogError($"[Proto] [{payload.Uuid}] Malformed GetPlayerOutProto");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode GetPlayerOutProto: {ex}");
                    }
                    break;

                case Method.GetHoloholoInventory:
                    try
                    {
                        var ghi = GetHoloholoInventoryOutProto.Parser.ParseFrom(Convert.FromBase64String(data));
                        if (ghi?.Success == true)
                        {
                            if (ghi.InventoryDelta.InventoryItem?.Count > 0)
                            {
                                // TODO: Publish with redis
                                inventory.Add(ghi.InventoryDelta);
                            }
                        }
                        else
                        {
                            _logger.LogError($"[Proto] [{payload.Uuid}] Malformed GetHoloholoInventoryOutProto");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode GetHoloholoInventoryOutProto: {ex}");
                    }
                    break;

                case Method.FortSearch:
                    try
                    {
                        var fsr = FortSearchOutProto.Parser.ParseFrom(Convert.FromBase64String(data));
                        if (fsr != null)
                        {
                            if (fsr.ChallengeQuest?.Quest != null)
                            {
                                await PushData(RedisChannels.ProtoQuest, new
                                {
                                    raw = data,
                                });

                                quests++;
                            }
                            //fortSearch.Add(fsr);
                            fortSearch++;
                        }
                        else
                        {
                            _logger.LogError($"[Proto] [{payload.Uuid}] Malformed FortSearchOutProto");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode FortSearchOutProto: {ex}");
                    }
                    break;

                case Method.Encounter:
                    isEmptyGmo   = false;
                    isInvalidGmo = false;
                    try
                    {
                        if (payload.Level >= 30)
                        {
                            var er = EncounterOutProto.Parser.ParseFrom(Convert.FromBase64String(data));
                            if (er?.Status == EncounterOutProto.Types.Status.EncounterSuccess)
                            {
                                await PushData(RedisChannels.ProtoEncounter, new
                                {
                                    data     = er,
                                    username = payload.Username,
                                });

                                encounters++;
                            }
                            else if (er == null)
                            {
                                _logger.LogError($"[Proto] [{payload.Uuid}] Malformed EncounterOutProto");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode EncounterOutProto: {ex}");
                    }
                    break;

                case Method.FortDetails:
                    try
                    {
                        var fdr = FortDetailsOutProto.Parser.ParseFrom(Convert.FromBase64String(data));
                        if (fdr != null)
                        {
                            fortDetails.Add(fdr);
                            //fortDetails++;
                            // TODO: Publish with redis
                            //await PublishData(RedisChannels.Fort, fdr);
                        }
                        else
                        {
                            _logger.LogError($"[Proto] [{payload.Uuid}] Malformed FortDetailsOutProto");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode FortDetailsOutProto: {ex}");
                    }
                    break;

                case Method.GetMapObjects:
                    containsGmo = true;
                    try
                    {
                        var gmo = GetMapObjectsOutProto.Parser.ParseFrom(Convert.FromBase64String(data));
                        if (gmo != null)
                        {
                            isInvalidGmo = false;
                            var mapCellsNew = gmo.MapCell;

                            if (mapCellsNew.Count == 0)
                            {
                                //_logger.LogDebug($"[Proto] [{payload.Uuid}] Map cells are empty");
                                //return null;
                            }

                            // Check if we're within the same cell, if so then we are within the target distance
                            if (!inArea && targetKnown && mapCellsNew.Select(x => x.S2CellId).Contains(targetCellId.Id))
                            {
                                inArea = true;
                            }

                            foreach (var mapCell in mapCellsNew)
                            {
                                cells.Add(mapCell.S2CellId);
                                await PushData(RedisChannels.ProtoCell, mapCell.S2CellId);

                                var tsMs = mapCell.AsOfTimeMs;
                                foreach (var wild in mapCell.WildPokemon)
                                {
                                    await PushData(RedisChannels.ProtoWildPokemon, new
                                    {
                                        cell         = mapCell.S2CellId,
                                        data         = wild,
                                        timestamp_ms = tsMs,
                                        username     = payload.Username,
                                    });

                                    wildPokemon++;
                                }
                                foreach (var nearby in mapCell.NearbyPokemon)
                                {
                                    await PushData(RedisChannels.ProtoNearbyPokemon, new
                                    {
                                        cell         = mapCell.S2CellId,
                                        data         = nearby,
                                        timestamp_ms = tsMs,
                                        username     = payload.Username,
                                    });

                                    nearbyPokemon++;
                                }
                                foreach (var fort in mapCell.Fort)
                                {
                                    await PushData(RedisChannels.ProtoFort, new
                                    {
                                        cell = mapCell.S2CellId,
                                        data = fort,
                                    });

                                    forts++;
                                }
                            }
                            foreach (var weather in gmo.ClientWeather)
                            {
                                await PushData(RedisChannels.ProtoWeather, new Weather(weather));

                                clientWeather++;
                            }
                            if (wildPokemon == 0 && nearbyPokemon == 0 && forts == 0 && quests == 0)
                            {
                                foreach (var cellId in cells)
                                {
                                    if (!_emptyCells.ContainsKey(cellId))
                                    {
                                        _emptyCells.Add(cellId, 1);
                                    }
                                    else
                                    {
                                        _emptyCells[cellId]++;
                                    }
                                    if (_emptyCells[cellId] == 3)
                                    {
                                        _logger.LogWarning($"[Proto] [{payload.Uuid}] Cell {cellId} was empty 3 times in a row, assuming empty...");
                                        await PushData(RedisChannels.ProtoCell, cellId);
                                    }
                                }
                                _logger.LogDebug($"[Proto] [{payload.Uuid}] GMO is empty");
                                isEmptyGmo = true;
                            }
                            else
                            {
                                cells.ForEach(cellId => _emptyCells[cellId] = 0);
                                isEmptyGmo = false;
                            }
                        }
                        else
                        {
                            _logger.LogError($"[Proto] [{payload.Uuid}] Malformed GetMapObjectsOutProto");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode GetMapObjectsOutProto: {ex}");
                    }
                    break;

                case Method.GymGetInfo:
                    try
                    {
                        var ggi = GymGetInfoOutProto.Parser.ParseFrom(Convert.FromBase64String(data));
                        if (ggi != null)
                        {
                            if (ggi.GymStatusAndDefenders == null)
                            {
                                ConsoleExt.WriteWarn($"[DataConsumer] Invalid GymStatusAndDefenders provided, skipping...\n: {ggi}");
                                continue;
                            }
                            var fortId       = ggi.GymStatusAndDefenders.PokemonFortProto.FortId;
                            var gymDefenders = ggi.GymStatusAndDefenders.GymDefender;
                            if (gymDefenders == null)
                            {
                                continue;
                            }

                            foreach (var gymDefender in gymDefenders)
                            {
                                if (gymDefender.TrainerPublicProfile != null)
                                {
                                    await PushData(RedisChannels.ProtoGymTrainer, new Trainer(gymDefender));
                                }
                                if (gymDefender.MotivatedPokemon != null)
                                {
                                    await PushData(RedisChannels.ProtoGymDefender, new GymDefender(fortId, gymDefender));
                                }
                            }
                        }
                        else
                        {
                            _logger.LogError($"[Proto] [{payload.Uuid}] Malformed GymGetInfoOutProto");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode GymGetInfoOutProto: {ex}");
                    }
                    break;

                //case Method.Unset:
                default:
                    _logger.LogDebug($"[Proto] [{payload.Uuid}] Invalid method or data provided. {method}:{data}");
                    break;
                }
            }

            Coordinate pokemonCoords = null;

            /*
             * if (targetCoord != null)
             * {
             *  foreach (var fort in forts)
             *  {
             *      if (!inArea)
             *      {
             *          var coord = new Coordinate(fort.data.Latitude, fort.data.Longitude);
             *          if (coord.DistanceTo(targetCoord) <= payload.TargetMaxDistance)
             *          {
             *              inArea = true;
             *          }
             *      }
             *  }
             * }
             * if (targetCoord != null || payload.PokemonEncounterId != null)
             * {
             *  foreach (var pokemon in wildPokemons)
             *  {
             *      WildPokemonProto wild = (WildPokemonProto)pokemon.data;
             *      if (targetCoord != null)
             *      {
             *          if (pokemonCoords != null && inArea)
             *          {
             *              break;
             *          }
             *
             *          if (!inArea)
             *          {
             *              var coord = new Coordinate(wild.Latitude, wild.Longitude);
             *              if (coord.DistanceTo(targetCoord) <= payload.TargetMaxDistance)
             *              {
             *                  inArea = true;
             *              }
             *          }
             *      }
             *      if (!string.IsNullOrEmpty(payload.PokemonEncounterId))
             *      {
             *          if (pokemonCoords != null && inArea)
             *          {
             *              break;
             *          }
             *
             *          if (pokemonCoords == null)
             *          {
             *              if (string.Compare(wild.EncounterId.ToString(), payload.PokemonEncounterId, true) == 0)
             *              {
             *                  pokemonCoords = new Coordinate(wild.Latitude, wild.Longitude);
             *              }
             *          }
             *      }
             *  }
             * }
             * if (targetCoord != null && !inArea)
             * {
             *  foreach (var cell in cells)
             *  {
             *      if (inArea)
             *      {
             *          break;
             *      }
             *
             *      var s2cell = new S2Cell(new S2CellId(cell));
             *      var latlng = new S2LatLng(s2cell.Center);
             *      var coord = new Coordinate(latlng.LatDegrees, latlng.LngDegrees);
             *      if (coord.DistanceTo(targetCoord) <= Math.Max(payload.TargetMaxDistance ?? 250, 100))
             *      {
             *          inArea = true;
             *      }
             *  }
             * }
             */

            stopwatch.Stop();

            var response = new ProtoResponse
            {
                Status = "ok",
                Data   = new ProtoDataDetails
                {
                    Nearby             = nearbyPokemon,
                    Wild               = wildPokemon,
                    Forts              = forts,
                    Quests             = quests,
                    FortSearch         = fortSearch,
                    Encounters         = encounters,
                    Level              = payload.Level,
                    OnlyEmptyGmos      = containsGmo && isEmptyGmo,
                    OnlyInvalidGmos    = containsGmo && isInvalidGmo,
                    ContainsGmos       = containsGmo,
                    InArea             = inArea,
                    LatitudeTarget     = targetCoord?.Latitude,
                    LongitudeTarget    = targetCoord?.Longitude,
                    PokemonLatitude    = pokemonCoords?.Latitude,
                    PokemonLongitude   = pokemonCoords?.Longitude,
                    PokemonEncounterId = payload.PokemonEncounterId,
                },
            };

            _logger.LogInformation($"[{payload.Uuid}] {response.ToJson()} parsed in {stopwatch.Elapsed.TotalSeconds}s");
            return(response);
        }
        /**
         * <summary>
         * Converts protocol object into object.</summary>
         *
         * <param name="val">Protocol message object to convert into value.</param>
         * <returns>Recovered object.</returns>
         */
        public static Object WrapObject(ObjectWrapper val)
        {
            byte[] bin = val.Binary.ToByteArray();

            // Primitives.

            switch (val.Type)
            {
            case ObjectWrapperType.NONE:
                return(null);

            case ObjectWrapperType.BOOL:
                Dbg.Assert(bin.Length == 1, "bin.Length == 1");

                return(bin[0] != 0);

            case ObjectWrapperType.BYTE:
                Dbg.Assert(bin.Length == 1, "bin.Length == 1");

                return(bin[0]);

            case ObjectWrapperType.SHORT:
                Dbg.Assert(bin.Length == 2, "bin.Length == 2");

                return(U.BytesToInt16(bin, 0));

            case ObjectWrapperType.INT32:
                Dbg.Assert(bin.Length == 4, "bin.Length == 4");

                return(U.BytesToInt32(bin, 0));

            case ObjectWrapperType.INT64:
                Dbg.Assert(bin.Length == 8, "bin.Length == 8");

                return(U.BytesToInt64(bin, 0));

            case ObjectWrapperType.FLOAT:
                Dbg.Assert(bin.Length == 4, "bin.Length == 4");

                return(U.BytesToSingle(bin, 0));

            case ObjectWrapperType.DOUBLE:
                Dbg.Assert(bin.Length == 8, "bin.Length == 8");

                return(U.BytesToDouble(bin, 0));

            case ObjectWrapperType.BYTES:
                return(bin);

            case ObjectWrapperType.UUID:
                return(WrapGuid(val.Binary));

            case ObjectWrapperType.STRING:
                return(val.Binary.ToStringUtf8());

            case ObjectWrapperType.COLLECTION:
                return(WrapCollection(Collection.ParseFrom(bin)));

            case ObjectWrapperType.MAP:
                return(WrapMap(Map.ParseFrom(bin)));

            case ObjectWrapperType.AUTH_REQUEST:
                return(WrapAuthRequest(ProtoRequest.ParseFrom(bin)));

            case ObjectWrapperType.CACHE_REQUEST:
                return(WrapCacheRequest(ProtoRequest.ParseFrom(bin)));

            case ObjectWrapperType.TASK_REQUEST:
                return(WrapTaskRequest(ProtoRequest.ParseFrom(bin)));

            case ObjectWrapperType.LOG_REQUEST:
                return(WrapLogRequest(ProtoRequest.ParseFrom(bin)));

            case ObjectWrapperType.TOPOLOGY_REQUEST:
                return(WrapTopologyRequest(ProtoRequest.ParseFrom(bin)));

            case ObjectWrapperType.RESPONSE:
                return(WrapResponse(ProtoResponse.ParseFrom(bin)));

            case ObjectWrapperType.NODE_BEAN:
                return(WrapNode(ProtoNodeBean.ParseFrom(bin)));

            case ObjectWrapperType.TASK_BEAN:
                return(WrapTaskResult(ProtoTaskBean.ParseFrom(bin)));

            default:
                throw new ArgumentException("Failed to deserialize object (object deserialization" +
                                            " of given type is not supported): " + val.Type);
            }
        }