예제 #1
0
 /// <summary>
 /// Get an object by the provided key.
 /// Returns null if no object is found.
 /// </summary>
 /// <param name="key">Lookup key</param>
 /// <returns>T</returns>
 public virtual async Task<T> Get<T>(string key) where T : class, IKeyProvider
 {
     try
     {
         return await _blobCache.GetObject<T>(key);
     }
     catch (KeyNotFoundException)
     {
         return null;
     }
 }
예제 #2
0
        public async Task LoadInfoAsync(ulong guildId)
        {
            if (Info != null)
            {
                return;
            }

            bool needsReset = false;

            try
            {
                Info = await _blobCache.GetObject <CacheInfo>("info");

                if (Info.GuildId != guildId)
                {
                    needsReset = true;
                }
            }
            catch (KeyNotFoundException)
            {
                needsReset = true;
            }
            if (needsReset)
            {
                Info = new CacheInfo()
                {
                    GuildId = guildId, Version = 0
                };
                await SaveInfoAsync().ConfigureAwait(false);
            }
        }
예제 #3
0
        public static IObservable <T> CacheApiResult <T>(
            this IObservable <T> source,
            string cacheKey,
            IBlobCache blobCache,
            IFullLogger?logger   = null,
            IScheduler?scheduler = null,
            bool forceUpdate     = false,
            TimeSpan expiration  = default)
        {
            expiration = expiration == TimeSpan.Zero ? Constants.DefaultCacheExpirationTimeOut : expiration;

            if (forceUpdate)
            {
                // TODO: [rlittlesii: July 30, 2020] Add retry and cached
                return(source.SelectMany(async value =>
                {
                    await blobCache.InsertObject(cacheKey, value, expiration);

                    logger?.Debug($"CACHE: Writing {{Value}} to cache with key: {{CacheKey}}", value, cacheKey);

                    return value;
                }));
            }

            blobCache
            .GetObject <T>(cacheKey)
            .Subscribe(obj => logger?.Debug("Found: {@Object}", obj));

            // TODO: [rlittlesii: July 30, 2020] Add retry and cached
            return(blobCache
                   .GetOrFetchObject(
                       cacheKey,
                       () => source.Timeout(Constants.DefaultRequestTimeout), DateTimeOffset.Now.Add(expiration)));
        }
 /// <summary>
 /// Check a file to see if it needs to be re-downloaded.
 /// </summary>
 /// <param name="file">The file to look at for updates, which must already exist in the blob cache</param>
 /// <returns>True once if we need to update again.</returns>
 /// <remarks>
 /// We use the date from the headers of the file to understand if we need to update. That way we don't have to deal
 /// with translating time-zones, and anything funny from indico.
 ///
 /// If something goes wrong (e.g. we are offline), the also return false.
 /// If the cache is missing the item, then we need to update.
 /// </remarks>
 public static IObservable <bool> CheckForUpdate(this IFile file, IBlobCache cache)
 {
     return(cache.GetObject <string>(file.FileDateKey())
            .Zip(file.GetFileDate(), (cacheDate, remoteDate) => cacheDate != remoteDate)
            .Catch <bool, KeyNotFoundException>(_ => Observable.Return(true))
            .Catch(Observable.Return(false)));
 }
