diff --git a/casdk-docs/docs/architecture/decisions/0016-watt-time-v3.md b/casdk-docs/docs/architecture/decisions/0016-watt-time-v3.md index 0e726d313..a2b199c64 100644 --- a/casdk-docs/docs/architecture/decisions/0016-watt-time-v3.md +++ b/casdk-docs/docs/architecture/decisions/0016-watt-time-v3.md @@ -38,7 +38,7 @@ The following is configured at `CarbonAware.DataSources.WattTime/src/Constants/ | Forecast | Get forecast| /forecast | /forecast | **TODO: CHECK IMPACT**
No longer be used for historical data
_Request_
  • `ba` is now `region`
  • `extended_forecast` removed
  • `horizon_hours` added
  • `signal_type` added
  • Historical forecasts are now at `/forecast/historical`
    _Response_
  • `signal_type` added | Historical | Get historical forecast data | /historical (?) | /forecast/historical (?) | **We need to validate why historical was being used for the API, and what historical used to be, and whether this should be the new /forecast/historical or not.** | Balancing Authority From Location | Get balancing authority from location | /ba-from-loc | /region-from-loc | Check if the CA SDK uses BA at all

    _Request_
  • `name` is now `region_full_name`
  • `abbrev` is now `region`
  • `signal_type` added
    _Response_
  • `id` removed
  • `signal_type` added | -| Login | User login | https://api2.watttime.org/v2/login | https://api.watttime.org/login | Path has changed from being version specific to being unique from the API version.

    **TODO: CHECK HOW BASE URL IS DEFINED AS THIS WILL NOW HAVE DIFFERENT VALUES** +| Login | User login | https://api2.watttime.org/v2/login | https://api.watttime.org/login | Path has changed from being version specific to being no longer related to the API version.

    **TODO: CHECK HOW BASE URL IS DEFINED AS THIS WILL NOW HAVE DIFFERENT VALUES** ### Query Strings diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/IWattTimeClient.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/IWattTimeClient.cs index fbe1fdef1..4cdf21f18 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/IWattTimeClient.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/IWattTimeClient.cs @@ -8,6 +8,7 @@ namespace CarbonAware.DataSources.WattTime.Client; internal interface IWattTimeClient { public const string NamedClient = "WattTimeClient"; + public const string NamedAuthenticationClient = "WattTimeAuthenticationClient" /// /// Async method to get observed emission data for a given balancing authority and time period. diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/WattTimeClient.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/WattTimeClient.cs index ed4e10e5d..9b17882ae 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/WattTimeClient.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/WattTimeClient.cs @@ -25,6 +25,7 @@ internal class WattTimeClient : IWattTimeClient }; private HttpClient _client; + private HttpClient _authenticationClient; private IOptionsMonitor _configurationMonitor { get; } @@ -37,12 +38,19 @@ internal class WattTimeClient : IWattTimeClient public WattTimeClient(IHttpClientFactory factory, IOptionsMonitor configurationMonitor, ILogger log, IMemoryCache memoryCache) { _client = factory.CreateClient(IWattTimeClient.NamedClient); + _authenticationClient = factory.CreateClient(IWattTimeClient.NamedAuthenticationClient); + _configurationMonitor = configurationMonitor; _log = log; _configuration.Validate(); _client.BaseAddress = new Uri(this._configuration.BaseUrl); _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json)); + + _authenticationClient.BaseAddress = new Uri(this._configuration.AuthenticationBaseUrl); + _authenticationClient.DefaultRequestHeaders.Accept.Clear(); + _authenticationClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json)); + _memoryCache = memoryCache; } @@ -215,7 +223,7 @@ private async Task UpdateAuthTokenAsync() _log.LogInformation("Attempting to log in user {username}", this._configuration.Username); this.SetBasicAuthenticationHeader(); - HttpResponseMessage response = await this._client.GetAsync(Paths.Login); + HttpResponseMessage response = await this._authenticationClient.GetAsync(Paths.Login); LoginResult? data = null; @@ -239,6 +247,7 @@ private void SetBasicAuthenticationHeader() { var authToken = Encoding.UTF8.GetBytes($"{this._configuration.Username}:{this._configuration.Password}"); this._client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(AuthenticationHeaderTypes.Basic, Convert.ToBase64String(authToken)); + this._authenticationClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(AuthenticationHeaderTypes.Basic, Convert.ToBase64String(authToken)); } internal void SetBearerAuthenticationHeader(string token) diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/WattTimeClientConfiguration.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/WattTimeClientConfiguration.cs index 746cd2b4c..104aeb759 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/WattTimeClientConfiguration.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/WattTimeClientConfiguration.cs @@ -25,6 +25,12 @@ internal class WattTimeClientConfiguration /// public string BaseUrl { get; set; } = "https://api2.watttime.org/v2/"; + /// + /// Authentication base url. This changed between v2 and v3 + /// to be different to the API base url. + /// + public string AuthenticationBaseUrl { get; set; } = "https://api.watttime.org/"; + /// /// Gets or sets the cached expiration time (in seconds) for a BalancingAuthority instance. /// It defaults to 86400 secs. @@ -51,6 +57,11 @@ public void Validate() throw new ConfigurationException($"{Key}:{nameof(this.BaseUrl)} is not a valid absolute url."); } + if (!Uri.IsWellFormedUriString(this.AuthenticationBaseUrl, UriKind.Absolute)) + { + throw new ConfigurationException($"{Key}:{nameof(this.AuthenticationBaseUrl)} is not a valid absolute url."); + } + // Validate credential encoding/decoding with UTF8 if (!Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(this.Username)).Equals(this.Username)) {