public void Execute(bool force) { if (RefreshStatus == WebCallRefreshStatus.WaitingForRefreshCallback) { if (!force) { return; } RefreshStatus = WebCallRefreshStatus.NotRefreshing; } if (force) { this.OnUnqueued(this, new WebCallUnqueuedEventArgs()); } SessionDocument sessionDocument = database.GetSessionDocument(swid); if (!force && sessionDocument != null && sessionDocument.ProtocolVersion != 3) { this.OnUnauthorized(this, new WebCallUnauthorizedEventArgs("UNAUTHORIZED_MIX_SESSION")); return; } numAttempts++; bodyBytes = Encoding.UTF8.GetBytes(body); bodyBytes = WebCallEncryptor.Encrypt(bodyBytes); wwwCall = wwwCallFactory.Create(uri, method, bodyBytes, headers, latencyWwwCallTimeout, maxWwwCallTimeout); wwwCall.OnDone += HandleWwwDone; wwwCall.Execute(); logger.Debug(HttpLogBuilder.BuildRequestLog(wwwCall.RequestId, uri, method, headers, body)); }
private static void HandleGetStateSuccess(AbstractLogger logger, IEpochTime epochTime, IDatabase database, IUserDatabase userDatabase, INotificationQueue notificationQueue, GetStateResponse response, IMixWebCallFactory mixWebCallFactory, Action <GetStateResponse> successCallback, Action failureCallback) { try { if (ValidateResponse(response)) { epochTime.ReferenceTime = response.Timestamp.Value; database.SetServerTimeOffsetMillis((long)epochTime.Offset.TotalMilliseconds); logger.Debug("New time offset: " + epochTime.Offset); successCallback(response); notificationQueue.LatestSequenceNumber = response.NotificationSequenceCounter.Value; } else { logger.Critical("Error validating get state response: " + JsonParser.ToJson(response)); failureCallback(); notificationQueue.Clear(); } } catch (Exception ex) { logger.Critical("Unhandled exception: " + ex); failureCallback(); notificationQueue.Clear(); } }
public IInternalSession Create(string swid) { byte[] localStorageKey = keychain.LocalStorageKey; IDocumentCollection <AlertDocument> documentCollection = GetDocumentCollection <AlertDocument>(swid, "Alerts", databaseDirectoryCreator, localStorageKey, documentCollectionFactory); IDocumentCollection <FriendDocument> documentCollection2 = GetDocumentCollection <FriendDocument>(swid, "Friends", databaseDirectoryCreator, localStorageKey, documentCollectionFactory); IDocumentCollection <FriendInvitationDocument> documentCollection3 = GetDocumentCollection <FriendInvitationDocument>(swid, "FriendInvitations", databaseDirectoryCreator, localStorageKey, documentCollectionFactory); IDocumentCollection <UserDocument> documentCollection4 = GetDocumentCollection <UserDocument>(swid, "Users", databaseDirectoryCreator, localStorageKey, documentCollectionFactory); databaseCorruptionHandler.Add(documentCollection4); string dirPath = BuildDocCollectionPath(databaseDirectoryCreator, swid); UserDatabase userDatabase = new UserDatabase(documentCollection, documentCollection2, documentCollection3, documentCollection4, localStorageKey, dirPath, epochTime, documentCollectionFactory, databaseCorruptionHandler, coroutineManager); database.ClearServerTimeOffsetMillis(); epochTime.OffsetMilliseconds = database.GetServerTimeOffsetMillis() ?? 0; logger.Debug("Initial time offset: " + epochTime.Offset); SessionDocument sessionDocument = database.GetSessionDocument(swid); keychain.PushNotificationKey = sessionDocument.CurrentSymmetricEncryptionKey; IWebCallEncryptor webCallEncryptor = webCallEncryptorFactory.Create(sessionDocument.CurrentSymmetricEncryptionKey, sessionDocument.SessionId); IGuestControllerClient guestControllerClient = guestControllerClientFactory.Create(swid); ISessionRefresher sessionRefresher = sessionRefresherFactory.Create(mixSessionStarter, guestControllerClient); IMixWebCallFactory mixWebCallFactory = mixWebCallFactoryFactory.Create(webCallEncryptor, swid, sessionDocument.GuestControllerAccessToken, sessionRefresher); guestControllerClient.OnAccessTokenChanged += delegate(object sender, AbstractGuestControllerAccessTokenChangedEventArgs e) { mixWebCallFactory.GuestControllerAccessToken = e.GuestControllerAccessToken; }; AssetLoader assetLoader = new AssetLoader(logger, wwwCallFactory); IList <IInternalFriend> friends = CreateFriends(userDatabase); AgeBandType ageBandType = AgeBandTypeConverter.Convert(sessionDocument.AgeBand); DateTime lastRefreshTime = epochTime.FromSeconds(sessionDocument.LastProfileRefreshTime); RegistrationProfile registrationProfile = new RegistrationProfile(logger, sessionDocument.DisplayNameText, sessionDocument.ProposedDisplayName, sessionDocument.ProposedDisplayNameStatus, sessionDocument.FirstName, sessionDocument.AccountStatus, lastRefreshTime, sessionDocument.CountryCode); GetStateResponseParser getStateResponseParser = new GetStateResponseParser(logger); NotificationPoller notificationPoller = new NotificationPoller(logger, mixWebCallFactory, notificationQueue, pollCountdownStopwatch, getStateResponseParser, epochTime, random, database, swid); DisplayName displayName = new DisplayName(sessionDocument.DisplayNameText); LocalUser localUser = new LocalUser(logger, displayName, swid, friends, ageBandType, database, userDatabase, registrationProfile, mixWebCallFactory, guestControllerClient, notificationQueue, encryptor, epochTime); Session session = new Session(logger, localUser, sessionDocument.GuestControllerAccessToken, sessionDocument.PushNotificationToken != null, notificationPoller, coroutineManager, database, userDatabase, guestControllerClient, mixWebCallFactory, epochTime, databaseCorruptionHandler, sessionStatus, keychain, getStateResponseParser, clientVersion, notificationQueue); try { NotificationHandler.Handle(notificationDispatcher, userDatabase, localUser, epochTime); notificationQueue.LatestSequenceNumber = sessionDocument.LatestNotificationSequenceNumber; IEnumerable <IncomingFriendInvitation> incomingFriendInvitations = GetIncomingFriendInvitations(userDatabase, localUser); foreach (IncomingFriendInvitation item in incomingFriendInvitations) { localUser.AddIncomingFriendInvitation(item); } IEnumerable <OutgoingFriendInvitation> outgoingFriendInvitations = GetOutgoingFriendInvitations(userDatabase, localUser); foreach (OutgoingFriendInvitation item2 in outgoingFriendInvitations) { localUser.AddOutgoingFriendInvitation(item2); } } catch (Exception) { session.Dispose(); throw; } return(session); }
public static void Resume(AbstractLogger logger, IGetStateResponseParser getStateResponseParser, IEpochTime epochTime, string clientVersion, INotificationQueue notificationQueue, IMixWebCallFactory mixWebCallFactory, IInternalLocalUser localUser, IDatabase database, IUserDatabase userDatabase, INotificationPoller notificationPoller, Action <IResumeSessionResult> callback) { epochTime.OffsetMilliseconds = database.GetServerTimeOffsetMillis() ?? 0; logger.Debug("Initial time offset: " + epochTime.Offset); SessionDocument sessionDocument = database.GetSessionDocument(localUser.Swid); long lastNotificationTime = sessionDocument.LastNotificationTime; StateGetter.GetState(logger, epochTime, clientVersion, database, userDatabase, notificationQueue, mixWebCallFactory, localUser.Swid, lastNotificationTime, delegate(GetStateResponse response) { HandleGetStateSuccess(logger, getStateResponseParser, response, mixWebCallFactory, localUser, userDatabase, notificationPoller, callback); }, delegate { callback(new ResumeSessionResult(success: false)); }); }
public static void Search(AbstractLogger logger, IMixWebCallFactory mixWebCallFactory, string displayName, IUserDatabase userDatabase, Action <IInternalUnidentifiedUser> successCallback, Action failureCallback) { try { DisplayNameSearchRequest displayNameSearchRequest = new DisplayNameSearchRequest(); displayNameSearchRequest.DisplayName = displayName; DisplayNameSearchRequest request = displayNameSearchRequest; IWebCall <DisplayNameSearchRequest, DisplayNameSearchResponse> webCall = mixWebCallFactory.SearchDisplaynamePost(request); webCall.OnResponse += delegate(object sender, WebCallEventArgs <DisplayNameSearchResponse> e) { DisplayNameSearchResponse response = e.Response; if (ValidateResponse(response)) { userDatabase.InsertUserDocument(new UserDocument { DisplayName = response.DisplayName, FirstName = response.FirstName, Swid = null, HashedSwid = null }); IInternalUnidentifiedUser obj = RemoteUserFactory.CreateUnidentifiedUser(response.DisplayName, response.FirstName, userDatabase); successCallback(obj); } else { logger.Critical("Failed to validate display name search response: " + JsonParser.ToJson(response)); failureCallback(); } }; webCall.OnError += delegate(object sender, WebCallErrorEventArgs e) { logger.Debug("Failed to find user: "******"Unhandled exception: " + arg); failureCallback(); } }
private static void HandleResult(WwwCallResult result, string log, byte[] bytes, Uri uri, StringBuilder timeoutLogs, int numAttempts, Action <LoadAssetResult> callback, Action <Uri, Action <LoadAssetResult>, StringBuilder, int> retry, AbstractLogger logger) { switch (result) { case WwwCallResult.Success: logger.Debug(log); callback(new LoadAssetResult(success: true, bytes)); break; case WwwCallResult.TooManyTimeoutsError: logger.Critical("Too many timeouts: " + uri.AbsoluteUri + "\nPrevious logs:\n" + timeoutLogs); callback(new LoadAssetResult(success: false, null)); break; case WwwCallResult.TooManyServerErrors: logger.Critical("Too many server errors:\n" + log); callback(new LoadAssetResult(success: false, null)); break; case WwwCallResult.RetryTimeout: logger.Error(log); timeoutLogs.Append(log); timeoutLogs.Append("\n\n"); retry(uri, callback, timeoutLogs, numAttempts + 1); break; case WwwCallResult.RetryServerError: logger.Error(log); retry(uri, callback, timeoutLogs, numAttempts + 1); break; case WwwCallResult.OfflineError: logger.Error(log); callback(new LoadAssetResult(success: false, null)); break; case WwwCallResult.ClientError: logger.Critical(log); callback(new LoadAssetResult(success: false, null)); break; } }
private void Load(Uri uri, Action <LoadAssetResult> callback, StringBuilder timeoutLogs, int numAttempts) { IWwwCall wwwCall = wwwCallFactory.Create(uri, HttpMethod.GET, null, emptyHeaders, 10000L, 30000L); logger.Debug(BuildRequestLog(uri, wwwCall.RequestId)); EventHandler <WwwDoneEventArgs> handleOnDone = null; handleOnDone = delegate { wwwCall.OnDone -= handleOnDone; Dictionary <string, string> responseHeaders = wwwCall.ResponseHeaders; uint statusCode = wwwCall.StatusCode; WwwCallResult result = GetResult(wwwCall.Error, statusCode, numAttempts); string log = BuildResponseLog(uri, result, responseHeaders, statusCode, wwwCall); byte[] responseBody = wwwCall.ResponseBody; HandleResult(result, log, responseBody, uri, timeoutLogs, numAttempts, callback, Load, logger); wwwCall.Dispose(); }; wwwCall.OnDone += handleOnDone; wwwCall.Execute(); }
public static IInternalPushNotification Receive(AbstractLogger logger, IEncryptor encryptor, IDatabase database, string swid, IDictionary notification) { SessionDocument sessionDocument = database.GetSessionDocument(swid); byte[] currentSymmetricEncryptionKey = sessionDocument.CurrentSymmetricEncryptionKey; string optionalString = GetOptionalString(notification, "payload"); IDictionary dictionary; if (optionalString == null) { dictionary = notification; } else { byte[] payloadEncryptedBytes; try { payloadEncryptedBytes = Convert.FromBase64String(optionalString); } catch (Exception ex) { throw new ArgumentException("Couldn't deserialize push notification: " + ex); } try { dictionary = DecryptPayload(encryptor, currentSymmetricEncryptionKey, payloadEncryptedBytes); } catch (Exception ex) { byte[] previousSymmetricEncryptionKey = sessionDocument.PreviousSymmetricEncryptionKey; if (previousSymmetricEncryptionKey == null) { throw new ArgumentException("Couldn't decrypt push notification: " + ex); } try { dictionary = DecryptPayload(encryptor, previousSymmetricEncryptionKey, payloadEncryptedBytes); } catch (Exception ex2) { throw new ArgumentException(string.Concat("Couldn't decrypt push notification: ", ex, "\n", ex2)); } } } StringBuilder stringBuilder = new StringBuilder("Received push notification with payload:\n"); foreach (DictionaryEntry item in dictionary) { stringBuilder.Append(item.Key); stringBuilder.Append(" = "); stringBuilder.Append(item.Value); stringBuilder.Append('\n'); } logger.Debug(stringBuilder.ToString()); string optionalString2 = GetOptionalString(dictionary, "type"); if (optionalString2 == null) { throw new ArgumentException("Push notification doesn't have a type"); } string optionalString3 = GetOptionalString(dictionary, "notifications_available"); bool notificationsAvailable = optionalString3 == null || optionalString3 == "true"; switch (optionalString2) { case "FRIENDSHIP_INVITATION_MESSAGE": { string optionalString5 = GetOptionalString(dictionary, "friendshipInvitationId"); return(new FriendshipInvitationReceivedPushNotification(notificationsAvailable, optionalString5)); } case "FRIENDSHIP_MESSAGE": { string optionalString4 = GetOptionalString(dictionary, "friendId"); return(new FriendshipAddedPushNotification(notificationsAvailable, optionalString4)); } case "BROADCAST": return(new BroadcastPushNotification(notificationsAvailable)); case "ADD_ALERT": return(new AlertAddedPushNotification(notificationsAvailable)); case "CLEAR_ALERT": return(new AlertsClearedPushNotification(notificationsAvailable)); case "REMOVE_FRIENDSHIP_INVITATION": return(new FriendshipInvitationRemovedPushNotification(notificationsAvailable)); case "REMOVE_FRIENDSHIP_TRUST": return(new UntrustedPushNotification(notificationsAvailable)); default: return(new GenericPushNotification(notificationsAvailable)); } }
private void ExecuteNextCall() { if (isExecuting || queue.Count == 0) { return; } QueueItem item = queue[0]; Dictionary <string, string> dictionary = new Dictionary <string, string>(); dictionary.Add("Content-Type", "application/json"); dictionary.Add("Accept", "application/json"); dictionary.Add("Cache-Control", "no-cache,no-store,must-revalidate"); Dictionary <string, string> dictionary2 = dictionary; if (spoofedIpAddress != null) { dictionary2["X-Forwarded-For"] = spoofedIpAddress; } switch (item.AuthType) { case GuestControllerAuthenticationType.ApiKey: { string guestControllerApiKey = database.GetGuestControllerApiKey(); if (guestControllerApiKey == null) { GetApiKeyImmediately(delegate(GuestControllerResult <GuestControllerWebCallResponse> r) { if (!r.Success) { logger.Critical("Getting API key failed"); queue.Remove(item); CallCallbackWithFailureResult(item, null, null); } ExecuteNextCall(); }); return; } dictionary2["Authorization"] = "APIKEY " + guestControllerApiKey; break; } case GuestControllerAuthenticationType.AccessToken: { SessionDocument sessionDocument = database.GetSessionDocument(swid); if (sessionDocument == null) { logger.Critical("Guest Controller web call requires access token, but no session document found"); queue.Remove(item); CallCallbackWithFailureResult(item, null, null); ExecuteNextCall(); return; } string guestControllerAccessToken = sessionDocument.GuestControllerAccessToken; if (guestControllerAccessToken == null) { logger.Critical("Guest Controller web call requires access token, session document doesn't have one"); queue.Remove(item); CallCallbackWithFailureResult(item, null, null); ExecuteNextCall(); return; } dictionary2["Authorization"] = "BEARER " + guestControllerAccessToken; break; } } item.NumAttempts++; isExecuting = true; IWwwCall wwwCall = wwwCallFactory.Create(item.Uri, item.HttpMethod, item.RequestBody, dictionary2, 60000L, 70000L); logger.Debug(HttpLogBuilder.BuildRequestLog(wwwCall.RequestId, item.Uri, item.HttpMethod, dictionary2, item.RequestBodyJson)); wwwCalls.Add(wwwCall); wwwCall.OnDone += delegate { isExecuting = false; Dictionary <string, string> responseHeaders = new Dictionary <string, string>(wwwCall.ResponseHeaders); string error = wwwCall.Error; int requestId = wwwCall.RequestId; long timeToStartUpload = wwwCall.TimeToStartUpload; long timeToFinishUpload = wwwCall.TimeToFinishUpload; float percentUploaded = wwwCall.PercentUploaded; long timeToStartDownload = wwwCall.TimeToStartDownload; long timeToFinishDownload = wwwCall.TimeToFinishDownload; float percentDownloaded = wwwCall.PercentDownloaded; string timeoutReason = wwwCall.TimeoutReason; long timeoutTime = wwwCall.TimeoutTime; uint statusCode = wwwCall.StatusCode; string responseText = (wwwCall.ResponseBody == null) ? string.Empty : stringEncoding.GetString(wwwCall.ResponseBody); GuestControllerWebCallResponse response = item.ResponseParser(responseText); if (response == null) { CallCallbackWithFailureResult(item, null, responseHeaders); } else { wwwCalls.Remove(wwwCall); wwwCall.Dispose(); if (!string.IsNullOrEmpty(error)) { string text = error.ToLower(); if (text == "couldn't connect to host" || text.Contains("timedout") || text.Contains("timed out")) { string text2 = HttpLogBuilder.BuildTimeoutLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, timeToStartUpload, timeToFinishUpload, percentUploaded, timeToStartDownload, timeToFinishDownload, percentDownloaded, timeoutReason, timeoutTime); item.TimeoutLogs.Append(text2); item.TimeoutLogs.Append("\n\n"); logger.Error(text2); if (item.NumAttempts > 3) { logger.Critical("Too many timeouts: " + item.Uri.AbsoluteUri + "\nPrevious logs:\n" + item.TimeoutLogs); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); } ExecuteNextCall(); return; } } if (statusCode >= 500 && statusCode <= 599) { string text2 = HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode); if (item.NumAttempts > 1) { logger.Critical(text2); logger.Critical("Too many server errors"); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); } else { logger.Error(text2); } ExecuteNextCall(); } else if (HasErrorCode(response, "API_KEY_INVALID")) { logger.Error(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); if (item.RefreshedApiKey) { logger.Critical("Invalid API key. Already got new token once. Giving up."); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); ExecuteNextCall(); } else { logger.Error("Invalid API key. Getting new API key..."); GetApiKeyImmediately(delegate(GuestControllerResult <GuestControllerWebCallResponse> r) { if (!r.Success) { logger.Critical(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); logger.Critical("Getting new API key failed."); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); } ExecuteNextCall(); }); } } else if (HasErrorCode(response, "RATE_LIMITED")) { logger.Error(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); if (item.RefreshedApiKey) { logger.Critical("Couldn't get new API key. Already got new API key once. Giving up."); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); ExecuteNextCall(); } else { logger.Error("Rate limited. Getting new API key..."); GetApiKeyImmediately(delegate(GuestControllerResult <GuestControllerWebCallResponse> r) { if (!r.Success || HasErrorCode(r.Response, "RATE_LIMITED")) { logger.Critical(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); logger.Critical("Getting new API key failed."); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); } ExecuteNextCall(); }); } } else if (HasErrorCode(response, "ACCESS_TOKEN_NOT_FOUND", "AUTHORIZATION_INVALID_OR_EXPIRED_TOKEN")) { logger.Error(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); if (item.RefreshedAccessToken) { logger.Critical("Invalid access token. Already tried to refresh. Giving up."); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); ExecuteNextCall(); } else { logger.Error("Invalid access token. Refreshing..."); RefreshImmediately(delegate(GuestControllerResult <RefreshResponse> r) { if (!r.Success) { logger.Critical(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); logger.Critical("Refreshing access token failed"); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); } ExecuteNextCall(); }); } } else if (statusCode >= 401 && statusCode <= 499) { logger.Critical(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); ExecuteNextCall(); } else if (statusCode == 400 || (statusCode >= 200 && statusCode <= 299)) { logger.Debug(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); queue.Remove(item); item.Callback(new GuestControllerResult <GuestControllerWebCallResponse>(success: true, response, responseHeaders)); ExecuteNextCall(); } else { if (!string.IsNullOrEmpty(error)) { string text = error.ToLower(); if (text.Contains("connection appears to be offline") || text.Contains("connection was lost") || text.Contains("network is unreachable")) { logger.Critical(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); logger.Critical("Offline error = " + error); } else { logger.Critical(HttpLogBuilder.BuildResponseLog(requestId, item.Uri, item.HttpMethod, responseHeaders, responseText, statusCode)); logger.Critical("Other web call error = " + error); } } queue.Remove(item); CallCallbackWithFailureResult(item, response, responseHeaders); ExecuteNextCall(); } } }; wwwCall.Execute(); }