예제 #5
0
        /// <summary>
        /// This method attempts to returned a cached value, while
        /// simultaneously calling a Func to return the latest value. When the
        /// latest data comes back, it replaces what was previously in the
        /// cache.
        ///
        /// This method is best suited for loading dynamic data from the
        /// Internet, while still showing the user earlier data.
        ///
        /// This method returns an IObservable that may return *two* results
        /// (first the cached data, then the latest data). Therefore, it's
        /// important for UI applications that in your Subscribe method, you
        /// write the code to merge the second result when it comes in.
        ///
        /// This also means that await'ing this method is a Bad Idea(tm), always
        /// use Subscribe.
        /// </summary>
        /// <param name="key">The key to store the returned result under.</param>
        /// <param name="fetchFunc"></param>
        /// <param name="fetchPredicate">An optional Func to determine whether
        /// the updated item should be fetched. If the cached version isn't found,
        /// this parameter is ignored and the item is always fetched.</param>
        /// <param name="absoluteExpiration">An optional expiration date.</param>
        /// <param name="shouldInvalidateOnError">If this is true, the cache will
        /// be cleared when an exception occurs in fetchFunc</param>
        /// <returns>An Observable stream containing either one or two
        /// results (possibly a cached version, then the latest version)</returns>
        public static IObservable <T> GetAndFetchLatest <T>(this IBlobCache This,
                                                            string key,
                                                            Func <IObservable <T> > fetchFunc,
                                                            Func <DateTimeOffset, bool> fetchPredicate = null,
                                                            DateTimeOffset?absoluteExpiration          = null,
                                                            bool shouldInvalidateOnError = false)
        {
            var fetch = Observable.Defer(() => This.GetObjectCreatedAt <T>(key))
                        .Select(x => fetchPredicate == null || x == null || fetchPredicate(x.Value))
                        .Where(x => x != false)
                        .SelectMany(_ =>
            {
                var fetchObs = fetchFunc().Catch <T, Exception>(ex =>
                {
                    var shouldInvalidate = shouldInvalidateOnError ?
                                           This.InvalidateObject <T>(key) :
                                           Observable.Return(Unit.Default);
                    return(shouldInvalidate.SelectMany(__ => Observable.Throw <T>(ex)));
                });

                return(fetchObs
                       .SelectMany(x => This.InvalidateObject <T>(key).Select(__ => x))
                       .SelectMany(x => This.InsertObject <T>(key, x, absoluteExpiration).Select(__ => x)));
            });

            var result = This.GetObject <T>(key).Select(x => new Tuple <T, bool>(x, true))
                         .Catch(Observable.Return(new Tuple <T, bool>(default(T), false)));

            return(result.SelectMany(x =>
            {
                return x.Item2 ?
                Observable.Return(x.Item1) :
                Observable.Empty <T>();
            }).Concat(fetch).Multicast(new ReplaySubject <T>()).RefCount());
        }
