using System; using System.Collections.Generic; using System.Linq; using System.Security.Authentication; using System.Text; using System.Threading.Tasks; using Tango.Transport.Web; using Tango.Web.Security; namespace Tango.Web { public abstract class TangoWebClient : IDisposable where TLoginRequest : WebRequestMessage where TLoginResponse : WebTokenResponse { private WebTransportClient _client; private bool _disposed; private TLoginRequest _lastLoginRequest; private DeploymentSlot? _environment; public DeploymentSlot? Environment { get { return _environment; } set { if (_environment != value) { _lastLoginRequest = null; IsAuthenticated = false; } _environment = value; } } public String Address { get; set; } public String Controller { get; private set; } public String Token { get; private set; } public WebToken WebToken { get; private set; } public bool IsAuthenticated { get; private set; } public TimeSpan RequestTimeout { get { return _client.RequestTimeout; } set { _client.RequestTimeout = value; } } public TangoWebClient(DeploymentSlot environment, String controller) { _client = new WebTransportClient(); Controller = controller; Environment = environment; } public TangoWebClient(DeploymentSlot environment, String controller, String token) : this(environment, controller) { Token = token; } public TangoWebClient(String address, String controller, String token) { _client = new WebTransportClient(); Address = address; Controller = controller; Token = token; } public TangoWebClient(TangoWebClient cloned) { _client = new WebTransportClient(); Environment = cloned.Environment; Address = cloned.Address; Controller = cloned.Controller; IsAuthenticated = cloned.IsAuthenticated; RequestTimeout = cloned.RequestTimeout; WebToken = cloned.WebToken; _lastLoginRequest = cloned._lastLoginRequest; Token = cloned.Token; } public T Clone() where T : TangoWebClient { return Activator.CreateInstance(typeof(T), new object[] { this }) as T; } public async Task Login(TLoginRequest request) { var response = await _client.PostJson(GetActionAddress("Login"), request); Token = response.AccessToken; _client.AuthenticationToken = Token; WebToken = WebToken.FromToken(Token); _lastLoginRequest = request; IsAuthenticated = true; return response; } protected virtual async Task Post(String action, TRequest request) where TRequest : class, IWebRequestMessage where TResponse : class, IWebResponseMessage { if (IsAuthenticated) { if (DateTime.UtcNow >= WebToken.Expiration) { await Login(_lastLoginRequest); } } try { var response = await _client.PostJson(GetActionAddress(action), request); return response; } catch (TokenExpiredException) { try { await Login(_lastLoginRequest); var response = await _client.PostJson(GetActionAddress(action), request); return response; } catch { throw; } } catch (Exception ex) { throw; } } private String GetActionAddress(String action) { return GetServiceAddress() + action; } protected virtual String GetServiceAddress() { if (Environment != null) { return Environment.Value.ToAddress() + $"/api/{Controller}/"; } else { return Address + $"/api/{Controller}/"; } } public virtual void Dispose() { if (!_disposed) { _disposed = true; _client.Dispose(); } } } }