/// <summary> /// Сообщить пользователю о новом запросе в друзья. /// </summary> /// <param name="userId">Идентификатор пользователя, которому поступил запрос в друзья.</param> /// <param name="request">Поступивший запрос в друзья.</param> public void NotifyUserAboutFriendRequest(Guid userId, FriendRequest request) { ComplexAccountState targetUserState = AccountStateService.Instance.GetStatusOf(userId); if (targetUserState == null) { throw new InvalidOperationException($"Got null target user state"); } if (targetUserState.OnlineStatus == AccountOnlineStatus.Online) { using (IHttpActor actor = new HttpActor()) { string requesterAddress = $"{ targetUserState.Address }{ Subroutes.NotifyClient.NotifyFriendRequest }"; actor.SetRequestAddress(requesterAddress); actor.AddHeader(FreengyHeaders.Server.ServerSessionTokenHeaderName, targetUserState.ClientAuth.ServerToken); var result = actor.PostAsync <FriendRequest, FriendRequest>(request).Result; string resultMessage = result.Success ? "Success" : result.Error.Message; ( $"Sent friendrequest notification from '{ request.RequesterAccount.Name }' to " + $"{ request.TargetAccount.Name }:{ Environment.NewLine } { resultMessage }" ) .WriteToConsole(ConsoleColor.DarkBlue); } } }
private dynamic OnLoginRequest(dynamic arg) { //logInRequest = new SerializeHelper().DeserializeObject<LoginModel>(Request.Body); bool isLoggingIn = logInRequest.IsLoggingIn; string direction = isLoggingIn ? "in" : "out"; $"Got '{ logInRequest.Account.Name }' log { direction } request".WriteToConsole(); string userAddress = GetUserAddress(Request); if (string.IsNullOrEmpty(userAddress)) { $"Client { logInRequest.Account.Name } didnt attach his address".WriteToConsole(); throw new InvalidOperationException("Client address must be set in headers"); } ComplexAccountState accountState = LogInOrOut(logInRequest, userAddress); $"'{ logInRequest.Account.Name } [{ userAddress }]' log { direction } result: { accountState.OnlineStatus }".WriteToConsole(); // сложный аккаунт нужно упростить, иначе при дефолтной сериализации получается бесконечная рекурсия ссылающихся друг на друга свойств var jsonResponse = new JsonResponse <AccountStateModel>(accountState.ToSimple(), new DefaultJsonSerializer()); SetAuthHeaders(jsonResponse.Headers, accountState.ClientAuth); SetNextPasswordData(logInRequest); $"Logged '{ logInRequest.Account.Name }' { direction }".WriteToConsole(isLoggingIn ? ConsoleColor.Green : ConsoleColor.Magenta); return(jsonResponse); }
/// <summary> /// Notify user about appeared reaction for his friendrequest. /// </summary> /// <param name="requesterId"></param> /// <param name="requestReply"></param> public void NotifyUserAboutFriendReply(Guid requesterId, FriendRequestReply requestReply) { ComplexAccountState requesterState = AccountStateService.Instance.GetStatusOf(requesterId); if (requesterState == null) { throw new InvalidOperationException($"Got null requester state"); } if (requesterState.OnlineStatus == AccountOnlineStatus.Online) { using (IHttpActor actor = new HttpActor()) { string requesterAddress = $"{requesterState.Address}{Subroutes.NotifyClient.NotifyFriendRequestState}"; actor.SetRequestAddress(requesterAddress); actor.AddHeader(FreengyHeaders.Server.ServerSessionTokenHeaderName, requesterState.ClientAuth.ServerToken); var result = actor.PostAsync <FriendRequestReply, FriendRequestReply>(requestReply).Result; string resultMessage = result.Success ? "Success" : result.Error.Message; $"Sent friendrequest reply '{ requestReply.Reaction }' to { requesterState.ComplexAccount.Name }:{ Environment.NewLine } { resultMessage }" .WriteToConsole(ConsoleColor.Blue); } } }
/// <summary> /// Check if user is authorized. /// </summary> /// <param name="requesterId">Target use identifier.</param> /// <param name="requesterToken">Target user session token.</param> /// <returns>True if user is authorized.</returns> public bool IsAuthorized(Guid requesterId, string requesterToken) { ComplexAccountState requesterAccountState = GetStatusOf(requesterId); bool isAuthorized = requesterAccountState != null && requesterAccountState.OnlineStatus != AccountOnlineStatus.Offline && requesterAccountState.ClientAuth.ClientToken == requesterToken; return(isAuthorized); }
/// <summary> /// Преобразовать сложную серверную модель в простую для отправки юзеру. /// </summary> /// <param name="complexModel"></param> /// <returns></returns> public static AccountStateModel ToSimple(this ComplexAccountState complexModel) { var simpleModel = new AccountStateModel { Address = complexModel.Address, OnlineStatus = complexModel.OnlineStatus, AccountModel = complexModel.ComplexAccount.ToSimpleModel() }; return(simpleModel); }
private static void NotifyFriendAboutUser(ComplexAccountState userState, ComplexAccountState friendAccountState) { using (IHttpActor actor = new HttpActor()) { string targetFriendAddress = $"{friendAccountState.Address}{Subroutes.NotifyClient.NotifyFriendState}"; actor.SetRequestAddress(targetFriendAddress); actor.AddHeader(FreengyHeaders.Server.ServerSessionTokenHeaderName, friendAccountState.ClientAuth.ServerToken); var result = actor.PostAsync <AccountStateModel, AccountStateModel>(userState.ToSimple()).Result; } }
/// <summary> /// Send informing message to a friend about user account state change. /// </summary> /// <param name="userState"></param> /// <param name="friendId"></param> public void NotifyFriendAboutUserChange(Guid friendId, ComplexAccountState userState) { ComplexAccountState friendAccountState = AccountStateService.Instance.GetStatusOf(friendId); if (friendAccountState == null) { throw new InvalidOperationException($"Got null friend state"); } if (friendAccountState.OnlineStatus == AccountOnlineStatus.Online) { NotifyFriendAboutUser(userState, friendAccountState); } }
public void NotifyUserOfExpAddition(ComplexAccountState userState, GainExpModel expModel) { using (IHttpActor actor = new HttpActor()) { //TODO добавить начисление экспы string address = $"{userState.Address}{Subroutes.NotifyClient.SyncExp}"; actor.SetRequestAddress(address); actor.AddHeader(FreengyHeaders.Server.ServerSessionTokenHeaderName, userState.ClientAuth.ServerToken); $"Giving { expModel.Amount } exp to { userState.ComplexAccount.Name } for { expModel.GainReason }" .WriteToConsole(ConsoleColor.Yellow); var result = actor.PostAsync <GainExpModel, GainExpModel>(expModel).Result; } }
private void CacheNewState(UserAccountModel accountModel, string address) { accountModel.LastLogInTime = DateTime.Now; var newState = new AccountStateModel { Address = address, AccountModel = accountModel, OnlineStatus = AccountOnlineStatus.Offline }; var complexState = new ComplexAccountState(newState); complexState.ClientAuth.ClientToken = CreateNewToken(); complexState.ClientAuth.ServerToken = CreateNewToken(); accountStates.Add(complexState); }
private static ComplexAccountState LogInOrOut(LoginModel logInRequest, string userAddress) { bool isLoggingIn = logInRequest.IsLoggingIn; var stateService = AccountStateService.Instance; var targetStatus = isLoggingIn ? AccountOnlineStatus.Online : AccountOnlineStatus.Offline; ComplexAccountState complexAccountState = isLoggingIn ? stateService.LogIn(logInRequest.Account.Name, userAddress) : stateService.LogOut(logInRequest.Account.Name); if (complexAccountState.OnlineStatus == targetStatus) { Task.Run(() => UserInformerService.Instance.NotifyAllFriendsAboutUser(complexAccountState)); } return(complexAccountState); }
/// <summary> /// Log the user in. /// </summary> /// <param name="userName">User account name.</param> /// <param name="userAddress">User address.</param> /// <returns>Account state model and user authentication.</returns> public ComplexAccountState LogIn(string userName, string userAddress) { ComplexAccountState accountState = GetStatusOf(userName); if (accountState == null) { throw new UserNotFoundException(userName); } accountState.Address = userAddress; accountState.ClientAuth.ClientToken = CreateNewToken(); accountState.ClientAuth.ServerToken = CreateNewToken(); accountState.ComplexAccount.LastLogInTime = DateTime.Now; accountState.OnlineStatus = AccountOnlineStatus.Online; AccountDbInteracter.Instance.AddOrUpdate(accountState.ComplexAccount); return(accountState); }
private dynamic OnSyncAccountRequest(dynamic arg) { var stateService = AccountStateService.Instance; Guid senderId = Request.Headers.GetClientId(); SessionAuth clientAuth = Request.Headers.GetSessionAuth(); if (!stateService.IsAuthorized(senderId, clientAuth.ClientToken)) { throw new ClientNotAuthorizedException(senderId); } ComplexAccountState currentState = AccountStateService.Instance.GetStatusOf(senderId); var responce = new JsonResponse <AccountStateModel>(currentState.ToSimple(), new DefaultJsonSerializer()); responce.Headers.Add(FreengyHeaders.Server.ServerSessionTokenHeaderName, currentState.ClientAuth.ServerToken); return(responce); }
/// <summary> /// Отправить уведомления всем друзьям юзера о любом изменении состояния его аккаунта. /// </summary> /// <param name="userState">Модель состояния аккаунта юзера.</param> public void NotifyAllFriendsAboutUser(ComplexAccountState userState) { var outFriendIds = FriendshipService.Instance.FindByInvoker(userState.ComplexAccount.Id) .Select(friendship => friendship.AcceptorAccountId); var inFriendIds = FriendshipService.Instance.FindByAcceptor(userState.ComplexAccount.Id) .Select(friendship => friendship.ParentId); var allFriendIds = inFriendIds.Union(outFriendIds); IEnumerable <ComplexAccountState> allFriendStates = allFriendIds.Select(friendId => AccountStateService.Instance.GetStatusOf(friendId)); Parallel.ForEach(allFriendStates, friendState => { if (friendState.OnlineStatus == AccountOnlineStatus.Online) { NotifyFriendAboutUser(userState, friendState); } }); }
private dynamic ProcessSearchFriends(SearchRequest searchRequest, SerializeHelper helper) { var registrationService = RegistrationService.Instance; var friendService = FriendshipService.Instance; ComplexUserAccount senderAcc = registrationService.FindById(searchRequest.SenderId); if (senderAcc == null) { return($"Account id {searchRequest.SenderId} is not registered"); } friendService.UpdateFriendships(senderAcc); var stateService = AccountStateService.Instance; AccountStateModel AccountStateSelector(FriendshipModel friendship) { Guid friendId = friendship.AcceptorAccountId == searchRequest.SenderId ? friendship.ParentId : friendship.AcceptorAccountId; ComplexAccountState complexAccountState = stateService.GetStatusOf(friendId); if (complexAccountState == null) { throw new InvalidOperationException($"Found null state pair for account id { friendId }"); } return(complexAccountState.ToSimple()); } IEnumerable <AccountStateModel> friendStateModels = senderAcc.Friendships.Select(AccountStateSelector); var serialized = helper.Serialize(friendStateModels); return(serialized); }
private static void GetClientState(ComplexAccountState complexAccountState) { using (var actor = new HttpActor()) { string address = $"{complexAccountState.Address}{Subroutes.NotifyClient.RequestUserState}"; actor .SetRequestAddress(address) .AddHeader(FreengyHeaders.Server.ServerSessionTokenHeaderName, complexAccountState.ClientAuth.ServerToken); HttpResponseMessage responce = null; actor .GetAsync() .ContinueWith(task => { if (task.Exception != null) { responce = null; complexAccountState.FailResponceCount++; logger.Error(task.Exception.GetReallyRootException(), "Failed to get async response"); } else { responce = task.Result.Value; } }) .Wait(); if (responce?.StatusCode != HttpStatusCode.OK) { complexAccountState.FailResponceCount++; string message = $"Client {complexAccountState.ComplexAccount.Name} replied wrong status '{ responce?.StatusCode }'. " + $"Count: {complexAccountState.FailResponceCount}"; message.WriteToConsole(); } } }