using FabAccessAPI.Schema; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace FabAccessAPI { public class MachineException : Exception { } /// /// Wraps a capability for accessing the Machines subsystem of BFFH /// public class Machines { private readonly IMachines _machinesCap; /// /// Constructs the Wrapper Class from a given capability. /// /// The capability that should be wrapped. public Machines(IMachines machinesCap) { _machinesCap = machinesCap; } /// /// List of all machines that BFFH knows about the user has been granted at least read access on /// /// ReadOnlyList of available Machines public async Task?> ListMachines() { IReadOnlyList? machineList = await _machinesCap.ListMachines().ConfigureAwait(false); List machineList_new = new List(); foreach(Schema.Machine machine in machineList) { machineList_new.Add(new Machine(machine)); } return machineList_new; } /// /// Access a particular machine by known name. This may fail for two reasons: /// The user has not been granted access to know the machine exists or the machine does in fact not exist. /// In both cases the `machine` result will be a NULL-pointer /// /// Name of the Machine /// The Machine we requested public async Task GetMachine(string name) { var mach = (await _machinesCap.GetMachine(name).ConfigureAwait(false)).Item1; if (mach == null) { //TODO: Throw a more specific exception! throw new MachineException(); } return new Machine(mach); } } /// /// A machine. This represents a machine as BFFH thinks about it which may mean ///several machines or just part of a machine in the real world. ///By itself this struct is completely useless since it contains only the information ///that the machine exists the user is allowed to know about that fact. For all further ///information the user has to call the contained capabilities which depending on the ///access level may not be set. For example an admin will have every capability here ///set but a simple user may only have `read` and `write` set while some users may not /// even have `read` set and are unable to even see if the machine is currently in use. /// public class Machine { private readonly Schema.Machine _machine; /// /// Constructs the Wrapper Class from a given capability /// /// The capability that should be wrapped. public Machine(Schema.Machine machine) { _machine = machine; } // read operations /// /// Get the MInfo Struct for the Machine. /// This contains everything BFFH knows about the Machine. /// /// /// The MInfo Struct describing the Machine public async Task GetMInfo() { var readCap = _machine.Read; if (readCap == null) { throw new UnauthorizedException(); } return (await _machine.Read.Info().ConfigureAwait(false)).Item1; } //write operations /// /// Try to use a machine. Throws a UnauthorizedException if the user does not have the required /// permissions to use this machine. /// /// Use the Ret() Method of the returned Object to return the machine /// /// /// Capability to give back the machine public Task Use() { var writeCap = _machine.Write; if (writeCap == null) { throw new UnauthorizedException(); } return writeCap.Use(); } /// /// Try to get a GiveBack capability for a machine. /// /// Capability to give back the machine or null /// public Task GetGiveBack() { var writeCap = _machine.Write; if (writeCap == null) { throw new UnauthorizedException(); } return writeCap.GetGiveBack(); } /// /// Try to reserve a machine. Throws a UnauthorizedException if the user does not have the required /// permissions to use this machine. /// /// Use the Ret() Method of the returned Object to return the machine /// Use the Use() Nethod of the Machine to use your reserved machine. /// /// /// Capability to give back the machine public Task Reserve() { var writeCap = _machine.Write; if (writeCap == null) { throw new UnauthorizedException(); } return writeCap.Reserve(); } // public void GiveBack(Schema.Machine.WriteInterface.IGiveBack cap) { // cap.Ret(); // } //manage operations /// /// After a machine has been used by an user with low enough permissions it's /// in the 'toCheck' state. This call then allows more priviledged users to /// "check" the machine and move it to the `free` state. /// /// Calling this method signifies that the machine was checked and in an acceptable state. /// public async void MarkOk() { var manageCap = _machine.Manage; if (manageCap == null) { throw new UnauthorizedException(); } // TODO: Do we really want to check this here? if ((await GetMInfo().ConfigureAwait(false)).State == State.toCheck) { await _machine.Manage.Ok().ConfigureAwait(false); } } /// /// After a machine has been used by an user with low enough permissions it's /// in the 'toCheck' state. This call then allows more priviledged users to /// "check" the machine and move it to the `free` state. /// /// Calling this method signifies that the machine was checked and in an unacceptable state. /// It will most likely be marked as `blocked` and the previous user will somehow be informed. /// public async void MarkNotOk() { var manageCap = _machine.Manage; if (manageCap == null) { throw new UnauthorizedException(); } // TODO: Do we really want to check this here? if ((await GetMInfo().ConfigureAwait(false)).State == State.toCheck) { await _machine.Manage.NotOk().ConfigureAwait(false); } } //administrative operations /// /// Forcefully set a machine state. /// /// The desired machine state. public async void ForceSetState(State state) { var adminCap = _machine.Admin; if (adminCap == null) { throw new UnauthorizedException(); } await adminCap.ForceSetState(state).ConfigureAwait(false); } /// /// Set the given user as current responsible /// /// The user public async void ForceSetUser(String user) { var adminCap = _machine.Admin; if (adminCap == null) { throw new UnauthorizedException(); } await adminCap.ForceSetUser(user).ConfigureAwait(false); } } }