/// <summary>
 /// - this returns twice, once immediately with cached value if exists, once again with updated results if the date of the week is older than Wednesday.
 /// </summary>
 /// <param name="issueNumber"></param>
 /// <returns></returns>
 public IObservable <IssueResult> Issue(int issueNumber)
 {
     return(_stateService.GetAndFetchLatest(BlobCacheKeys.GetKeyForIssue(issueNumber),
                                            _weeklyXamarinApiService.WeeklyXamarinApi.Issues(),
                                            fetchPredicate: dateTimeOffset => true,
                                            absoluteExpiration: RxApp.MainThreadScheduler.Now.AddDays(31)));
 }
Пример #2
0
 IObservable <List <ArticleViewModel> > GetAndFetchLatestArticles()
 {
     return(Cache.GetAndFetchLatest(BlobCacheKeys.GetCacheKeyForFeedAddress(FeedAddress),
                                    async() => await Task.Run(() => FeedService.GetFeedFor(FeedAddress)),
                                    datetimeOffset => true, // store the results in the cache for 31 days.
                                    RxApp.MainThreadScheduler.Now + TimeSpan.FromDays(31)));
 }
 /// <summary>
 ///
 /// </summary>
 /// <param name="issuesPerPage"></param>
 /// <param name="page"></param>
 /// <returns></returns>
 public IObservable <IssuesResult> Issues(int issuesPerPage = 250, int page = 1)
 {
     return(_stateService.GetAndFetchLatest(BlobCacheKeys.GetKeyForIssues(issuesPerPage, page),
                                            _weeklyXamarinApiService.WeeklyXamarinApi.Issues(),
                                            fetchPredicate: dateTimeOffset => FetchOnlyIfCloseOrAfterUsualPublishDate(dateTimeOffset),
                                            absoluteExpiration: RxApp.MainThreadScheduler.Now.AddDays(7)));
 }
Пример #4
0
            public void SetsArtworkKey()
            {
                string key = BlobCacheKeys.GetKeyForArtwork(new byte[] { 0, 1 });

                var song = new LocalSong("C://Bla", TimeSpan.Zero, key);

                Assert.Equal(key, song.ArtworkKey);
            }
Пример #5
0
            public void SmokeTest()
            {
                const string artworkKey = BlobCacheKeys.Artwork + "mycoolhash";

                string keyWithSize = BlobCacheKeys.GetArtworkKeyWithSize(artworkKey, 50);

                Assert.Equal(artworkKey + "-50x50", keyWithSize);
            }
Пример #6
0
            public async Task NullSearchTermDefaultsToEmptyString()
            {
                var songs = new[] { new YoutubeSong("http://blabla", TimeSpan.Zero) };
                var cache = new InMemoryBlobCache();

                cache.InsertObject(BlobCacheKeys.GetKeyForYoutubeCache(string.Empty), songs);
                var finder = new YoutubeSongFinder(cache);

                var result = await finder.GetSongsAsync();

                Assert.Equal(1, result.Count);
            }
Пример #7
0
            public async Task StoresArtworkInBlobCache()
            {
                var blobCache    = new InMemoryBlobCache();
                var artworkCache = new ArtworkCache(blobCache);

                var    data = new byte[] { 0, 1 };
                string key  = BlobCacheKeys.GetKeyForArtwork(data);

                await artworkCache.Store(key, data);

                Assert.Equal(data, await blobCache.Get(key));
            }
Пример #8
0
            public async Task UsesCachedSongsIfAvailable()
            {
                const string searchTerm = "Foo";
                var          songs      = new[] { new YoutubeSong("http://blabla", TimeSpan.Zero) };
                var          cache      = new InMemoryBlobCache();

                cache.InsertObject(BlobCacheKeys.GetKeyForYoutubeCache(searchTerm), songs);
                var finder = new YoutubeSongFinder(cache);

                var result = await finder.GetSongsAsync(searchTerm);

                Assert.Equal(1, result.Count);
            }
Пример #9
0
            public async Task NullSearchTermDefaultsToEmptyString()
            {
                var songs = new[] { new SoundCloudSong {
                                        IsStreamable = true, StreamUrl = new Uri("http://blabla.com"), PermaLinkUrl = new Uri("http://blabla")
                                    } };
                var cache = new InMemoryBlobCache();

                cache.InsertObject(BlobCacheKeys.GetKeyForSoundCloudCache(string.Empty), songs);
                var finder = new SoundCloudSongFinder(cache);

                var result = await finder.GetSongsAsync();

                Assert.Equal(1, result.Count);
            }
Пример #10
0
            public async Task NotFoundRequestIsMarked()
            {
                var fetcher = Substitute.For <IArtworkFetcher>();

                fetcher.RetrieveAsync(Arg.Any <string>(), Arg.Any <string>()).Returns(Task.FromResult <Uri>(null));
                var    blobCache = new InMemoryBlobCache();
                var    fixture   = new ArtworkCache(blobCache, fetcher);
                string artist    = "A";
                string album     = "B";
                string lookupKey = BlobCacheKeys.GetKeyForOnlineArtwork(artist, album);

                await fixture.FetchOnline(artist, album);

                Assert.Equal("FAILED", await blobCache.GetObject <string>(lookupKey));
            }
Пример #11
0
            public async Task DoesntStoreArtworkIfAlreadyInLocalCache()
            {
                var    blobCache    = Substitute.For <IBlobCache>();
                var    artworkCache = new ArtworkCache(blobCache);
                var    data         = new byte[] { 0, 1 };
                string key          = BlobCacheKeys.GetKeyForArtwork(data);

                await artworkCache.Store(key, data);

                blobCache.GetCreatedAt(Arg.Any <string>()).Returns(Observable.Return(new DateTimeOffset?(DateTimeOffset.MaxValue)));

                await artworkCache.Store(key, data);

                blobCache.Received(1).Insert(Arg.Any <string>(), Arg.Any <byte[]>());
            }
