public async Task <IActionResult> GetCharacterSessionDataByAccount([FromRoute(Name = "id")] int accountId)
        {
            if (!await CharacterSessionRepository.AccountHasActiveSession(accountId)
                .ConfigureAwait(false))
            {
                return(Ok(new CharacterSessionDataResponse(CharacterSessionDataResponseCode.NoSessionAvailable)));
            }

            //TODO: There is a dangerous race condition where the zoneserver can release a session inbetween the last databse call and the characte rsessin data call
            //This is unlikely to be exploitably but it is dangerous
            ProjectVersionStage.AssertBeta();

            try
            {
                ClaimedSessionsModel claimedSessionsModel = await CharacterSessionRepository.RetrieveClaimedSessionByAccountId(accountId)
                                                            .ConfigureAwait(false);

                return(Ok(new CharacterSessionDataResponse(claimedSessionsModel.Session.ZoneId, claimedSessionsModel.CharacterId)));
            }
            catch (Exception e)
            {
                if (Logger.IsEnabled(LogLevel.Error))
                {
                    Logger.LogError($"Failed to query for character session data for active character session on AccountId: {accountId} Exception: {e.GetType().Name} - {e.Message}");
                }

                return(Ok(new CharacterSessionDataResponse(CharacterSessionDataResponseCode.GeneralServerError)));
            }
        }
        [NoResponseCache]         //we don't want to cache this, if they are removed from a guild then we want this reflected immediately or they may be taking in a guild chat they aren't apart of due to a race condition
        public async Task <IActionResult> GetCharacterMembershipGuildStatus([FromRoute(Name = "id")] int characterId, [NotNull][FromServices] IGuildCharacterMembershipRepository guildCharacterMembershipRepository)
        {
            if (guildCharacterMembershipRepository == null)
            {
                throw new ArgumentNullException(nameof(guildCharacterMembershipRepository));
            }

            //If guild membership repo doesn't have the character id as an entry then it means there is no guild associated with them.
            if (!(await guildCharacterMembershipRepository.ContainsAsync(characterId).ConfigureAwait(false)))
            {
                return(Json(new CharacterGuildMembershipStatusResponse(CharacterGuildMembershipStatusResponseCode.NoGuild)));
            }

            //TODO: There is technically a race condition here. They could have just been kicked from a guild but the cached model may say they are in a guild
            //this could result in incredibly rare cases of a kicked member joining at the perfect moment who can talk in guild chat but no longer be in the guild
            ProjectVersionStage.AssertBeta();

            //Otherwise, they are in a guild
            try
            {
                return(Json(new CharacterGuildMembershipStatusResponse((await guildCharacterMembershipRepository.RetrieveAsync(characterId).ConfigureAwait(false)).GuildId)));
            }
            catch (Exception e)
            {
                if (Logger.IsEnabled(LogLevel.Error))
                {
                    Logger.LogError($"Encountered error in expected guild membership status request. CharacterId: {characterId} Reason: {e.Message}\n\nStack: {e.StackTrace}");
                }

                return(Json(new CharacterGuildMembershipStatusResponse(CharacterGuildMembershipStatusResponseCode.GeneralServerError)));
            }
        }
Beispiel #3
0
        private async Task <string> GetSocialServiceAuthorizationToken([JetBrains.Annotations.NotNull] IAuthenticationService authService)
        {
            if (authService == null)
            {
                throw new ArgumentNullException(nameof(authService));
            }

            //TODO: Don't hardcode the authentication details
            ProjectVersionStage.AssertBeta();
            //TODO: Handle errors
            return((await authService.TryAuthenticate(new AuthenticationRequestModel("SocialService", "Test69!"))).AccessToken);
        }
Beispiel #4
0
        /// <inheritdoc />
        public bool Destroy(NetworkEntityGuid obj)
        {
            //This removes the world entity from it's special collection AND removes it from the relevant map
            GameObject rootEntityGameObject = GuidToGameObjectMappable[obj];

            GameObjectToEntityMap.ObjectToEntityMap.Remove(rootEntityGameObject);
            GameObject.Destroy(rootEntityGameObject);

            foreach (var removable in RemovableCollections)
            {
                ProjectVersionStage.AssertBeta();
                //TODO: Should we check this?
                removable.RemoveEntityEntry(obj);
            }

            return(true);
        }
