using Dfs.WayneChina.SpsDataCourier.Models; using Newtonsoft.Json; using Polly; using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; namespace Dfs.WayneChina.SpsDataCourier { public class DataCourier { #region Fields private HttpClient _client = new HttpClient(); private ConnectionInfo connectionInfo; private string grantType = "password"; private string tokenAuthPath = "token"; private string authScheme = "bearer"; private int retryCount; private AuthToken currentAuthToken; #endregion #region Logger NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("SpsDataCourier"); #endregion #region Constructor public DataCourier(string username, string password, string authServiceBaseUrl, string accountServiceBaseUrl, string accountServiceRelativeUrl, string deviceSN, int retryCount) { connectionInfo = new ConnectionInfo { UserName = username, Password = password, AuthServiceBaseUrl = authServiceBaseUrl, AccountServiceBaseUrl = accountServiceBaseUrl, AccountServiceRelativeUrl = accountServiceRelativeUrl, DeviceSN = deviceSN }; this.retryCount = retryCount; _client.DefaultRequestHeaders.Clear(); } #endregion #region Get token public void GetToken() { currentAuthToken = GetTokenAsync(connectionInfo.UserName, connectionInfo.Password, connectionInfo.AuthServiceBaseUrl).Result; } private async Task GetTokenAsync(string userName, string password, string baseUrl) { logger.Info("Start to get token..."); _client.DefaultRequestHeaders.Clear(); string tokenUrl = string.Concat(baseUrl, tokenAuthPath); var formParam = new AuthenticationParameter(grantType, userName, password); try { var response = await _client.PostAsync(tokenUrl, new FormUrlEncodedContent(formParam.Params)).ConfigureAwait(false); logger.Info($"Get token, StatusCode = {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { currentAuthToken = JsonConvert.DeserializeObject(x?.Result); currentAuthToken.TokenRetrievedTime = DateTime.Now; }); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); } return currentAuthToken; } catch (Exception ex) { logger.Error(ex.ToString()); return null; } } #endregion #region Send request public async Task SendRequest(OfflineRequest offlineRequest, HostOperationType operationType) { if (currentAuthToken != null && currentAuthToken.IsTokenValid()) { if (!_client.DefaultRequestHeaders.Contains("DeviceSN")) _client.DefaultRequestHeaders.Add("DeviceSN", connectionInfo.DeviceSN); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, currentAuthToken.AccessToken); Response resp = null; // // Create account // if (operationType == HostOperationType.CreateAccount) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PostAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}", offlineRequest) .ConfigureAwait(false); logger.Info($"Upload account, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } // // Update account // else if (operationType == HostOperationType.UpdateAccount) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PutAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/update", offlineRequest) .ConfigureAwait(false); logger.Info($"Update account, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } // // Create card // else if (operationType == HostOperationType.CreateCard) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PostAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/cardInfo", offlineRequest) .ConfigureAwait(false); logger.Info($"Upload card, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } // // Update card // else if (operationType == HostOperationType.UpdateCard) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PutAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/update", offlineRequest) .ConfigureAwait(false); logger.Info($"Update card, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } else if (operationType == HostOperationType.DisableAccount) { } // // Create payment record // else if (operationType == HostOperationType.CreatePayRecord) { var requestString = JsonConvert.SerializeObject(offlineRequest); logger.Info("Card Pay record: " + requestString); try { var maxRetryAttempts = retryCount; var pauseBetweenFailures = TimeSpan.FromSeconds(3); var retryPolicy = Policy .Handle() .WaitAndRetryAsync(maxRetryAttempts, i => pauseBetweenFailures, (exception, timeSpan, retryCount, context) => { logger.Info("Wait and retry"); }); var uploadResult = await retryPolicy.ExecuteAsync(async () => { logger.Info("Executing Polly policy..."); if (!_client.DefaultRequestHeaders.Contains("DeviceSN")) { logger.Info("Check again the DeviceSN before sending"); _client.DefaultRequestHeaders.Add("DeviceSN", connectionInfo.DeviceSN); } var response = await _client.PostAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/payment", offlineRequest) .ConfigureAwait(false); logger.Info($"Upload pay record, StatusCode: {(int)response?.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) // 2=Don't retry { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } }); return uploadResult; } catch (Exception ex) { logger.Error($"Upload Pay record exception: {ex}"); return ErrorResult(); } } // // Recharge and reduction record // else if (operationType == HostOperationType.CreateRechargeRecord) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PostAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/recharge", offlineRequest) .ConfigureAwait(false); logger.Info($"Upload recharge/reduction record, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } //Card operations, report for loss, release card, close card... else if (operationType == HostOperationType.CardOperation) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PutAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/update", offlineRequest) .ConfigureAwait(false); logger.Info($"Card Operation, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } else if (operationType == HostOperationType.ListedCard) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PostAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/blackCard", offlineRequest) .ConfigureAwait(false); logger.Info($"Black Card, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } else if (operationType == HostOperationType.GrayInfo) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PostAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/grayInfo", offlineRequest) .ConfigureAwait(false); logger.Info($"GrayInfo, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } else if (operationType == HostOperationType.CardRepLoss) { var request = JsonConvert.SerializeObject(offlineRequest); logger.Info(request); try { var response = await _client.PostAsJsonAsync($"{connectionInfo.AccountServiceBaseUrl}{connectionInfo.AccountServiceRelativeUrl}/cardRepLoss", offlineRequest) .ConfigureAwait(false); logger.Info($"CardRepLoss, StatusCode: {(int)response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { resp = JsonConvert.DeserializeObject(x?.Result); }); if (resp != null) { logger.Info($" StatusCode: {resp.StatusCode}, Result: {resp.Result}, Message: {resp.Message}"); if (resp.Result == 0 || resp.Result == 2) { return OkResult(resp.Result); } } return FailedResult(resp.Result); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); return ErrorResult(); } } catch (Exception ex) { logger.Error(ex); return ErrorResult(); } } } else { currentAuthToken = await GetTokenAsync(connectionInfo.UserName, connectionInfo.Password, connectionInfo.AuthServiceBaseUrl); if (currentAuthToken != null && currentAuthToken.IsTokenValid()) { return await SendRequest(offlineRequest, operationType); } } logger.Info("Reached here? Impossible"); return ErrorResult(); } #endregion private SendResult OkResult(int code) { return new SendResult { Success = true, Code = code }; } private SendResult FailedResult(int code) { return new SendResult { Success = false, Code = code }; } private SendResult ErrorResult() { return new SendResult { Success = false, Code = -1 }; } } }