예제 #1
0
파일: Api.cs 프로젝트: Amethi/DiscourseApi
        /// <summary>
        /// API post using multipart/form-data.
        /// </summary>
        /// <param name="application">The full Uri you want to call (including any get parameters)</param>
        /// <param name="getParameters">Get parameters (or null if none)</param>
        /// <param name="postParameters">Post parameters as an  object or JObject
        /// </param>
        /// <returns>The result as a JObject, with MetaData filled in.</returns>
        public async Task <JObject> PostFormAsync(string application, object getParameters, object postParameters, params string[] fileParameterNames)
        {
            string uri = AddGetParams(makeUri(application), getParameters);

            using (DisposableCollection objectsToDispose = new DisposableCollection()) {
                MultipartFormDataContent content = objectsToDispose.Add(new MultipartFormDataContent());
                foreach (var o in postParameters.ToCollection())
                {
                    if (Array.IndexOf(fileParameterNames, o.Key) >= 0)
                    {
                        string      filename = o.Value;
                        FileStream  fs       = objectsToDispose.Add(new FileStream(filename, FileMode.Open));
                        HttpContent v        = objectsToDispose.Add(new StreamContent(fs));
                        content.Add(v, o.Key, Path.GetFileName(filename));
                    }
                    else
                    {
                        HttpContent v = objectsToDispose.Add(new StringContent(o.Value));
                        content.Add(v, o.Key);
                    }
                }
                return(await SendMessageAsync(HttpMethod.Post, uri, content));
            }
        }
예제 #2
0
파일: Api.cs 프로젝트: Amethi/DiscourseApi
        /// <summary>
        /// Send a message and get the result.
        /// Deal with rate limiting return values and redirects.
        /// </summary>
        /// <param name="method">Get/Post/etc.</param>
        /// <param name="uri">The full Uri you want to call (including any get parameters)</param>
        /// <param name="postParameters">Post parameters as an object or JObject</param>
        public async Task <HttpResponseMessage> SendMessageAsyncAndGetResponse(HttpMethod method, string uri, object postParameters = null)
        {
            LastRequest  = "";
            LastResponse = "";
            for (; ;)
            {
                if (Settings.DelayBetweenApiCalls > 0)
                {
                    double elapsedSinceLastRequest = (DateTime.Now - lastRequest).TotalMilliseconds;
                    if (elapsedSinceLastRequest < Settings.DelayBetweenApiCalls)
                    {
                        await Task.Delay((int)(Settings.DelayBetweenApiCalls - elapsedSinceLastRequest));
                    }
                }
                lastRequest = DateTime.Now;
                string content = null;
                using (DisposableCollection disposeMe = new DisposableCollection()) {
                    var message = disposeMe.Add(new HttpRequestMessage(method, uri));
                    if (!string.IsNullOrEmpty(Settings.ApiKey))
                    {
                        message.Headers.Add("Api-Key", Settings.ApiKey);
                    }
                    if (!string.IsNullOrEmpty(Settings.ApiUsername))
                    {
                        message.Headers.Add("Api-Username", Settings.ApiUsername);
                    }
                    message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                    message.Headers.Add("User-Agent", Settings.ApplicationName);

                    if (postParameters != null)
                    {
                        if (postParameters is FileStream f)
                        {
                            content         = Path.GetFileName(f.Name);
                            f.Position      = 0;
                            message.Content = disposeMe.Add(new StreamContent(f));
                            string contentType = MimeMapping.MimeUtility.GetMimeMapping(content);
                            message.Content.Headers.ContentType        = new MediaTypeHeaderValue(contentType);
                            message.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                            {
                                FileName = content
                            };
                            message.Content.Headers.ContentLength = f.Length;
                            content = "File: " + content;
                        }
                        else if (postParameters is HttpContent parameters)
                        {
                            message.Content = parameters;
                        }
                        else
                        {
                            var postParamsList = postParameters.ToCollection().ToList();
                            var form           = new MultipartFormDataContent();

                            if (Settings.SkipValidations)
                            {
                                postParamsList.Add(new KeyValuePair <string, string>("skip_validations", "true"));
                            }

                            foreach (var kvp in postParamsList)
                            {
                                form.Add(new StringContent(kvp.Value), kvp.Key);
                            }

                            content         = postParamsList.ToJson();
                            message.Content = disposeMe.Add(form);
                        }
                    }
                    else if (method != HttpMethod.Get && Settings.SkipValidations)
                    {
                        // add in a skip_validations parameter if required for methods that change objects
                        var postParamsList = new List <KeyValuePair <string, string> > {
                            new KeyValuePair <string, string>("skip_validations", "true")
                        };
                        content         = postParamsList.ToJson();
                        message.Content = disposeMe.Add(new FormUrlEncodedContent(postParamsList));
                    }

                    LastRequest = $"{message}:{content}";
                    HttpResponseMessage result;
                    int backoff = 1000;
                    int delay;
                    if (Settings.LogRequest > 0)
                    {
                        Log($"Sent -> {(Settings.LogRequest > 1 ? message.ToString() : message.RequestUri.ToString())}:{content}");
                    }
                    result = await _client.SendAsync(message);

                    LastResponse = result.ToString();
                    if (Settings.LogResult > 1)
                    {
                        Log($"Received -> {result}");
                    }
                    switch (result.StatusCode)
                    {
                    case HttpStatusCode.Found:                                  // Redirect
                        uri   = result.Headers.Location.AbsoluteUri;
                        delay = 1;
                        break;

                    case (HttpStatusCode)429:                                   // TooManyRequests
                        IEnumerable <string> values;
                        delay = 5000;
                        if (result.Headers.TryGetValues("Retry-After", out values))
                        {
                            try {
                                int d = 1000 * int.Parse(values.FirstOrDefault());
                                if (d > delay)
                                {
                                    delay = d;
                                }
                            } catch {
                            }
                        }
                        break;

                    case HttpStatusCode.BadGateway:
                    case HttpStatusCode.ServiceUnavailable:
                    case HttpStatusCode.GatewayTimeout:
                        backoff *= 2;
                        delay    = backoff;
                        if (delay > 16000)
                        {
                            return(result);
                        }
                        break;

                    default:
                        return(result);
                    }
                    result.Dispose();
                    await Task.Delay(delay);
                }
            }
        }