예제 #6
0
        /// <summary>
        /// This method attempts to returned a cached value, and fetch one from
        /// the web. Optionally, it can continue to query to see if an update is required.
        ///
        /// If the cached value exists, it is returned. Then the predicate is queried to see
        /// if the remote value should be refreshed.
        ///
        /// If there is no cached value, then the value is fetched.
        ///
        /// Once the above is done, as the retrySequence comes in, the predicate will
        /// be called to see if a refresh is needed. If so, the data will be re-fetched.
        ///
        /// In all cases any remotely fetched data is cached.
        ///
        /// This also means that await'ing this method is a Bad Idea(tm), always
        /// use Subscribe. 1-infinity values can be returned depending on the arguments.
        /// </summary>
        /// <param name="key">The key to store the returned result under.</param>
        /// <param name="fetchFunc">A sequence that will return the new values of the data</param>
        /// <param name="fetchPredicate">A Func to determine whether
        /// the updated item should be fetched. Only called once a cached version exists.</param>
        /// <param name="retrySequence">Sequence that will trigger a predicate call followed by
        /// a fetch call if the predicate indicates so.</param>
        /// <param name="This">The blob cache against which we operate</param>
        /// <returns>An Observable stream containing one or more
        /// results (possibly a cached version, then the latest version(s))</returns>
        public static IObservable <T> GetAndFetchLatest <T>(this IBlobCache This,
                                                            string key,
                                                            Func <IObservable <T> > fetchFunc,
                                                            Func <DateTimeOffset, IObservable <bool> > fetchPredicate,
                                                            IObservable <Unit> retrySequence  = null,
                                                            DateTimeOffset?absoluteExpiration = null
                                                            )
        {
            if (fetchPredicate == null)
            {
                throw new ArgumentException("fetchPredicate");
            }
            if (fetchFunc == null)
            {
                throw new ArgumentException("fetchFunc");
            }

            // We are going to get the cache value if we can. And then we will run updates after that.
            // If we have nothing cached, then we will run the fetch directly. Otherwise we will run the
            // fetch sequence.

            var getOldKey = This.GetObjectCreatedAt <T>(key);

            var refetchIfNeeded = getOldKey
                                  .Where(dt => dt != null && dt.HasValue && dt.Value != null)
                                  .SelectMany(dt => fetchPredicate(dt.Value))
                                  .Where(doit => doit == true)
                                  .Select(_ => default(Unit));

            var fetchRequired = getOldKey
                                .Where(dt => dt == null || !dt.HasValue || dt.Value == null)
                                .Select(_ => default(Unit));

            // Next, get the item...

            var fetchFromCache = Observable.Defer(() => This.GetObject <T>(key))
                                 .Catch <T, KeyNotFoundException>(_ => Observable.Empty <T>());

            var fetchFromRemote = fetchRequired.Concat(refetchIfNeeded)
                                  .SelectMany(_ => fetchFunc())
                                  .SelectMany(x => This.InsertObject <T>(key, x, absoluteExpiration).Select(_ => x));

            var items = fetchFromCache.Concat(fetchFromRemote);

            // Once we have these, we also have to kick off a second set of fetches for our retry sequence.
            if (retrySequence == null)
            {
                return(items);
            }

            var getAfter = retrySequence
                           .SelectMany(_ => This.GetObjectCreatedAt <T>(key))
                           .SelectMany(dt => fetchPredicate(dt.Value))
                           .Where(doit => doit == true)
                           .SelectMany(_ => fetchFunc())
                           .SelectMany(x => This.InsertObject <T>(key, x, absoluteExpiration).Select(_ => x));

            return(items.Concat(getAfter));
        }
