mirror of
https://gitlab.com/fabinfra/fabaccess/borepin.git
synced 2025-03-12 23:01:52 +01:00
316 lines
11 KiB
C#
316 lines
11 KiB
C#
using System;
|
|
using Borepin.Model;
|
|
using System.Threading.Tasks;
|
|
using System.Collections.Generic;
|
|
using FabAccessAPI.Schema;
|
|
|
|
using Borepin.Service.Storage;
|
|
using Borepin.Model.Storage;
|
|
using Borepin.Service.BFFH.Exceptions;
|
|
using Borepin.Service.Storage.Exceptions;
|
|
|
|
namespace Borepin.Service.BFFH
|
|
{
|
|
public class BFFHService : IBFFHService
|
|
{
|
|
#region Private Fields
|
|
private readonly ConnectionStorage _ConnectionStorage;
|
|
private readonly ConnectionCredentialStorage _ConnectionCredentialStorage;
|
|
|
|
private FabAccessAPI.Connection _APIConnection;
|
|
private Connection_Plain _CurrentConnection;
|
|
#endregion
|
|
|
|
#region Constructors
|
|
public BFFHService(IPreferenceStorageService preferenceStorageService, ISecretStorageService secretStorageService)
|
|
{
|
|
_ConnectionStorage = new ConnectionStorage(preferenceStorageService);
|
|
_ConnectionCredentialStorage = new ConnectionCredentialStorage(secretStorageService);
|
|
}
|
|
#endregion
|
|
|
|
#region Fields
|
|
|
|
/// <summary>
|
|
/// Current Connection of Service
|
|
/// </summary>
|
|
public Connection CurrentConnection
|
|
{
|
|
get
|
|
{
|
|
return _CurrentConnection;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if Service is connected to a Server
|
|
/// </summary>
|
|
public bool IsConnected
|
|
{
|
|
get
|
|
{
|
|
if (_APIConnection != null && _APIConnection.RpcClient != null)
|
|
{
|
|
return _APIConnection.RpcClient.State == Capnp.Rpc.ConnectionState.Active;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Methods
|
|
/// <summary>
|
|
/// Get all known Connections from Storage
|
|
/// </summary>
|
|
public async Task<IList<Connection>> GetConnections()
|
|
{
|
|
return await _ConnectionStorage.GetConnectionList().ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove Connection from Storage
|
|
/// </summary>
|
|
public async Task RemoveConnection(Connection connection)
|
|
{
|
|
if (IsConnected && connection.Equals(CurrentConnection))
|
|
{
|
|
await Disconnect().ConfigureAwait(false);
|
|
}
|
|
|
|
try
|
|
{
|
|
await _ConnectionCredentialStorage.RemoveCredentials(connection).ConfigureAwait(false);
|
|
}
|
|
catch (KeyNotFoundException)
|
|
{
|
|
|
|
}
|
|
|
|
try
|
|
{
|
|
await _ConnectionStorage.RemoveConnection(connection).ConfigureAwait(false);
|
|
}
|
|
catch (KeyNotFoundException)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test a if a Server is reachable
|
|
/// </summary>
|
|
public async Task<bool> TestConnection(Connection connection)
|
|
{
|
|
try
|
|
{
|
|
Capnp.Rpc.TcpRpcClient rpcClient = new Capnp.Rpc.TcpRpcClient();
|
|
rpcClient.Connect(connection.Address.Host, connection.Address.Port);
|
|
await rpcClient.WhenConnected.ConfigureAwait(false);
|
|
rpcClient.Dispose();
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Connects to Server with Credential from ConnectionCredentialStorage
|
|
/// </summary>
|
|
/// <exception cref="AllreadyConnectedException"></exception>
|
|
/// <exception cref="MissingCredentialsException"></exception>
|
|
/// <exception cref="ConnectingFailedException"></exception>
|
|
/// <exception cref="AuthenticatingFailedException"></exception>
|
|
public async Task Connect(Connection connection)
|
|
{
|
|
if (IsConnected)
|
|
{
|
|
throw new AllreadyConnectedException();
|
|
}
|
|
|
|
string password;
|
|
try
|
|
{
|
|
password = await _ConnectionCredentialStorage.GetPassword(connection).ConfigureAwait(false);
|
|
}
|
|
catch (KeyNotFoundException)
|
|
{
|
|
await _ConnectionCredentialStorage.RemoveAllCredentials().ConfigureAwait(false);
|
|
await _ConnectionStorage.RemoveAllConnections().ConfigureAwait(false);
|
|
|
|
throw new MissingCredentialsException();
|
|
}
|
|
|
|
try
|
|
{
|
|
Capnp.Rpc.TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
|
|
|
|
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
|
}
|
|
catch (Capnp.Rpc.RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
|
{
|
|
throw new ConnectingFailedException("Connecting failed", exception);
|
|
}
|
|
|
|
if (! await _AuthenticatePlainAsync(connection.Username, password).ConfigureAwait(false))
|
|
{
|
|
await Disconnect().ConfigureAwait(false);
|
|
throw new AuthenticatingFailedException();
|
|
}
|
|
|
|
_CurrentConnection = new Connection_Plain(connection)
|
|
{
|
|
Password = password,
|
|
};
|
|
await _ConnectionStorage.UpdateConnectionTimestamp(_CurrentConnection).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Connects to Server with Password
|
|
/// Connection is saved to Storage if connecting was successfuss
|
|
/// </summary>
|
|
/// <exception cref="AllreadyConnectedException"></exception>
|
|
/// <exception cref="MissingCredentialsException"></exception>
|
|
/// <exception cref="ConnectingFailedException"></exception>
|
|
/// <exception cref="AuthenticatingFailedException"></exception>
|
|
public async Task Connect(Connection connection, string password)
|
|
{
|
|
if (IsConnected)
|
|
{
|
|
throw new AllreadyConnectedException();
|
|
}
|
|
|
|
try
|
|
{
|
|
Capnp.Rpc.TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
|
|
|
|
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
|
}
|
|
catch (Capnp.Rpc.RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
|
{
|
|
throw new ConnectingFailedException("Connecting failed", exception);
|
|
}
|
|
|
|
if (!await _AuthenticatePlainAsync(connection.Username, password).ConfigureAwait(false))
|
|
{
|
|
await Disconnect().ConfigureAwait(false);
|
|
throw new AuthenticatingFailedException();
|
|
}
|
|
|
|
_CurrentConnection = new Connection_Plain(connection)
|
|
{
|
|
Password = password,
|
|
};
|
|
|
|
try
|
|
{
|
|
await _ConnectionStorage.AddConnection(_CurrentConnection).ConfigureAwait(false);
|
|
}
|
|
catch(DuplicateConnectionException)
|
|
{
|
|
|
|
}
|
|
await _ConnectionCredentialStorage.AddCredentials(_CurrentConnection, password).ConfigureAwait(false);
|
|
await _ConnectionStorage.UpdateConnectionTimestamp(_CurrentConnection).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reconnects to server if connection has lost
|
|
/// </summary>
|
|
/// <exception cref="InvalidOperationException"></exception>
|
|
/// <exception cref="ReconnectingFailedException"></exception>
|
|
public async Task Reconnect()
|
|
{
|
|
if (IsConnected || _CurrentConnection == null)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
try
|
|
{
|
|
Capnp.Rpc.TcpRpcClient rpcClient = await _ConnectAsync(_CurrentConnection.Address.Host, _CurrentConnection.Address.Port).ConfigureAwait(false);
|
|
|
|
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
|
}
|
|
catch (Capnp.Rpc.RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
|
{
|
|
throw new ReconnectingFailedException("Connecting failed", new ConnectingFailedException("Connecting failed", exception));
|
|
}
|
|
|
|
if (! await _AuthenticatePlainAsync(_CurrentConnection.Username, _CurrentConnection.Password).ConfigureAwait(false))
|
|
{
|
|
throw new ReconnectingFailedException("Authentication failed", new AuthenticatingFailedException());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disconnects from Server
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public Task Disconnect()
|
|
{
|
|
if (IsConnected)
|
|
{
|
|
_APIConnection.RpcClient?.Dispose();
|
|
}
|
|
|
|
_APIConnection = null;
|
|
_CurrentConnection = null;
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
#region FabAccess API Systems
|
|
public async Task<IMachineSystem> GetMachineSystemInterface()
|
|
{
|
|
if (!IsConnected)
|
|
{
|
|
await Reconnect().ConfigureAwait(false);
|
|
}
|
|
|
|
return await _APIConnection.AccessMachineSystem().ConfigureAwait(false);
|
|
}
|
|
|
|
public async Task<IUserSystem> GetUserSystemInterface()
|
|
{
|
|
if (!IsConnected)
|
|
{
|
|
await Reconnect().ConfigureAwait(false);
|
|
}
|
|
|
|
return await _APIConnection.AccessUserSystem().ConfigureAwait(false);
|
|
}
|
|
|
|
public async Task<IPermissionSystem> GetPermissionSystemInterface()
|
|
{
|
|
if (!IsConnected)
|
|
{
|
|
await Reconnect().ConfigureAwait(false);
|
|
}
|
|
|
|
return await _APIConnection.AccessPermissionSystem().ConfigureAwait(false);
|
|
}
|
|
#endregion
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
private static async Task<Capnp.Rpc.TcpRpcClient> _ConnectAsync(string host, int port)
|
|
{
|
|
Capnp.Rpc.TcpRpcClient rpcClient = new Capnp.Rpc.TcpRpcClient();
|
|
rpcClient.Connect(host, port);
|
|
await rpcClient.WhenConnected.ConfigureAwait(false);
|
|
|
|
return rpcClient;
|
|
}
|
|
|
|
private Task<bool> _AuthenticatePlainAsync(string username, string password)
|
|
{
|
|
return _APIConnection.Auth("PLAIN", new Dictionary<string, object>(StringComparer.Ordinal) { { "Username", username }, { "Password", password } });
|
|
}
|
|
#endregion
|
|
}
|
|
}
|