diff --git a/UptimeSharp/IUptimeClient.cs b/UptimeSharp/IUptimeClient.cs index bac23e2..be23ef9 100644 --- a/UptimeSharp/IUptimeClient.cs +++ b/UptimeSharp/IUptimeClient.cs @@ -1,12 +1,24 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace UptimeSharp { public interface IUptimeClient { + /// + /// Accessor for the UptimeRebot API key + /// see: http://www.uptimerobot.com/api + /// + /// + /// The API key. + /// string ApiKey { get; set; } + + /// + /// Action which is executed before every request + /// + /// + /// The pre request callback. + /// + Action PreRequest { get; set; } } } diff --git a/UptimeSharp/UptimeClient.cs b/UptimeSharp/UptimeClient.cs index da24e1a..1223b36 100644 --- a/UptimeSharp/UptimeClient.cs +++ b/UptimeSharp/UptimeClient.cs @@ -1,10 +1,12 @@ -using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace UptimeSharp { @@ -32,29 +34,178 @@ namespace UptimeSharp /// Accessor for the UptimeRebot API key /// see: http://www.uptimerobot.com/api /// + /// + /// The API key. + /// public string ApiKey { get; set; } + /// + /// Action which is executed before every request + /// + /// + /// The pre request callback. + /// + public Action PreRequest { get; set; } + /// /// Initializes a new instance of the class. /// /// The API key - public UptimeClient(string apiKey) + /// The HttpMessage handler. + /// Request timeout (in seconds). + public UptimeClient(string apiKey, HttpMessageHandler handler = null, int? timeout = null) { // assign public properties ApiKey = apiKey; // initialize REST client - _restClient = new HttpClient(new HttpClientHandler() + _restClient = new HttpClient(handler ?? new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip }); + if (timeout.HasValue) + { + _restClient.Timeout = TimeSpan.FromSeconds(timeout.Value); + } + // set base uri _restClient.BaseAddress = baseUri; // defines the response format _restClient.DefaultRequestHeaders.Add("Accept", "application/json"); } + + + /// + /// Fetches a typed resource + /// + /// + /// Requested method (appended to base path) + /// The cancellation token. + /// Additional POST parameters + /// + protected async Task Request(string method, CancellationToken cancellationToken, Dictionary parameters = null) where T : class, new() + { + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, method); + HttpResponseMessage response = null; + + if (parameters == null) + { + parameters = new Dictionary(); + } + + // add api key to each request + parameters.Add("apiKey", ApiKey); + + // require UptimeRobot to respond with JSON formatting + parameters.Add("format", "json"); + + // UptimeRobot returns by default JSON-P when json-formatting is set + // with this param it can return raw JSON + parameters.Add("noJsonCallback", "1"); + + // content of the request + request.Content = new FormUrlEncodedContent(parameters); + + // call pre request action + if (PreRequest != null) + { + PreRequest(method); + } + + // make async request + try + { + response = await _restClient.SendAsync(request, cancellationToken); + } + catch (HttpRequestException exc) + { + throw new UptimeSharpException(exc.Message, exc); + } + + // validate HTTP response + ValidateResponse(response); + + // cache headers + lastHeaders = response.Headers; + + // read response + var responseString = await response.Content.ReadAsStringAsync(); + + responseString = responseString.Replace("[]", "{}"); + + // deserialize object + T parsedResponse = JsonConvert.DeserializeObject( + responseString, + new JsonSerializerSettings + { + Error = (object sender, ErrorEventArgs args) => + { + throw new UptimeSharpException(String.Format("Parse error: {0}", args.ErrorContext.Error.Message)); + }, + Converters = + { + new BoolConverter(), + new UnixDateTimeConverter(), + new UriConverter() + } + } + ); + + return parsedResponse; + } + + + /// + /// Validates the response. + /// + /// The response. + /// + /// + /// Error retrieving response + /// + protected void ValidateResponse(HttpResponseMessage response) + { + // no error found + if (response.StatusCode == HttpStatusCode.OK) + { + return; + } + + //string exceptionString = response.ReasonPhrase; + //bool isPocketError = response.Headers.Contains("X-Error"); + + //// fetch custom pocket headers + //string error = TryGetHeaderValue(response.Headers, "X-Error"); + //int errorCode = Convert.ToInt32(TryGetHeaderValue(response.Headers, "X-Error-Code")); + + //// create exception strings + //if (isPocketError) + //{ + // exceptionString = String.Format("Pocket error: {0} ({1}) ", error, errorCode); + //} + //else + //{ + // exceptionString = String.Format("Request error: {0} ({1})", response.ReasonPhrase, (int)response.StatusCode); + //} + + //// create exception + //PocketException exception = new PocketException(exceptionString); + + //if (isPocketError) + //{ + // // add custom pocket fields + // exception.PocketError = error; + // exception.PocketErrorCode = errorCode; + + // // add to generic exception data + // exception.Data.Add("X-Error", error); + // exception.Data.Add("X-Error-Code", errorCode); + //} + + //throw exception; + } } }