예제 #1
0
            public static XmlDocument makeRequest(string url, string method, string body = null)
            {
                var request = WebRequest.CreateHttp(url);

                request.Method = method;

                var header = new MKMAuth.OAuthHeader();

                request.Headers.Add(HttpRequestHeader.Authorization, header.getAuthorizationHeader(method, url));
                request.Method = method;

                if (body != null)
                {
                    request.ServicePoint.Expect100Continue = false;
                    request.ContentLength = body.Length;
                    request.ContentType   = "text/xml";

                    var writer = new StreamWriter(request.GetRequestStream());

                    writer.Write(body);
                    writer.Close();
                }

                var response = request.GetResponse() as HttpWebResponse;
                var doc      = new XmlDocument();

                doc.Load(response.GetResponseStream());

                return(doc);
            }
예제 #2
0
            private static System.DateTime denyTime;            // to know when denyAdditionalRequests was switched, if we pass to another day, reset it

            /// <summary>
            /// Makes a request from MKM's API.
            /// If the daily request limit has been reached, does not send the request and instead throws an exception.
            /// </summary>
            /// <param name="url">The http URL of the API.</param>
            /// <param name="method">The name of the request method (PUT, GET, etc.).</param>
            /// <param name="body">The body containing parameters of the method if applicable.</param>
            /// <returns>Document containing the response from MKM. In some cases this can empty (when the response is "nothing matches your request").</returns>
            /// <exception cref="HttpListenerException">429 - Too many requests. Wait for 0:00 CET for request counter to reset.</exception>
            /// <exception cref="APIProcessingExceptions">Many different network-based exceptions.</exception>
            public static XmlDocument makeRequest(string url, string method, string body = null)
            {
                // throw the exception ourselves to prevent sending requests to MKM that would end with this error
                // because MKM tends to revoke the user's app token if it gets too many requests above the limit
                // the 429 code is the same MKM uses for this error
                if (denyAdditionalRequests)
                {
                    // MKM resets the counter at 0:00 CET. CET is two hours ahead of UCT, so if it is after 22:00 of the same day
                    // the denial was triggered, that means the 0:00 CET has passed and we can reset the deny
                    if (System.DateTime.UtcNow.Date == denyTime.Date && System.DateTime.UtcNow.Hour < 22)
                    {
                        throw new HttpListenerException(429, "Too many requests. Wait for 0:00 CET for request counter to reset.");
                    }
                    else
                    {
                        denyAdditionalRequests = false;
                    }
                }
                XmlDocument doc     = new XmlDocument();
                var         request = WebRequest.CreateHttp(url);

                request.Method = method;

                var header = new MKMAuth.OAuthHeader();

                request.Headers.Add(HttpRequestHeader.Authorization, header.getAuthorizationHeader(method, url));
                request.Method = method;

                if (body != null)
                {
                    request.ServicePoint.Expect100Continue = false;
                    request.ContentLength = body.Length;
                    request.ContentType   = "text/xml";

                    var writer = new StreamWriter(request.GetRequestStream());

                    writer.Write(body);
                    writer.Close();
                }

                var response = request.GetResponse() as HttpWebResponse;

                // just for checking EoF, it is not accessible directly from the Stream object
                // Empty streams can be returned for example for article fetches that result in 0 matches (happens regularly when e.g. seeking nonfoils in foil-only promo sets).
                // Passing empty stream to doc.Load causes exception and also sometimes seems to screw up the XML parser
                // even when the exception is handled and it then causes problems for subsequent calls => first check if the stream is empty
                StreamReader s = new StreamReader(response.GetResponseStream());

                if (!s.EndOfStream)
                {
                    doc.Load(s);
                }
                s.Close();
                int requestCount = int.Parse(response.Headers.Get("X-Request-Limit-Count"));
                int requestLimit = int.Parse(response.Headers.Get("X-Request-Limit-Max"));

                if (requestCount >= requestLimit)
                {
                    denyAdditionalRequests = true;
                    denyTime = System.DateTime.UtcNow;
                }
                MainView.Instance.Invoke(new MainView.updateRequestCountCallback(MainView.Instance.updateRequestCount), requestCount, requestLimit);

                return(doc);
            }