Пример #12
0
            public async Task UsesCachedSongsIfAvailable()
            {
                const string searchTerm = "Foo";
                var          songs      = new[] { new SoundCloudSong {
                                                      IsStreamable = true, StreamUrl = new Uri("http://blabla.com"), PermaLinkUrl = new Uri("http://blabla")
                                                  } };
                var cache = new InMemoryBlobCache();

                cache.InsertObject(BlobCacheKeys.GetKeyForSoundCloudCache(searchTerm), songs);
                var finder = new SoundCloudSongFinder(cache);

                var result = await finder.GetSongsAsync(searchTerm);

                Assert.Equal(1, result.Count);
            }
Пример #13
0
            public async Task PullsSearchesFromCache()
            {
                string artist    = "A";
                string album     = "B";
                string key       = BlobCacheKeys.GetKeyForOnlineArtwork(artist, album);
                var    fetcher   = Substitute.For <IArtworkFetcher>();
                var    blobCache = new InMemoryBlobCache();
                await blobCache.InsertObject(key, "TestArtworkKey");

                var fixture = new ArtworkCache(blobCache, fetcher);

                string returned = await fixture.FetchOnline(artist, album);

                Assert.Equal("TestArtworkKey", returned);
                fetcher.DidNotReceiveWithAnyArgs().RetrieveAsync(null, null);
            }
Пример #14
0
            public void CanStoreMulipleArtworksIfArtworksExistsInCache()
            {
                var    blobCache = new InMemoryBlobCache();
                var    data      = new byte[] { 0, 1 };
                string key       = BlobCacheKeys.GetKeyForArtwork(data);

                blobCache.Insert(key, data);
                var fixture = new ArtworkCache(blobCache);

                Task firstTask  = fixture.Store(key, data);
                Task secondTask = fixture.Store(key, data);
                Task thrirdTask = fixture.Store(key, data);

                Assert.True(firstTask.IsCompleted);
                Assert.True(secondTask.IsCompleted);
                Assert.True(thrirdTask.IsCompleted);
            }
Пример #15
0
            public void SameKeysWaitOnFirstToFinish()
            {
                var signal    = new AsyncSubject <Unit>();
                var blobCache = Substitute.For <IBlobCache>();

                blobCache.Insert(Arg.Any <string>(), Arg.Any <byte[]>(), Arg.Any <DateTimeOffset?>()).Returns(signal);
                var    fixture = new ArtworkCache(blobCache);
                var    data    = new byte[] { 0, 1 };
                string key     = BlobCacheKeys.GetKeyForArtwork(data);

                Task firstTask = fixture.Store(key, data);

                Task secondTask = fixture.Store(key, data);

                Assert.False(firstTask.IsCompleted);
                Assert.False(secondTask.IsCompleted);

                signal.OnNext(Unit.Default);
                signal.OnCompleted();

                Assert.True(firstTask.IsCompleted);
                Assert.True(secondTask.IsCompleted);
            }
Пример #16
0
        public void SearchQueryKeyShouldBeExpected(string query, string expected)
        {
            var sut = BlobCacheKeys.GetKeyForSearch(query);

            sut.Should().Be(expected);
        }
Пример #17
0
        private async Task UpdateSongsAsync(string path)
        {
            if (this.currentSongFinderSubscription != null)
            {
                this.currentSongFinderSubscription.Dispose();
                this.currentSongFinderSubscription = null;
            }

            this.IsUpdating = true;

            await this.RemoveMissingSongsAsync(path);

            ILocalSongFinder songFinder = this.localSongFinderFunc(path);

            this.currentSongFinderSubscription = songFinder.GetSongsAsync()
                                                 .ObserveOn(RxApp.TaskpoolScheduler)
                                                 .Subscribe(t =>
            {
                LocalSong song = t.Item1;

                this.songLock.EnterWriteLock();

                bool added = this.songs.Add(song);

                LocalSong realSong;
                bool needsUpdate = false;

                if (added)
                {
                    realSong    = song;
                    needsUpdate = true;
                }

                else
                {
                    LocalSong existing = this.songs.First(x => x.OriginalPath == song.OriginalPath);

                    if (existing.UpdateMetadataFrom(song))
                    {
                        needsUpdate = true;
                    }

                    realSong = existing;
                }

                this.songLock.ExitWriteLock();

                byte[] artworkData = t.Item2;

                if (artworkData != null)
                {
                    string key = BlobCacheKeys.GetKeyForArtwork(artworkData);

                    if (realSong.ArtworkKey != key)
                    {
                        ArtworkCache.Instance.Store(key, artworkData).ToObservable()
                        .Subscribe(x => realSong.ArtworkKey = key);
                    }
                }

                if (needsUpdate)
                {
                    this.songsUpdated.OnNext(Unit.Default);
                }
            }, () =>
            {
                this.Save();

                this.StartOnlineArtworkLookup();

                this.songLock.EnterReadLock();
                int songCount = this.songs.Count;
                this.songLock.ExitReadLock();

                AnalyticsClient.Instance.RecordLibrarySize(songCount);

                this.IsUpdating = false;
            });
        }
Пример #18
0
 public IObservable <DuckDuckGoSearchResult> Search(string query)
 {
     return(_stateService.GetOrFetch(BlobCacheKeys.GetKeyForSearch(query),
                                     async() => await _duckDuckGoApiService.UserInitiated.Search(query), absoluteExpiration: DateTime.UtcNow.AddDays(7)));
 }