/// <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; } }
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); } }
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))); }
/// <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()); }
/// <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)); }
public async Task <T> GetFromCache <T>(string cacheName) { try { T t = await _cache.GetObject <T>(cacheName); return(t); } catch (KeyNotFoundException) { return(default);
private async Task <T> GetFromCacheAsync <T>(string cacheKey) { try { return(await cache.GetObject <T>(cacheKey)); } catch (KeyNotFoundException) { return(default(T)); } }
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); }
public async Task <UserDto> GetUser() { try { return(await _blobCache.GetObject <UserDto>($"current_user").ToTask()); } catch (Exception) { return(null); } }
public IObservable <T> GetObject <T>(string key) { try { return(blob.GetObject <T>(key)); } catch (KeyNotFoundException) { return(Observable.Return(default(T))); } }
//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); }
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); })); }
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; } }
/// <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())); } }
/// <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)); }
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); }
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); }
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); }
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)); }
/// <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()); }
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)); }
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))); }
public IObservable <IEnumerable <GitHubRepository> > GetRepositories() => _blob.GetObject <IEnumerable <GitHubRepository> >(nameof(GitHubRepository));
private async void RecoverObjects() { var animal = (await localData.GetObject <Animal>("Animals").ToTask()); Settings.Name = "JoseMontero"; }
public IObservable <List <PuzzleGroup> > GetPuzzles() { IObservable <List <PuzzleGroup> > observableResult = _blobCache.GetObject <List <PuzzleGroup> >("kross"); return(observableResult); }