예제 #7
0
        public async Task <T> GetFromCache <T>(string cacheName)
        {
            try
            {
                T t = await _cache.GetObject <T>(cacheName);

                return(t);
            }
            catch (KeyNotFoundException)
            {
                return(default);
예제 #8
0
 private async Task <T> GetFromCacheAsync <T>(string cacheKey)
 {
     try
     {
         return(await cache.GetObject <T>(cacheKey));
     }
     catch (KeyNotFoundException)
     {
         return(default(T));
     }
 }
예제 #9
0
        public async Task <List <IPage> > FetchPages(string id)
        {
            Cache = BlobCache.LocalMachine;
            List <IPage> getPagesTask = await GetPagesAsync(id);

            await Cache.InsertObject("pages", getPagesTask, DateTimeOffset.Now.AddHours(2));

            List <IPage> pages = await Cache.GetObject <List <IPage> >("pages");

            return(pages);
        }
예제 #10
0
 public async Task <UserDto> GetUser()
 {
     try
     {
         return(await _blobCache.GetObject <UserDto>($"current_user").ToTask());
     }
     catch (Exception)
     {
         return(null);
     }
 }
예제 #11
0
 public IObservable <T> GetObject <T>(string key)
 {
     try
     {
         return(blob.GetObject <T>(key));
     }
     catch (KeyNotFoundException)
     {
         return(Observable.Return(default(T)));
     }
 }
예제 #12
0
        //These methods are the ones we call from courseViewModel and ChapterViewModel
        public async Task <List <ChapterLevel> > FetchChapterLevels(string id)
        {
            Cache = BlobCache.LocalMachine;
            List <Chapter> getChaptersTask = await GetChaptersAsync(id);

            List <ChapterLevel> chapterLevels = FetchSortedLevels(getChaptersTask);
            await Cache.InsertObject("chapters", chapterLevels, DateTimeOffset.Now.AddHours(2));

            List <ChapterLevel> chapters = await Cache.GetObject <List <ChapterLevel> >("chapters");

            return(chapters);
        }
예제 #13
0
 partial void BtnRestoreData_TouchUpInside(UIButton sender)
 {
     _encryptionProvider.SetPassword(txtPassword.Text);
     _encryptedBlobCache
     .GetObject <SomeData>("key")
     .Do(data => InvokeOnMainThread(() => lblResult.Text = $"Data Restored: {data.SomeName}"))
     .Catch((Exception exc) =>
     {
         InvokeOnMainThread(() => lblResult.Text = $"{exc}");
         return(Observable.Empty <SomeData>());
     })
     .Subscribe();
 }
        /// <summary>
        /// Attempt to return an object from the cache. If the item doesn't
        /// exist or returns an error, call a Func to return the latest
        /// version of an object and insert the result in the cache.
        ///
        /// For most Internet applications, this method is the best method to
        /// call to fetch static data (i.e. images) from the network.
        /// </summary>
        /// <param name="key">The key to associate with the object.</param>
        /// <param name="fetchFunc">A Func which will asynchronously return
        /// the latest value for the object should the cache not contain the
        /// key.
        ///
        /// Observable.Start is the most straightforward way (though not the
        /// most efficient!) to implement this Func.</param>
        /// <param name="absoluteExpiration">An optional expiration date.</param>
        /// <returns>A Future result representing the deserialized object from
        /// the cache.</returns>
        public static IObservable <T> GetOrFetchObject <T>(this IBlobCache This, string key, Func <IObservable <T> > fetchFunc, DateTimeOffset?absoluteExpiration = null)
        {
            return(This.GetObject <T>(key).Catch <T, Exception>(_ =>
            {
                object dontcare;
                var prefixedKey = This.GetHashCode().ToString() + key;

                var result = Observable.Defer(() => fetchFunc())
                             .Do(x => This.InsertObject(key, x, absoluteExpiration))
                             .Finally(() => inflightFetchRequests.TryRemove(prefixedKey, out dontcare))
                             .Multicast(new AsyncSubject <T>()).RefCount();

                return (IObservable <T>)inflightFetchRequests.GetOrAdd(prefixedKey, result);
            }));
        }
예제 #15
0
 public T GetObject <T>(string key)
 {
     try
     {
         return(_cache.GetObject <T>(key).ToTask().Result);
     }
     catch (AggregateException ex)
     {
         if (ex.InnerExceptions.Count == 1 && ex.InnerExceptions[0] is KeyNotFoundException)
         {
             return(default(T));
         }
         throw ex;
     }
 }
예제 #16
0
 /// <summary>
 /// Получаем кэш по ключу,
 /// если кэша нет взять данные из переданной функции и записать в кэш.
 /// </summary>
 /// <typeparam name="T">Тип данных получаемых из кеша.</typeparam>
 /// <param name="key">Ключ кеша.</param>
 /// <param name="fetchFunc">Функция получения данных.Вывозится в случаи если данных нет в кеше.</param>
 /// <returns>Данные из кеша</returns>
 public static T GetOrPutCached <T>(string key, Func <T> fetchFunc)
 {
     try
     {
         T result = Cache.GetObject <T>(key).Wait();
         if (result == null)
         {
             return(PutCache(key, fetchFunc.Invoke()));
         }
         return(result);
     }
     catch (KeyNotFoundException)
     {
         return(PutCache(key, fetchFunc.Invoke()));
     }
 }
예제 #17
0
        /// <summary>
        /// Gets a dictionary filled with the specified keys with their corresponding values.
        /// </summary>
        /// <typeparam name="T">The type of item to get.</typeparam>
        /// <param name="blobCache">The blob cache to extract the values from.</param>
        /// <param name="keys">The keys to get the values for.</param>
        /// <returns>A observable with the specified values.</returns>
        public static IObservable <IDictionary <string, T> > GetObjects <T>(this IBlobCache blobCache, IEnumerable <string> keys)
        {
            if (blobCache is IObjectBulkBlobCache bulkCache)
            {
                return(bulkCache.GetObjects <T>(keys));
            }

            return(keys.ToObservable()
                   .SelectMany(x =>
            {
                return blobCache.GetObject <T>(x)
                .Select(y => new KeyValuePair <string, T>(x, y))
                .Catch <KeyValuePair <string, T>, KeyNotFoundException>(_ => Observable.Empty <KeyValuePair <string, T> >());
            })
                   .ToDictionary(k => k.Key, v => v.Value));
        }
예제 #18
0
        public async Task DirectAuth(string login, string password)
        {
            _currentUserName    = login;
            _gitHub.Credentials = new Credentials(login, password);
            await _gitHub.User.Current();

            var persistentId = Id.ToString();
            var model        = await _blobCache.GetObject <ProviderModel>(persistentId);

            model.Token = password;
            model.User  = login;

            await _blobCache.InsertObject(persistentId, model);

            _isAuthenticated.OnNext(true);
        }
예제 #19
0
        public async Task <T> Get <T> (string key)
        {
            T u = default(T);

            try
            {
                string res = await cache.GetObject <string>(key);

                u = (T)JsonConvert.DeserializeObject(res, typeof(T), settings);
            }
            catch (KeyNotFoundException ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return(u);
        }
예제 #20
0
        public static IObservable <T> GetAndRequestFetch <T>(this IBlobCache This,
                                                             string key,
                                                             Func <IObservable <T> > fetchFunc,
                                                             Func <DateTimeOffset?, IObservable <bool> > fetchPredicate,
                                                             IObservable <Unit> requestSequence = null,
                                                             DateTimeOffset?absoluteExpiration  = null
                                                             )
        {
            if (fetchPredicate == null)
            {
                throw new ArgumentException("fetchPredicate");
            }
            if (fetchFunc == null)
            {
                throw new ArgumentException("fetchFunc");
            }

            // We are going to get the cache value if we can. And then we will run updates after that.
            // If we have nothing cached, then we will run the fetch directly. Otherwise we will run the
            // fetch sequence.

            var getOldKey = This.GetObjectCreatedAt <T>(key);

            // Next, get the item...

            var fetchFromCache = Observable.Defer(() => This.GetObject <T>(key))
                                 .Catch <T, KeyNotFoundException>(_ => Observable.Empty <T>());

            var items = fetchFromCache;

            // Once we have these, we also have to kick off a second set of fetches for our retry sequence.
            if (requestSequence == null)
            {
                return(items);
            }

            // TODO: How can we make this atomic. THe problem is that fetchPredicate may depend on the object having been
            // inserted, but because they are on different threads we may get race conditions. So there must be a way...
            var getAfter = requestSequence
                           .SelectMany(_ => This.GetObjectCreatedAt <T>(key))
                           .SelectMany(dt => fetchPredicate(dt))
                           .Where(doit => doit == true)
                           .SelectMany(_ => fetchFunc())
                           .SelectMany(x => This.InsertObject <T>(key, x, absoluteExpiration).Select(_ => x));

            return(items.Concat(getAfter));
        }
        public Task <T> Get <T>(string key)
        {
            var t = Task.Run(async() =>
            {
                try
                {
                    return(await cache.GetObject <T>(key));
                }
                catch (KeyNotFoundException)
                {
                    return(default(T));
                }
            });

            t.ConfigureAwait(false);
            return(t);
        }
예제 #22
0
        public static IObservable <IDictionary <string, T> > GetObjects <T>(this IBlobCache This, IEnumerable <string> keys, bool noTypePrefix = false)
        {
            var bulkCache = This as IObjectBulkBlobCache;

            if (bulkCache != null)
            {
                return(bulkCache.GetObjects <T>(keys));
            }

            return(keys.ToObservable()
                   .SelectMany(x =>
            {
                return This.GetObject <T>(x)
                .Select(y => new KeyValuePair <string, T>(x, y))
                .Catch <KeyValuePair <string, T>, KeyNotFoundException>(_ => Observable.Empty <KeyValuePair <string, T> >());
            })
                   .ToDictionary(k => k.Key, v => v.Value));
        }
예제 #23
0
        /// <summary>
        /// Return all objects of a specific Type in the cache.
        /// </summary>
        /// <param name="blobCache">The cache to get the items.</param>
        /// <typeparam name="T">The type of item to get.</typeparam>
        /// <returns>A Future result representing all objects in the cache
        /// with the specified Type.</returns>
        public static IObservable <IEnumerable <T> > GetAllObjects <T>(this IBlobCache blobCache)
        {
            if (blobCache is IObjectBlobCache objCache)
            {
                return(objCache.GetAllObjects <T>());
            }

            // NB: This isn't exactly thread-safe, but it's Close Enough(tm)
            // We make up for the fact that the keys could get kicked out
            // from under us via the Catch below
            return(blobCache.GetAllKeys()
                   .SelectMany(x => x
                               .Where(y =>
                                      y.StartsWith(GetTypePrefixedKey(string.Empty, typeof(T)), StringComparison.InvariantCulture))
                               .ToObservable())
                   .SelectMany(x => blobCache.GetObject <T>(x)
                               .Catch(Observable.Empty <T>()))
                   .ToList());
        }
예제 #24
0
        public SettingsService(ILogger logger = null, ISecureBlobCache secureBlobCache = null, IBlobCache localMachineCache = null)
        {
            _logger            = logger ?? Locator.Current.GetService <ILogger>();
            _secureBlobCache   = secureBlobCache ?? Locator.Current.GetService <ISecureBlobCache>();
            _localMachineCache = localMachineCache ?? Locator.Current.GetService <IBlobCache>();

            BaseApiUrl = @"http://test.test.no/api";
            var log = _logger.ForContext <SettingsService>();

            log.Information($"Instantiated: {nameof(SettingsService)}");

            // Check and set access token
            GetToken()
            .ToObservable()
            .LogException(log, "Unable to get access token")
            .Subscribe();

            _localMachineCache.GetObject <bool>(IsNewUserKey)
            .Catch <bool, Exception>(ex => Observable.Return(true))
            .Subscribe(newUser => IsNewUser = newUser);
        }
        /// <summary>
        /// Return all objects of a specific Type in the cache.
        /// </summary>
        /// <returns>A Future result representing all objects in the cache
        /// with the specified Type.</returns>
        public static IObservable <IEnumerable <T> > GetAllObjects <T>(this IBlobCache This)
        {
            var objCache = This as IObjectBlobCache;

            if (objCache != null)
            {
                return(objCache.GetAllObjects <T>());
            }

            // NB: This isn't exactly thread-safe, but it's Close Enough(tm)
            // We make up for the fact that the keys could get kicked out
            // from under us via the Catch below
            return(This.GetAllKeys()
                   .SelectMany(x => x
                               .Where(y =>
                                      y.StartsWith(GetTypePrefixedKey("", typeof(T))))
                               .ToObservable())
                   .SelectMany(x => This.GetObject <T>(x)
                               .Catch(Observable.Empty <T>()))
                   .ToList());
        }
 public object Get(string key, Type t)
 {
     return(_internalCache.GetObject <object>(key));
 }
예제 #27
0
 public Task <T> Get <T>(int id) where T : BaseModel, new()
 {
     return(Task.FromResult(localBlobCache.GetObject <T>(typeof(T).Name).FirstOrDefault(x => x.Id == id)));
 }
예제 #28
0
 public IObservable <IEnumerable <GitHubRepository> > GetRepositories() =>
 _blob.GetObject <IEnumerable <GitHubRepository> >(nameof(GitHubRepository));
예제 #29
0
        private async void RecoverObjects()
        {
            var animal = (await localData.GetObject <Animal>("Animals").ToTask());

            Settings.Name = "JoseMontero";
        }
예제 #30
0
        public IObservable <List <PuzzleGroup> > GetPuzzles()
        {
            IObservable <List <PuzzleGroup> > observableResult = _blobCache.GetObject <List <PuzzleGroup> >("kross");

            return(observableResult);
        }