예제 #3
0
            /// <summary>
            /// Makes a request from MKM's API.
            /// If the daily request limit has been reached, does not send the request and instead throws an exception.
            /// </summary>
            /// <param name="url">The http URL of the API.</param>
            /// <param name="method">The name of the request method (PUT, GET, etc.).</param>
            /// <param name="body">The body containing parameters of the method if applicable.</param>
            /// <returns>Document containing the response from MKM. In some cases this can empty (when the response is "nothing matches your request").</returns>
            /// <exception cref="HttpListenerException">429 - Too many requests. Wait for 0:00 CET for request counter to reset.</exception>
            /// <exception cref="APIProcessingExceptions">Many different network-based exceptions.</exception>
            public static XmlDocument makeRequest(string url, string method, string body = null)
            {
                // throw the exception ourselves to prevent sending requests to MKM that would end with this error
                // because MKM tends to revoke the user's app token if it gets too many requests above the limit
                // the 429 code is the same MKM uses for this error
                if (denyAdditionalRequests)
                {
                    // MKM resets the counter at 0:00 CET. CET is two hours ahead of UCT, so if it is after 22:00 of the same day
                    // the denial was triggered, that means the 0:00 CET has passed and we can reset the deny
                    if (DateTime.UtcNow.Date == denyTime.Date && DateTime.UtcNow.Hour < 22)
                    {
                        throw new HttpListenerException(429, "Too many requests. Wait for 0:00 CET for request counter to reset.");
                    }
                    else
                    {
                        denyAdditionalRequests = false;
                    }
                }
                // enforce the maxRequestsPerMinute limit - technically it's just an approximation as the requests
                // can arrive to MKM with some delay, but it should be close enough
                var now = DateTime.Now;

                while (requestTimes.Count > 0 && (now - requestTimes.Peek()).TotalSeconds > 60)
                {
                    requestTimes.Dequeue();// keep only times of requests in the past 60 seconds
                }
                if (requestTimes.Count >= maxRequestsPerMinute)
                {
                    // wait until 60.01 seconds passed since the oldest request
                    // we know (now - peek) is <= 60, otherwise it would get dequeued above,
                    // so we are passing a positive number to sleep
                    System.Threading.Thread.Sleep(
                        60010 - (int)(now - requestTimes.Peek()).TotalMilliseconds);
                    requestTimes.Dequeue();
                }

                requestTimes.Enqueue(DateTime.Now);
                XmlDocument doc     = new XmlDocument();
                var         request = WebRequest.CreateHttp(url);

                request.Method = method;

                request.Headers.Add(HttpRequestHeader.Authorization, header.getAuthorizationHeader(method, url));
                request.Method = method;

                if (body != null)
                {
                    request.ServicePoint.Expect100Continue = false;
                    request.ContentLength = System.Text.Encoding.UTF8.GetByteCount(body);
                    request.ContentType   = "text/xml";

                    var writer = new StreamWriter(request.GetRequestStream());

                    writer.Write(body);
                    writer.Close();
                }

                var response = request.GetResponse() as HttpWebResponse;

                // just for checking EoF, it is not accessible directly from the Stream object
                // Empty streams can be returned for example for article fetches that result in 0 matches (happens regularly when e.g. seeking nonfoils in foil-only promo sets).
                // Passing empty stream to doc.Load causes exception and also sometimes seems to screw up the XML parser
                // even when the exception is handled and it then causes problems for subsequent calls => first check if the stream is empty
                StreamReader s = new StreamReader(response.GetResponseStream());

                if (!s.EndOfStream)
                {
                    doc.Load(s);
                }
                s.Close();
                int requestCount = int.Parse(response.Headers.Get("X-Request-Limit-Count"));
                int requestLimit = int.Parse(response.Headers.Get("X-Request-Limit-Max"));

                if (requestCount >= requestLimit)
                {
                    denyAdditionalRequests = true;
                    denyTime = System.DateTime.UtcNow;
                }
                MainView.Instance.Invoke(new MainView.updateRequestCountCallback(MainView.Instance.UpdateRequestCount), requestCount, requestLimit);

                return(doc);
            }