2021-06-26 20:57:55 +02:00
using System ;
2021-05-13 20:03:07 +02:00
using System.Linq ;
using System.Threading.Tasks ;
2022-08-30 15:42:25 +02:00
using Serilog ;
using TINK.Model.Bikes ;
using TINK.Model.Connector.Updater ;
2021-05-13 20:03:07 +02:00
using TINK.Model.Services.CopriApi ;
2021-06-26 20:57:55 +02:00
using TINK.Repository ;
2021-05-13 20:03:07 +02:00
namespace TINK.Model.Connector
{
2022-09-06 16:08:19 +02:00
/// <summary> Provides query functionality for a logged in user. </summary>
public class CachedQueryLoggedIn : BaseLoggedIn , IQuery
{
/// <summary> Cached copri server. </summary>
private ICachedCopriServer Server { get ; }
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public CachedQueryLoggedIn ( ICopriServerBase copriServer ,
string sessionCookie ,
string mail ,
Func < DateTime > dateTimeProvider ) : base ( copriServer , sessionCookie , mail , dateTimeProvider )
{
Server = copriServer as ICachedCopriServer ;
if ( Server = = null )
{
throw new ArgumentException ( $"Copri server is not of expected typ. Type detected is {copriServer.GetType()}." ) ;
}
}
/// <summary> Gets all stations including postions.</summary>
public async Task < Result < StationsAndBikesContainer > > GetBikesAndStationsAsync ( )
{
var stationsResponse = await Server . GetStations ( ) ;
if ( stationsResponse . Source = = typeof ( CopriCallsMonkeyStore )
| | stationsResponse . Exception ! = null )
{
// Stations were read from cache ==> get bikes availbalbe and occupied from cache as well to avoid inconsistencies
return new Result < StationsAndBikesContainer > (
stationsResponse . Source ,
new StationsAndBikesContainer (
stationsResponse . Response . GetStationsAllMutable ( ) ,
UpdaterJSON . GetBikesAll (
( await Server . GetBikesAvailable ( true ) ) . Response ? . bikes ? . Values ,
( await Server . GetBikesOccupied ( true ) ) . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ) ,
stationsResponse . GeneralData ,
stationsResponse . Exception ) ;
}
var bikesAvailableResponse = await Server . GetBikesAvailable ( ) ;
if ( bikesAvailableResponse . Source = = typeof ( CopriCallsMonkeyStore )
| | bikesAvailableResponse . Exception ! = null )
{
// Bikes avilable were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies
return new Result < StationsAndBikesContainer > (
bikesAvailableResponse . Source ,
new StationsAndBikesContainer (
( await Server . GetStations ( true ) ) . Response . GetStationsAllMutable ( ) ,
UpdaterJSON . GetBikesAll ( bikesAvailableResponse . Response ? . bikes ? . Values ,
( await Server . GetBikesOccupied ( true ) ) . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ) ,
bikesAvailableResponse . GeneralData ,
bikesAvailableResponse . Exception ) ;
}
var bikesOccupiedResponse = await Server . GetBikesOccupied ( ) ;
if ( bikesOccupiedResponse . Source = = typeof ( CopriCallsMonkeyStore )
| | bikesOccupiedResponse . Exception ! = null )
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
return new Result < StationsAndBikesContainer > (
bikesOccupiedResponse . Source ,
new StationsAndBikesContainer (
( await Server . GetStations ( true ) ) . Response . GetStationsAllMutable ( ) ,
UpdaterJSON . GetBikesAll (
( await Server . GetBikesAvailable ( true ) ) . Response ? . bikes ? . Values ,
bikesOccupiedResponse . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ) ,
bikesOccupiedResponse . GeneralData ,
bikesOccupiedResponse . Exception ) ;
}
// Both types bikes could read from copri => update cache
Server . AddToCache ( stationsResponse ) ;
Server . AddToCache ( bikesAvailableResponse ) ;
Server . AddToCache ( bikesOccupiedResponse ) ;
var exceptions = new [ ] { stationsResponse ? . Exception , bikesAvailableResponse ? . Exception , bikesOccupiedResponse ? . Exception } . Where ( x = > x ! = null ) . ToArray ( ) ;
var stationsMutable = stationsResponse . Response . GetStationsAllMutable ( ) ;
var bikesMutable = UpdaterJSON . GetBikesAll (
bikesAvailableResponse . Response ? . bikes ? . Values ,
bikesOccupiedResponse . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ;
return new Result < StationsAndBikesContainer > (
stationsResponse . Source ,
new StationsAndBikesContainer ( stationsMutable , bikesMutable ) ,
stationsResponse . GeneralData ,
exceptions . Length > 0 ? new AggregateException ( exceptions ) : null ) ;
}
/// <summary> Gets bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task < Result < BikeCollection > > GetBikesOccupiedAsync ( )
{
var bikesAvailableResponse = await Server . GetBikesAvailable ( false ) ;
if ( bikesAvailableResponse . Source = = typeof ( CopriCallsMonkeyStore )
| | bikesAvailableResponse . Exception ! = null )
{
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
Log . ForContext < CachedQueryLoggedIn > ( ) . Debug ( "Bikes available read from cache. Reading bikes occupied from cache as well." ) ;
return new Result < BikeCollection > (
bikesAvailableResponse . Source ,
UpdaterJSON . GetBikesAll (
bikesAvailableResponse . Response ? . bikes ? . Values ? . Where ( bike = > bike . GetState ( ) = = State . InUseStateEnum . FeedbackPending ) ,
( await Server . GetBikesOccupied ( true ) ) ? . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ,
bikesAvailableResponse . GeneralData ,
bikesAvailableResponse . Exception ) ;
}
var bikesOccupiedResponse = await Server . GetBikesOccupied ( false ) ;
if ( bikesOccupiedResponse . Source = = typeof ( CopriCallsMonkeyStore )
| | bikesOccupiedResponse . Exception ! = null )
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
Log . ForContext < CachedQueryLoggedIn > ( ) . Debug ( "Bikes occupied read from cache. Reread bikes available from cache as well." ) ;
return new Result < BikeCollection > (
bikesOccupiedResponse . Source ,
UpdaterJSON . GetBikesAll (
( await Server . GetBikesAvailable ( true ) ) . Response ? . bikes ? . Values ? . Where ( bike = > bike . GetState ( ) = = State . InUseStateEnum . FeedbackPending ) ,
bikesOccupiedResponse . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ,
bikesOccupiedResponse . GeneralData ,
bikesOccupiedResponse . Exception ) ;
}
// Both types bikes could read from copri => update bikes occupied cache.
// // Do not add bikes available to cache because this might lead to conflicts calls GetBikesAsync() and bikes with FeedbackPending state are of no use offline.
Server . AddToCache ( bikesOccupiedResponse ) ;
return new Result < BikeCollection > (
bikesOccupiedResponse . Source ,
UpdaterJSON . GetBikesAll (
bikesAvailableResponse ? . Response . bikes ? . Values ? . Select ( bike = > bike ) ? . Where ( bike = > bike . GetState ( ) = = State . InUseStateEnum . FeedbackPending ) ,
bikesOccupiedResponse ? . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ,
bikesOccupiedResponse . GeneralData ,
bikesOccupiedResponse . Exception ) ;
}
/// <summary> Gets bikes available and bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task < Result < BikeCollection > > GetBikesAsync ( )
{
var bikesAvailableResponse = await Server . GetBikesAvailable ( ) ;
if ( bikesAvailableResponse . Source = = typeof ( CopriCallsMonkeyStore )
| | bikesAvailableResponse . Exception ! = null )
{
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
Log . ForContext < CachedQueryLoggedIn > ( ) . Debug ( "Bikes available read from cache. Reading bikes occupied from cache as well." ) ;
return new Result < BikeCollection > (
bikesAvailableResponse . Source ,
UpdaterJSON . GetBikesAll (
bikesAvailableResponse . Response ? . bikes ? . Values ,
( await Server . GetBikesOccupied ( true ) ) . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ,
bikesAvailableResponse . GeneralData ,
bikesAvailableResponse . Exception ) ;
}
var bikesOccupiedResponse = await Server . GetBikesOccupied ( ) ;
if ( bikesOccupiedResponse . Source = = typeof ( CopriCallsMonkeyStore )
| | bikesOccupiedResponse . Exception ! = null )
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
Log . ForContext < CachedQueryLoggedIn > ( ) . Debug ( "Bikes occupied read from cache. Reread bikes available from cache as well." ) ;
return new Result < BikeCollection > (
bikesOccupiedResponse . Source ,
UpdaterJSON . GetBikesAll (
( await Server . GetBikesAvailable ( true ) ) . Response ? . bikes ? . Values ,
bikesOccupiedResponse . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ,
bikesOccupiedResponse . GeneralData ,
bikesOccupiedResponse . Exception ) ;
}
// Both types bikes could read from copri => update cache
Server . AddToCache ( bikesAvailableResponse ) ;
Server . AddToCache ( bikesOccupiedResponse ) ;
Log . ForContext < CachedQueryLoggedIn > ( ) . Debug ( "Bikes available and occupied read successfully from server." ) ;
return new Result < BikeCollection > (
bikesAvailableResponse . Source ,
UpdaterJSON . GetBikesAll (
bikesAvailableResponse . Response ? . bikes ? . Values ,
bikesOccupiedResponse . Response ? . bikes_occupied ? . Values ,
Mail ,
DateTimeProvider ) ,
bikesAvailableResponse . GeneralData ,
bikesAvailableResponse . Exception ! = null | | bikesOccupiedResponse . Exception ! = null ? new AggregateException ( new [ ] { bikesAvailableResponse . Exception , bikesOccupiedResponse . Exception } ) : null ) ;
}
}
2021-05-13 20:03:07 +02:00
}