protected void InvokeS3Post(PostObjectRequest publicrequest, AmazonServiceCallback callback, object state) { AsyncResult asyncResult = new AsyncResult(new DefaultRequest(publicrequest, "Amazon.S3"), publicrequest, callback, state, new S3Signer(), null); try { asyncResult.Metrics.StartEvent(Metric.ClientExecuteTime); asyncResult.Request.Endpoint = DetermineEndpoint(asyncResult.Request); if (Config.LogMetrics) { asyncResult.Metrics.IsEnabled = true; asyncResult.Metrics.AddProperty(Metric.ServiceName, asyncResult.Request.ServiceName); asyncResult.Metrics.AddProperty(Metric.ServiceEndpoint, asyncResult.Request.Endpoint); asyncResult.Metrics.AddProperty(Metric.MethodName, asyncResult.RequestName); asyncResult.Metrics.AddProperty(Metric.AsyncCall, !asyncResult.CompletedSynchronously); } //ConfigureRequest(asyncResult); InvokeHelperForS3PostObject(asyncResult, publicrequest); } catch (Exception e) { AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Errors, "S3", e); asyncResult.IsCompleted = true; asyncResult.HandleException(e); return; } //return asyncResult; }
private static void Execute <T>(AsyncCall call, DynamoDBAsyncState <T> result) { try { result.Return = call(); AmazonMainThreadDispatcher.ExecCallback <T>(result.Callback, new AmazonDynamoResult <T>((T)result.Return, null, result.State)); return; } catch (Exception ex) { AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Errors, result.Operation, ex); AmazonMainThreadDispatcher.ExecCallback <T>(result.Callback, new AmazonDynamoResult <T>(default(T), ex, result.State)); return; } }
/// <summary> /// The HandleWWWErrorResponse differs significantly from the error handling doing in .NET sdk /// since the www.error string message is incomplete /// so this requires rewriting all responseunmarshallers.HandleErrorContext which is not part of this version /// hence exception thrown will always be of base type AmazonServiceException /// </summary> /// <returns>True if the error needs retry</returns> private bool HandleWWWErrorResponse(AsyncResult asyncResult) { WWWResponseData errorResponse = asyncResult.ResponseData; asyncResult.Metrics.AddProperty(Metric.Exception, errorResponse.Error); AmazonServiceException errorResponseException = null; errorResponseException = new AmazonServiceException(errorResponse.Error, new WebException(errorResponse.Error)); errorResponseException.UnityStatusCode = errorResponse.Error; try { errorResponseException.StatusCode = errorResponse.ErrorStatusCode; } catch (Exception e) { // Parsing exception AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Errors, asyncResult.Request.RequestName, e); } string curl = "curl " + (asyncResult.Request.HttpMethod == "GET" && !HttpOverrideSupportedServices.Contains(asyncResult.Request.ServiceName) ? "-G " : "-X POST "); foreach (string key in asyncResult.RequestData.Headers.Keys) { curl += " -H \"" + key + ": " + asyncResult.RequestData.Headers[key] + "\" "; } if (asyncResult.RequestData.Data != null) { curl += " -d '" + System.Text.Encoding.Default.GetString(asyncResult.RequestData.Data) + "' "; } curl += " " + asyncResult.RequestData.Url; Debug.LogError(curl); if (errorResponse.IsHeaderPresent(HeaderKeys.XAmzRequestIdHeader.ToUpper())) { errorResponseException.RequestId = errorResponse.GetHeaderValue(HeaderKeys.XAmzRequestIdHeader); } asyncResult.Exception = errorResponseException; // currently no retries are done return(false); }
private void RunSyncOperationAsync(int retry, Action <RunSyncOperationResponse> callback) { if (retry < 0) { callback(new RunSyncOperationResponse(false, null)); return; } long lastSyncCount = _local.GetLastSyncCount(GetIdentityId(), _datasetName); // if dataset is deleted locally, push it to remote if (lastSyncCount == -1) { #if DELETE_METHOD_SUPPORT _remote.DeleteDatasetAsync(_datasetName, delegate(AmazonCognitoResult result) { if (result.Exception != null) { var e = result.Exception as DataStorageException; AmazonLogging.LogError(AmazonLogging.AmazonLoggingLevel.Errors, "CognitoSyncManager", "OnSyncFailure" + e.Message); this.FireSyncFailureEvent(e); callback(new RunSyncOperationResponse(false, null)); return; } _local.PurgeDataset(GetIdentityId(), _datasetName); AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "OnSyncSuccess: dataset delete is pushed to remote"); this.FireSyncSuccessEvent(new List <Record>()); callback(new RunSyncOperationResponse(true, null)); return; }, null); #endif // invalid scenario AmazonLogging.LogError(AmazonLogging.AmazonLoggingLevel.Critical, "CognitoSyncManager", "OnSyncFailure: DeleteDataset is an invalid operation"); FireSyncFailureEvent(new DataStorageException("DeleteDataset is an invalid operation")); callback(new RunSyncOperationResponse(false, null)); return; } // get latest modified records from remote AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "get latest modified records since " + lastSyncCount); _remote.ListUpdatesAsync(_datasetName, lastSyncCount, delegate(AmazonCognitoResult listUpdatesResult) { RemoteDataStorage.DatasetUpdates datasetUpdates = null; if (listUpdatesResult == null || listUpdatesResult.Exception != null) { var e = listUpdatesResult.Exception as DataStorageException; AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", e); FireSyncFailureEvent(e); callback(new RunSyncOperationResponse(false, listUpdatesResult.Exception)); return; } ListUpdatesResponse listUpdatesResponse = listUpdatesResult.Response as ListUpdatesResponse; datasetUpdates = listUpdatesResponse.DatasetUpdates; if (datasetUpdates.MergedDatasetNameList.Count != 0 && this.OnDatasetMerged != null) { bool resume = this.OnDatasetMerged(this, datasetUpdates.MergedDatasetNameList); if (resume) { this.RunSyncOperationAsync(--retry, callback); return; } else { AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "OnSyncFailure: Manual cancel"); FireSyncFailureEvent(new DataStorageException("Manual cancel")); callback(new RunSyncOperationResponse(false, null)); return; } } // if the dataset doesn't exist or is deleted, trigger onDelete if (lastSyncCount != 0 && !datasetUpdates.Exists || datasetUpdates.Deleted && this.OnDatasetDeleted != null) { bool resume = this.OnDatasetDeleted(this); if (resume) { // remove both records and metadata _local.DeleteDataset(GetIdentityId(), _datasetName); _local.PurgeDataset(GetIdentityId(), _datasetName); AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "OnSyncSuccess"); FireSyncSuccessEvent(new List <Record>()); callback(new RunSyncOperationResponse(true, null)); return; } else { AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "OnSyncFailure"); FireSyncFailureEvent(new DataStorageException("Manual cancel")); callback(new RunSyncOperationResponse(false, null)); return; } } List <Record> remoteRecords = datasetUpdates.Records; if (remoteRecords.Count != 0) { // if conflict, prompt developer/user with callback List <SyncConflict> conflicts = new List <SyncConflict>(); List <Record> conflictRecords = new List <Record>(); foreach (Record remoteRecord in remoteRecords) { Record localRecord = _local.GetRecord(GetIdentityId(), _datasetName, remoteRecord.Key); // only when local is changed and its value is different if (localRecord != null && localRecord.Modified && !StringUtils.Equals(localRecord.Value, remoteRecord.Value)) { conflicts.Add(new SyncConflict(remoteRecord, localRecord)); conflictRecords.Add(remoteRecord); } } // retaining only non-conflict records remoteRecords.RemoveAll(t => conflictRecords.Contains(t)); if (conflicts.Count > 0) { AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", String.Format("{0} records in conflict!", conflicts.Count)); bool syncConflictResult = false; if (this.OnSyncConflict == null) { // delegate is not implemented so the conflict resolution is applied syncConflictResult = this.DefaultConflictResolution(conflicts); } else { syncConflictResult = this.OnSyncConflict(this, conflicts); } if (!syncConflictResult) { AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "User cancelled conflict resolution"); callback(new RunSyncOperationResponse(false, null)); return; } } // save to local if (remoteRecords.Count > 0) { AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", String.Format("save {0} records to local", remoteRecords.Count)); _local.PutRecords(GetIdentityId(), _datasetName, remoteRecords); } // new last sync count AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", String.Format("updated sync count {0}", datasetUpdates.SyncCount)); _local.UpdateLastSyncCount(GetIdentityId(), _datasetName, datasetUpdates.SyncCount); } // push changes to remote List <Record> localChanges = this.GetModifiedRecords(); if (localChanges.Count != 0) { AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", String.Format("push {0} records to remote", localChanges.Count)); _remote.PutRecordsAsync(_datasetName, localChanges, datasetUpdates.SyncSessionToken, delegate(AmazonCognitoResult putRecordsResult) { if (putRecordsResult.Exception != null) { if (putRecordsResult.Exception.GetType() == typeof(DataConflictException)) { AmazonLogging.LogError(AmazonLogging.AmazonLoggingLevel.Warnings, "CognitoSyncManager", "Conflicts detected when pushing changes to remote: " + putRecordsResult.Exception.Message); this.RunSyncOperationAsync(--retry, callback); return; } else if (putRecordsResult.Exception.GetType() == typeof(DataStorageException)) { AmazonLogging.LogError(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "OnSyncFailure" + putRecordsResult.Exception.Message); FireSyncFailureEvent(putRecordsResult.Exception); callback(new RunSyncOperationResponse(false, null)); return; } } PutRecordsResponse putRecordsResponse = putRecordsResult.Response as PutRecordsResponse; List <Record> result = putRecordsResponse.UpdatedRecords; // update local meta data _local.PutRecords(GetIdentityId(), _datasetName, result); // verify the server sync count is increased exactly by one, aka no // other updates were made during this update. long newSyncCount = 0; foreach (Record record in result) { newSyncCount = newSyncCount < record.SyncCount ? record.SyncCount : newSyncCount; } if (newSyncCount == lastSyncCount + 1) { AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Info, "DefaultDataset", String.Format("updated sync count %d", newSyncCount)); _local.UpdateLastSyncCount(GetIdentityId(), _datasetName, newSyncCount); } AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "OnSyncSuccess"); // call back FireSyncSuccessEvent(remoteRecords); callback(new RunSyncOperationResponse(true, null)); return; }, null); return; } AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "CognitoSyncManager", "OnSyncSuccess"); // call back FireSyncSuccessEvent(remoteRecords); callback(new RunSyncOperationResponse(true, null)); return; }, null); }
/// <summary> /// Invoked as a callback from the AmazonMainThreadDispatcher /// Processes the http response /// </summary> /// <param name="state">State is expected to be AsyncResult</param> private void ProcessHttpResponse(object state) { AsyncResult asyncResult = null; try { asyncResult = state as AsyncResult; AmazonWebServiceResponse response = null; UnmarshallerContext context = null; var responseData = asyncResult.ResponseData; if (!String.IsNullOrEmpty(responseData.Error)) { AmazonLogging.LogError(AmazonLogging.AmazonLoggingLevel.Critical, asyncResult.Request.ServiceName, responseData.Error); if (HandleWWWErrorResponse(asyncResult)) { if (++asyncResult.RetriesAttempt >= 3) { if (asyncResult.Exception == null) { asyncResult.Exception = new AmazonServiceException("Maximum retries attempts completed"); } // maxretries asyncResult.IsCompleted = true; AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Errors, asyncResult.Request.ServiceName, asyncResult.Exception); asyncResult.HandleException(asyncResult.Exception); return; } else { // retry here InvokeHelper(asyncResult); return; } } else { // non-retriable error asyncResult.IsCompleted = true; asyncResult.HandleException(asyncResult.Exception); return; } } else { using (asyncResult.Metrics.StartEvent(Metric.ResponseProcessingTime)) { var unmarshaller = asyncResult.Unmarshaller; LogResponse(asyncResult.Metrics, asyncResult.Request, HttpStatusCode.Accepted); context = unmarshaller.CreateContext(responseData, this.SupportResponseLogging && (Config.LogResponse || Config.ReadEntireResponse), responseData.OpenResponse(), asyncResult.Metrics); try { using (asyncResult.Metrics.StartEvent(Metric.ResponseUnmarshallTime)) { response = unmarshaller.Unmarshall(context); if (responseData.IsHeaderPresent("STATUS")) { response.HttpStatusCode = responseData.StatusCode; } } } catch (Exception e) { //unmarshalling exception asyncResult.IsCompleted = true; asyncResult.HandleException(e); return; } context.ValidateCRC32IfAvailable(); if (responseData.IsHeaderPresent(HeaderKeys.ContentLengthHeader.ToUpper())) { response.ContentLength = Convert.ToInt32(responseData.GetHeaderValue(HeaderKeys.ContentLengthHeader.ToUpper())); } else { AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Warnings, asyncResult.Request.ServiceName, "cannot find CONTENT-LENGTH header"); } asyncResult.ServiceResult.Response = response; if (response.ResponseMetadata != null) { asyncResult.Metrics.AddProperty(Metric.AWSRequestID, response.ResponseMetadata.RequestId); } } } } catch (Exception e) { AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Errors, asyncResult.Request.ServiceName, e); asyncResult.HandleException(e); } asyncResult.IsCompleted = true; asyncResult.InvokeCallback(); return; }
/// <summary> /// Perform signing, setup WWWRequestData with headers, binary data(for POST request) /// and enqueues to the RequestQueue for Main thread /// </summary> /// <param name="asyncResult"></param> private void ProcessHttpRequest(AsyncResult asyncResult) { try { // prepare request IRequest wrappedRequest = asyncResult.Request; WWWRequestData requestData = new WWWRequestData(); if (HttpOverrideSupportedServices.Contains(asyncResult.Request.ServiceName)) { asyncResult.Request.Headers.Add("X-HTTP-Method-Override", asyncResult.Request.HttpMethod); if (asyncResult.Request.HttpMethod == "GET") { string emptyString = "{}"; asyncResult.Request.ContentStream = new MemoryStream(Encoding.UTF8.GetBytes(emptyString)); requestData.Data = Encoding.Default.GetBytes(emptyString); } } #if UNITY_WEBPLAYER wrappedRequest.Headers.Remove("User-Agent"); wrappedRequest.Headers.Remove("Host"); #endif SignRequest(asyncResult); if (asyncResult.RetriesAttempt > 0) { HandleRetry(asyncResult); } requestData.Url = ComposeUrl(wrappedRequest, wrappedRequest.Endpoint).ToString(); if (!wrappedRequest.UseQueryString && !(wrappedRequest.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase))) { if (wrappedRequest.ContentStream != null) { if (wrappedRequest.OriginalRequest.IncludeSHA256Header && !wrappedRequest.Headers.ContainsKey(HeaderKeys.XAmzContentSha256Header)) { requestData.Headers.Add(HeaderKeys.XAmzContentSha256Header, wrappedRequest.ComputeContentStreamHash()); } } } AddHeaders2(requestData, wrappedRequest.Headers); if (asyncResult.Unmarshaller is JsonResponseUnmarshaller) { requestData.Headers.Add(HeaderKeys.AcceptHeader, "application/json"); } if (!asyncResult.Request.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase)) { if (asyncResult.Request.Content != null && asyncResult.Request.Content.Length > 0) { requestData.Data = asyncResult.Request.Content; } else if (asyncResult.Request.ContentStream != null && asyncResult.Request.ContentStream.Length > 0) { using (asyncResult.Request.ContentStream) { requestData.Data = StreamToByteArray.Convert(asyncResult.Request.ContentStream, this.Config.BufferSize); StreamTransferProgressArgs args = new StreamTransferProgressArgs(asyncResult.Request.ContentStream.Length, asyncResult.Request.ContentStream.Length, asyncResult.Request.ContentStream.Length); if (asyncResult.Request.OriginalRequest.StreamUploadProgressCallback != null) { asyncResult.Request.OriginalRequest.StreamUploadProgressCallback(this, args); } if (args.PercentDone >= 100) { asyncResult.Request.OriginalRequest.StreamUploadProgressCallback = null; } } } else if (asyncResult.Request.Parameters != null && asyncResult.Request.Parameters.Count > 0) { requestData.Data = GetRequestData(asyncResult.Request); } } asyncResult.RequestData = requestData; // setting up callback for response handling asyncResult.WaitCallback = this.ProcessHttpResponse; // switching to main thread to make the network call AmazonMainThreadDispatcher.QueueAWSRequest(asyncResult); } catch (Exception e) { AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Errors, asyncResult.Request.ServiceName, e); asyncResult.IsCompleted = true; asyncResult.HandleException(e); return; } }