예제 #1
0
 public ParseCommand(string relativeUri,
                     string method,
                     string sessionToken = null,
                     IList <KeyValuePair <string, string> > headers = null,
                     IDictionary <string, object> data = null) : this(relativeUri : relativeUri,
                                                                      method : method,
                                                                      sessionToken : sessionToken,
                                                                      headers : headers,
                                                                      stream : data != null ? new MemoryStream(UTF8Encoding.UTF8.GetBytes(Json.Encode(data))) : null,
                                                                      contentType : data != null ? "application/json" : null)
 {
 }
        public Task <Tuple <HttpStatusCode, string> > ExecuteAsync(HttpRequest httpRequest,
                                                                   IProgress <ParseUploadProgressEventArgs> uploadProgress,
                                                                   IProgress <ParseDownloadProgressEventArgs> downloadProgress,
                                                                   CancellationToken cancellationToken)
        {
            var tcs = new TaskCompletionSource <Tuple <HttpStatusCode, string> >();

            cancellationToken.Register(() => tcs.TrySetCanceled());
            uploadProgress   = uploadProgress ?? new Progress <ParseUploadProgressEventArgs>();
            downloadProgress = downloadProgress ?? new Progress <ParseDownloadProgressEventArgs>();

            var headerTable = new Hashtable();

            // Fill in the headers
            if (httpRequest.Headers != null)
            {
                foreach (var pair in httpRequest.Headers)
                {
                    headerTable[pair.Key] = pair.Value;
                }
            }

            // Explicitly assume a JSON content.
            if (!headerTable.ContainsKey("Content-Type"))
            {
                headerTable["Content-Type"] = "application/json";
            }

            Task        readBytesTask         = null;
            IDisposable toDisposeAfterReading = null;

            byte[] bytes = null;
            if (!httpRequest.Method.Equals("POST") || httpRequest.Data == null)
            {
                bool   noBody = httpRequest.Data == null;
                Stream data   = httpRequest.Data ?? new MemoryStream(UTF8Encoding.UTF8.GetBytes("{}"));
                var    reader = new StreamReader(data);
                toDisposeAfterReading = reader;
                Task <string> streamReaderTask;

                if (PlatformHooks.IsCompiledByIL2CPP)
                {
                    streamReaderTask = Task.FromResult(reader.ReadToEnd());
                }
                else
                {
                    streamReaderTask = reader.ReadToEndAsync();
                }

                readBytesTask = streamReaderTask.OnSuccess(t => {
                    var parsed = Json.Parse(t.Result) as IDictionary <string, object>;
                    // Inject the method
                    parsed["_method"] = httpRequest.Method;
                    parsed["_noBody"] = noBody;
                    bytes             = UTF8Encoding.UTF8.GetBytes(Json.Encode(parsed));
                });
            }
            else
            {
                var ms = new MemoryStream();
                toDisposeAfterReading = ms;
                readBytesTask         = httpRequest.Data.CopyToAsync(ms).OnSuccess(_ => {
                    bytes = ms.ToArray();
                });
            }

            readBytesTask.Safe().ContinueWith(t => {
                if (toDisposeAfterReading != null)
                {
                    toDisposeAfterReading.Dispose();
                }
                return(t);
            }).Unwrap()
            .OnSuccess(_ => {
                float oldDownloadProgress = 0;
                float oldUploadProgress   = 0;

                PlatformHooks.RunOnMainThread(() => {
                    PlatformHooks.RegisterNetworkRequest(GenerateWWWInstance(httpRequest.Uri.AbsoluteUri, bytes, headerTable), www => {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            tcs.TrySetCanceled();
                            return;
                        }
                        if (www.isDone)
                        {
                            uploadProgress.Report(new ParseUploadProgressEventArgs {
                                Progress = 1
                            });
                            downloadProgress.Report(new ParseDownloadProgressEventArgs {
                                Progress = 1
                            });

                            var statusCode = GetStatusCode(www);
                            // Returns HTTP error if that's the only info we have.
                            if (!String.IsNullOrEmpty(www.error) && String.IsNullOrEmpty(www.text))
                            {
                                var errorString = string.Format("{{\"error\":\"{0}\"}}", www.error);
                                tcs.TrySetResult(new Tuple <HttpStatusCode, string>(statusCode, errorString));
                            }
                            else
                            {
                                tcs.TrySetResult(new Tuple <HttpStatusCode, string>(statusCode, www.text));
                            }
                        }
                        else
                        {
                            // Update upload progress
                            var newUploadProgress = www.uploadProgress;
                            if (oldUploadProgress < newUploadProgress)
                            {
                                uploadProgress.Report(new ParseUploadProgressEventArgs {
                                    Progress = newUploadProgress
                                });
                            }
                            oldUploadProgress = newUploadProgress;

                            // Update download progress
                            var newDownloadProgress = www.progress;
                            if (oldDownloadProgress < newDownloadProgress)
                            {
                                downloadProgress.Report(new ParseDownloadProgressEventArgs {
                                    Progress = newDownloadProgress
                                });
                            }
                            oldDownloadProgress = newDownloadProgress;
                        }
                    });
                });
            });

            // Get off of the main thread for further processing.
            return(tcs.Task.ContinueWith(t => {
                var dispatchTcs = new TaskCompletionSource <object>();
                // ThreadPool doesn't work well in IL2CPP environment, but Thread does!
                if (PlatformHooks.IsCompiledByIL2CPP)
                {
                    var thread = new Thread(_ => {
                        dispatchTcs.TrySetResult(null);
                    });
                    thread.Start();
                }
                else
                {
                    ThreadPool.QueueUserWorkItem(_ => dispatchTcs.TrySetResult(null));
                }
                return dispatchTcs.Task;
            }).Unwrap()
                   .ContinueWith(_ => tcs.Task).Unwrap());
        }