Beispiel #5
0
        /// <inheritdoc />
        public string GetUserId(HubConnectionContext connection)
        {
            //TODO: This could fail if they don't put the header in
            ProjectVersionStage.AssertBeta();

            //We trust the client to send us a header that contains the character id
            //You may be freaking out, but we aren't taking the client at face value here.
            //This is and MUST be verified in the Hub's OnConnected method to prevent
            //malicious uses from spoofing.
            int characterId = connection.GetHttpContext().Request.GetTypedHeaders().Get <int>(SocialNetworkConstants.CharacterIdRequestHeaderName);

            if (characterId <= 0)
            {
                if (Logger.IsEnabled(LogLevel.Warning))
                {
                    Logger.LogWarning($"Encountered client: {ClaimsReader.GetUserName(connection.User)}:{ClaimsReader.GetUserId(connection.User)} with invalid characterId {characterId}");
                }

                connection.Abort();
                return(String.Empty);
            }

            return(characterId.ToString());
        }
 static GlobalEntityResourceLockingPolicy()
 {
     //TODO: There is kinda data race here, we need to a global for this collection too to prevent it being modidified before the lock occurs inbetween lookup
     ProjectVersionStage.AssertBeta();
 }
        /// <inheritdoc />
        protected override void HandleEvent(SessionStatusChangeEventArgs args)
        {
            //The reason this system is so simple is basically the other threads just need a way to queue up
            //cleanup on the main thread. The reasoning being that GameObject destruction needs to occur
            //as well as collection modification needs to happen, and the main thread is where the majority if collection
            //iteration should be taking place.

            //it's possible that we're attempting to clean up an entity for a connection
            //that doesn't have one. This can happen if they disconnect during claim or before claim.
            if (!ConnectionToEntityMap.ContainsKey(args.Details.ConnectionId))
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"ConnectionId: {args.Details.ConnectionId} had entity exit cleanup but contained no entity. This is not an error.");
                }

                //We may be in this method, handling cleanup for an entity that has a claim going on
                //in the claim handler, but is still awaiting a response for character data from the gameserver. MEANING we could end up with hanging entites.
                //This is not mitgated here, but inside the player entery factory
                //which SHOULD make a check for the connection still being valid AFTER creation
                //Not before because we still want to create, and then deconstruct. Reasoning being that gameserver session
                //will still be claimed unless we go through th cleanup process.
                return;
            }

            NetworkEntityGuid entityGuid = ConnectionToEntityMap[args.Details.ConnectionId];

            //First we need to save the entity data since it DOES own an entity.
            UnityExtended.UnityMainThreadContext.PostAsync(async() =>
            {
                //Nothing should really be taking a write lock, except session entry I guess.
                //This could be bad
                //We no longer do a read lock because Player Entry is actually trying to
                //aquire a write lock and this could block if for a LONG time. KILLING the server basically
                //So, we just assume it's safe to save entity data. Even if it's changing mid save like this.
                //using(await LockingPolicy.ReaderLockAsync(null, CancellationToken.None))
                {
                    //We know that an entity exists, so we must save it. Before we even queue it up for removal.
                    await EntitySaver.SaveAsync(entityGuid)
                    .ConfigureAwait(true);
                }

                //At this point we MUST write lock, since we are actually modifying entity collections and entries
                using (await LockingPolicy.WriterLockAsync(null, CancellationToken.None))                //we can use async await since we're in a async context too!! Which is good.
                {
                    SessionDestructor.Destroy(new PlayerSessionDeconstructionContext(args.Details.ConnectionId));
                }

                //TODO: We have a big problem if this fails, we need to handle it properly. Otherwise the player cannot log in again.\
                ProjectVersionStage.AssertBeta();

                //We need to async send the release request, a very important part of session cleanup.
                //if this failes we have BIG problems. BIG BIG BIG.
                await ZoneClientGameService.ReleaseActiveSession(entityGuid.EntityId)
                .ConfigureAwait(false);

                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Cleaned up Entity Player Session for ConnectionId: {args.Details.ConnectionId} Guid: {entityGuid} {entityGuid.EntityType}:{entityGuid.EntityId}");
                }
            });
        }